-
-
Notifications
You must be signed in to change notification settings - Fork 114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ObjectBuilder: add property_if(), property_if_some(), property_from_iter() ... #1377
Conversation
e81405d
to
86bbd20
Compare
Haven't had the time to review the PR yet but at some point there was a discussion about adding the possibility to set a property only if a condition is truthful. The use case was setting a property only if a certain gstreamer version is available iirc cc @sdroege, do you remember where was that needed? or maybe it was someone else. |
@bilelmoussaoui: indeed that would be useful. Something like |
Noteworthy annoyance with these changes is that we need to |
I propose renaming |
That is ok, I already migrated a bunch of files to use prelude instead of including traits manually. Going forward in that direction is good from my point of view |
I would name it |
Makes sense.
Already taken by the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me otherwise and the method names also make sense. @bilelmoussaoui @felinira do you prefer any different names, or would like to have something else changed?
Also seems fine to me |
86bbd20
to
23be9af
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
otherwise lgtm, can't comment on the namings because i am bad at that
Sorry for the lack of progress on this one. fwiw, I'm planning on working on it during the hackfest. |
…ter() ... ... & property_if_not_empty() This commit adds functions to improve usability when setting properties. **`property_if()`** allows setting a property from an `Option` only if a given `predicate` evaluates to `true`. Otherwise, the `Object`'s default value or any previously set value is kept. **`property_if_some()`** allows setting a property from an `Option` only if the `Option` is `Some`. Otherwise, the `Object`'s default value or any previously set value is kept. For instance, assuming an `Args` `struct` which was built from the application's CLI arguments: ```rust let args = Args { name: Some("test"), anwser: None, }; ``` ... without this change, we need to write something like this: ```rust let mut builder = Object::builder::<SimpleObject>(); if let Some(ref name) = args.name { builder = builder.property("name", name) } if let Some(ref answer) = args.answer { builder = builder.property("answer", &args.answer) } let obj = builder.build(); ``` With `property_if_some()`, we can write: ```rust let obj = Object::builder::<SimpleObject>() .property_if_some("name", &args.name) .property_if_some("answer", &args.answer) .build(); ``` **`property_from_iter()`** allows building a collection-like `Value` property from a collection of items: ```rust let obj = Object::builder::<SimpleObject>() .property_from_iter::<ValueArray>("array", ["val0", "val1"]) .build(); ``` **`property_if_not_empty()`** allows building a collection-like `Value` property from a collection of items but does nothing if the provided collection if empty, thus keeping the default value of the property, if any: ```rust let obj = Object::builder::<SimpleObject>() .property_if_not_empty::<ValueArray>("array", ["val0", "val1"]) .build(); ```
Should be ready now |
E.g. (also applies to `property`): * `field_from_iter()`, * `field_if_not_empty()`. Use a macro to factorize implementation & documentation of `field` / `property` convenience setters. Also: * add some `*_if_not_empty` for some iterator based setters. * add `*_if` for predicate based setters. Related to gtk-rs/gtk-rs-core#1377 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1431>
Another option to keep ergonomic and flexible builder syntax is to use something similar to Kotlin's scope functions. trait BuilderScopeExt {
fn apply(self, scope: &mut FnMut(&Self)) -> Self;
}
impl BuilderScopeExt {
fn apply(mut self, scope: &mut FnMut(&Self)) -> Self {
(scope)(&mut self);
self
}
}
let obj = Object::builder::<SimpleObject>()
.apply(|builder| {
if let Some(ref name) = args.name {
builder.property("name", name);
}
if let Some(ref answer) = args.answer {
builder.property("answer", &args.answer);
}
})
.build(); |
@andy128k, thanks for the suggestion! My main intention with this PR was to avoid constructions such as: if let Some(ref name) = args.name {
[...]
} Do you want to propose the |
@fengalin There will always be specific inconvenient cases. Now it is |
... & property_if_not_empty()
This commit adds an
ObjectBuilderPropertySetter
trait
which implementsfunctions to improve usability when setting properties.
property_if()
allows setting a property from anOption
only if a givenpredicate
evaluates totrue
. Otherwise, theObject
's default value orany previously set value is kept.
property_if_some()
allows setting a property from anOption
only if theOption
isSome
. Otherwise, theObject
's default value or any previouslyset value is kept.
For instance, assuming an
Args
struct
which was built from the application'sCLI arguments:
... without this change, we need to write something like this:
With
property_if_some()
, we can write:property_from_iter()
allows building a collection-likeValue
propertyfrom a collection of items:
property_if_not_empty()
allows building a collection-likeValue
propertyfrom a collection of items but does nothing if the provided collection if empty,
thus keeping the default value of the property, if any: