Skip to content
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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

fengalin
Copy link
Contributor

@fengalin fengalin commented Apr 29, 2024

... & property_if_not_empty()

This commit adds an ObjectBuilderPropertySetter trait which implements
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:

let args = Args {
    name: Some("test"),
    anwser: None,
};

... without this change, we need to write something like this:

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:

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. In GStreamer this allows things like:

let src = gst::ElementFactory::make("webrtcsrc")
    .property_from_iter::<gst::Array>("audio-codecs", ["L24", "OPUS"])
    .build()
    .unwrap();

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. In GStreamer this allows
things like:

    .property_if_not_empty::<gst::Array>("audio-codecs", &args.audio_codecs)
    .build()
    .unwrap();

@bilelmoussaoui
Copy link
Member

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.

@fengalin
Copy link
Contributor Author

@bilelmoussaoui: indeed that would be useful. Something like Option::take_if in reverse? I can add that too yes.

@fengalin
Copy link
Contributor Author

Noteworthy annoyance with these changes is that we need to use glib::prelude::*; (or gst::prelude::*;) in some places were it wasn't before.

@felinira
Copy link
Contributor

I propose renaming property_if_any() to property_if_not_empty() to clarify its purpose and to be more similar to the common is_empty() collection method.

@bilelmoussaoui
Copy link
Member

Noteworthy annoyance with these changes is that we need to use glib::prelude::*; (or gst::prelude::*;) in some places were it wasn't before.

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

@bilelmoussaoui
Copy link
Member

bilelmoussaoui commented Apr 29, 2024

I propose renaming property_if_any() to property_if_not_empty() to clarify its purpose and to be more similar to the common is_empty() collection method.

I would name it property_if_some instead.

@fengalin
Copy link
Contributor Author

I propose renaming property_if_any() to property_if_not_empty() to clarify its purpose and to be more similar to the common is_empty() collection method

Makes sense.

I would name it property_if_some instead.

Already taken by the Option<_> variant :)

}
}

impl<'a, O: IsA<Object> + IsClass> ObjectBuilderPropertySetter<'a> for ObjectBuilder<'a, O> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an extension trait instead of just implementing it directly on ObjectBuilder?

Copy link
Contributor Author

@fengalin fengalin Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you suggested this :): https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1431#note_2392609

I think it's convenient to have a single definition too: I can use this trait for gst::ElementFactory, implement property() and get all the other implementations for free.

I used a similar pattern gst::StructureBuilderPropertySetter which is applicable to gst::StructureBuilder, gst::CapsBuilder, gst_audio::CapsBuilder, gst_video::CapsBuilder, ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested this because I thought of adding this extension trait in gstreamer-rs, but here it could also be a normal impl block.

If it makes anything easier and you're going to implement the trait on other types too that's fine. (Btw, could you also add this to the appsrc/appsink builders then? I just noticed that they don't have the general property method)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested this because I thought of adding this extension trait in gstreamer-rs, but here it could also be a normal impl block.

As far as this PR is concerned, I can only see one implementation here. @bilelmoussaoui can you think of other builders which would use property() and would benefit from this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can only see one implementation here

But more in gstreamer-rs?

And here, I think all the autogenerated builders for specific types could make use of this. I think they all don't have a generic property method right now but that would be useful.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A macro that is exported from the glib crate? Not sure I like adding more macro public API. @bilelmoussaoui ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I see it: due to the Value / SendValue differences, I will handle this separately in gtk-rs & GStreamer.

  • In gtk-rs: the new methods property_* can be added to the ObjectBuilder impl directly. For the generated Builders, a gir update could add the additional methods on a per-property basis.
  • In GStreamer, I think I can use the macro I was mentioning in my previous comment. It would be transparent to users since it would only be used in the bindings for the ElementFactory & the Structure-like struct builders, not something like glib::clone! for instance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a plan

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see which other types that could use this. I think the only use case would be either gstreamer-rs or gegl-rs(which is not maintained anyways...). So do we really need this to be an extension trait?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't. See my comment: #1377 (comment)

glib/src/object.rs Outdated Show resolved Hide resolved
Copy link
Member

@sdroege sdroege left a 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?

@sdroege
Copy link
Member

sdroege commented Apr 30, 2024

I propose renaming property_if_any() to property_if_not_empty() to clarify its purpose and to be more similar to the common is_empty() collection method

Makes sense.

Also seems fine to me

…ter() ...

... & property_if_not_empty()

This commit adds an `ObjectBuilderPropertySetter` `trait` which implements
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. In GStreamer this allows things like:

```rust
let src = gst::ElementFactory::make("webrtcsrc")
    .property_from_iter::<gst::Array>("audio-codecs", ["L24", "OPUS"])
    .build()
    .unwrap();
```

**`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. In GStreamer this allows
things like:

```let src = gst::ElementFactory::make("webrtcsrc")
    .property_if_not_empty::<gst::Array>("audio-codecs", &args.audio_codecs)
    .build()
    .unwrap();
```
@fengalin fengalin changed the title ObjectBuilder: add property_if_some(), property_from_iter() & … ObjectBuilder: add property_if(), property_if_some(), property_from_iter() ... Apr 30, 2024
Copy link
Member

@bilelmoussaoui bilelmoussaoui left a 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

@@ -23,6 +24,25 @@ impl ValueArray {
unsafe { from_glib_full(gobject_ffi::g_value_array_new(n_prealloced)) }
}

pub fn from_items(values: impl IntoIterator<Item = impl Into<Value> + Send>) -> Self {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those changes should go to a different commit if possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

}
}

impl<'a, O: IsA<Object> + IsClass> ObjectBuilderPropertySetter<'a> for ObjectBuilder<'a, O> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see which other types that could use this. I think the only use case would be either gstreamer-rs or gegl-rs(which is not maintained anyways...). So do we really need this to be an extension trait?

@fengalin
Copy link
Contributor Author

Sorry for the lack of progress on this one. fwiw, I'm planning on working on it during the hackfest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants