diff --git a/gstreamer-audio/src/caps.rs b/gstreamer-audio/src/caps.rs index 33cfe131d..5f13c82a0 100644 --- a/gstreamer-audio/src/caps.rs +++ b/gstreamer-audio/src/caps.rs @@ -61,6 +61,30 @@ impl AudioCapsBuilder { } } + // rustdoc-stripper-ignore-next + /// Constructs an `AudioCapsBuilder` for the specified encoding. + /// + /// The resulting `Caps` will use the `encoding` argument as name + /// and will not contain any additional fields unless explicitly added. + pub fn for_encoding_from_static(encoding: impl AsRef + 'static) -> Self { + assert_initialized_main_thread!(); + AudioCapsBuilder { + builder: Caps::builder_from_static(encoding), + } + } + + // rustdoc-stripper-ignore-next + /// Constructs an `AudioCapsBuilder` for the specified encoding. + /// + /// The resulting `Caps` will use the `encoding` argument as name + /// and will not contain any additional fields unless explicitly added. + pub fn for_encoding_from_id(encoding: impl AsRef) -> Self { + assert_initialized_main_thread!(); + AudioCapsBuilder { + builder: Caps::builder_from_id(encoding), + } + } + pub fn any_features(self) -> AudioCapsBuilder { AudioCapsBuilder { builder: self.builder.any_features(), @@ -75,6 +99,24 @@ impl AudioCapsBuilder { builder: self.builder.features(features), } } + + pub fn features_from_statics( + self, + features: impl IntoIterator + 'static>, + ) -> AudioCapsBuilder { + AudioCapsBuilder { + builder: self.builder.features_from_statics(features), + } + } + + pub fn features_from_ids( + self, + features: impl IntoIterator>, + ) -> AudioCapsBuilder { + AudioCapsBuilder { + builder: self.builder.features_from_ids(features), + } + } } impl Default for AudioCapsBuilder { diff --git a/gstreamer-video/src/caps.rs b/gstreamer-video/src/caps.rs index 2ff222c9d..a31f5bd8b 100644 --- a/gstreamer-video/src/caps.rs +++ b/gstreamer-video/src/caps.rs @@ -43,6 +43,30 @@ impl VideoCapsBuilder { } } + // rustdoc-stripper-ignore-next + /// Constructs an `VideoCapsBuilder` for the specified encoding. + /// + /// The resulting `Caps` will use the `encoding` argument as name + /// and will not contain any additional fields unless explicitly added. + pub fn for_encoding_from_static(encoding: impl AsRef + 'static) -> Self { + assert_initialized_main_thread!(); + VideoCapsBuilder { + builder: Caps::builder_from_static(encoding), + } + } + + // rustdoc-stripper-ignore-next + /// Constructs an `VideoCapsBuilder` for the specified encoding. + /// + /// The resulting `Caps` will use the `encoding` argument as name + /// and will not contain any additional fields unless explicitly added. + pub fn for_encoding_from_id(encoding: impl AsRef) -> Self { + assert_initialized_main_thread!(); + VideoCapsBuilder { + builder: Caps::builder_from_id(encoding), + } + } + pub fn any_features(self) -> VideoCapsBuilder { VideoCapsBuilder { builder: self.builder.any_features(), @@ -57,6 +81,24 @@ impl VideoCapsBuilder { builder: self.builder.features(features), } } + + pub fn features_from_statics( + self, + features: impl IntoIterator + 'static>, + ) -> VideoCapsBuilder { + VideoCapsBuilder { + builder: self.builder.features_from_statics(features), + } + } + + pub fn features_from_ids( + self, + features: impl IntoIterator>, + ) -> VideoCapsBuilder { + VideoCapsBuilder { + builder: self.builder.features_from_ids(features), + } + } } impl Default for VideoCapsBuilder { diff --git a/gstreamer/src/caps.rs b/gstreamer/src/caps.rs index 1baa2acd3..0d589975d 100644 --- a/gstreamer/src/caps.rs +++ b/gstreamer/src/caps.rs @@ -2,10 +2,12 @@ use std::{fmt, marker::PhantomData, ptr, str}; +use cfg_if::cfg_if; use glib::{ prelude::*, translate::*, value::{SendValue, ToSendValue}, + GStr, }; use crate::{caps_features::*, ffi, structure::*, CapsIntersectMode, IdStr}; @@ -19,6 +21,18 @@ impl Caps { Builder::new(name) } + #[doc(alias = "gst_caps_new_static_str_simple")] + pub fn builder_from_static(name: impl AsRef + 'static) -> Builder { + assert_initialized_main_thread!(); + Builder::from_static(name) + } + + #[doc(alias = "gst_caps_new_id_str_simple")] + pub fn builder_from_id(name: impl AsRef) -> Builder { + assert_initialized_main_thread!(); + Builder::from_id(name) + } + #[doc(alias = "gst_caps_new_full")] pub fn builder_full() -> BuilderFull { assert_initialized_main_thread!(); @@ -60,6 +74,28 @@ impl Caps { caps } + #[doc(alias = "gst_caps_new_static_str_empty_simple")] + pub fn new_empty_simple_from_static(name: impl AsRef + 'static) -> Self { + skip_assert_initialized!(); + let mut caps = Caps::new_empty(); + + let structure = Structure::new_empty_from_static(name); + caps.get_mut().unwrap().append_structure(structure); + + caps + } + + #[doc(alias = "gst_caps_new_id_str_empty_simple")] + pub fn new_empty_simple_from_id(name: impl AsRef) -> Self { + skip_assert_initialized!(); + let mut caps = Caps::new_empty(); + + let structure = Structure::new_empty_from_id(name); + caps.get_mut().unwrap().append_structure(structure); + + caps + } + #[doc(alias = "gst_caps_fixate")] pub fn fixate(&mut self) { unsafe { @@ -313,6 +349,32 @@ impl CapsRef { self.set_value(name, value); } + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given value `value`. + /// + /// Overrides any default or previously defined value for `name`. + #[doc(alias = "gst_caps_set_value_static_str")] + #[doc(alias = "gst_caps_set_simple_static_str")] + pub fn set_with_static( + &mut self, + name: impl AsRef + 'static, + value: impl ToSendValue + Sync, + ) { + let value = value.to_send_value(); + self.set_value_with_static(name, value); + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given value `value`. + /// + /// Overrides any default or previously defined value for `name`. + #[doc(alias = "gst_caps_id_str_set_value")] + #[doc(alias = "gst_caps_id_str_set_simple")] + pub fn set_with_id(&mut self, name: impl AsRef, value: impl ToSendValue + Sync) { + let value = value.to_send_value(); + self.set_value_with_id(name, value); + } + // rustdoc-stripper-ignore-next /// Sets field `name` to the given value if the `predicate` evaluates to `true`. /// @@ -326,6 +388,42 @@ impl CapsRef { } } + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given value if the `predicate` evaluates to `true`. + /// + /// This has no effect if the `predicate` evaluates to `false`, + /// i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_set_value_static_str")] + #[doc(alias = "gst_caps_set_simple_static_str")] + pub fn set_with_static_if( + &mut self, + name: impl AsRef + 'static, + value: impl ToSendValue + Sync, + predicate: bool, + ) { + if predicate { + self.set_with_static(name, value); + } + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given value if the `predicate` evaluates to `true`. + /// + /// This has no effect if the `predicate` evaluates to `false`, + /// i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_id_str_set_value")] + #[doc(alias = "gst_caps_id_str_set_simple")] + pub fn set_with_id_if( + &mut self, + name: impl AsRef, + value: impl ToSendValue + Sync, + predicate: bool, + ) { + if predicate { + self.set_with_id(name, value); + } + } + // rustdoc-stripper-ignore-next /// Sets field `name` to the given inner value if `value` is `Some`. /// @@ -338,6 +436,38 @@ impl CapsRef { } } + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given inner value if `value` is `Some`. + /// + /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_set_value_static_str")] + #[doc(alias = "gst_caps_set_simple_static_str")] + pub fn set_with_static_if_some( + &mut self, + name: impl AsRef + 'static, + value: Option, + ) { + if let Some(value) = value { + self.set_with_static(name, value); + } + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given inner value if `value` is `Some`. + /// + /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_id_str_set_value")] + #[doc(alias = "gst_caps_id_str_set_simple")] + pub fn set_with_id_if_some( + &mut self, + name: impl AsRef, + value: Option, + ) { + if let Some(value) = value { + self.set_with_id(name, value); + } + } + // rustdoc-stripper-ignore-next /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s. /// @@ -352,6 +482,36 @@ impl CapsRef { self.set(name, V::from_iter(iter)); } + // rustdoc-stripper-ignore-next + /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s. + /// + /// Overrides any default or previously defined value for `name`. + #[inline] + pub fn set_with_static_from_iter< + V: ValueType + ToSendValue + FromIterator + Sync, + >( + &mut self, + name: impl AsRef + 'static, + iter: impl IntoIterator, + ) { + let iter = iter.into_iter().map(|item| item.to_send_value()); + self.set_with_static(name, V::from_iter(iter)); + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s. + /// + /// Overrides any default or previously defined value for `name`. + #[inline] + pub fn set_with_id_from_iter + Sync>( + &mut self, + name: impl AsRef, + iter: impl IntoIterator, + ) { + let iter = iter.into_iter().map(|item| item.to_send_value()); + self.set_with_id(name, V::from_iter(iter)); + } + // rustdoc-stripper-ignore-next /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s, /// if `iter` is not empty. @@ -370,6 +530,44 @@ impl CapsRef { } } + // rustdoc-stripper-ignore-next + /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s, + /// if `iter` is not empty. + /// + /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged. + #[inline] + pub fn set_with_static_if_not_empty< + V: ValueType + ToSendValue + FromIterator + Sync, + >( + &mut self, + name: impl AsRef + 'static, + iter: impl IntoIterator, + ) { + let mut iter = iter.into_iter().peekable(); + if iter.peek().is_some() { + let iter = iter.map(|item| item.to_send_value()); + self.set_with_static(name, V::from_iter(iter)); + } + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s, + /// if `iter` is not empty. + /// + /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged. + #[inline] + pub fn set_with_id_if_not_empty + Sync>( + &mut self, + name: impl AsRef, + iter: impl IntoIterator, + ) { + let mut iter = iter.into_iter().peekable(); + if iter.peek().is_some() { + let iter = iter.map(|item| item.to_send_value()); + self.set_with_id(name, V::from_iter(iter)); + } + } + // rustdoc-stripper-ignore-next /// Sets field `name` to the given value `value`. /// @@ -383,6 +581,52 @@ impl CapsRef { } } + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given value `value`. + /// + /// Overrides any default or previously defined value for `name`. + #[doc(alias = "gst_caps_set_value_static_str")] + pub fn set_value_with_static( + &mut self, + name: impl AsRef + 'static, + value: glib::SendValue, + ) { + unsafe { + cfg_if! { + if #[cfg(feature = "v1_26")] { + ffi::gst_caps_set_value_static_str( + self.as_mut_ptr(), + name.as_ref().as_ptr(), + value.to_glib_none().0, + ) + } else { + ffi::gst_caps_set_value(self.as_mut_ptr(), name.as_ref().as_ptr(), value.to_glib_none().0) + } + } + } + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given value `value`. + /// + /// Overrides any default or previously defined value for `name`. + #[doc(alias = "gst_caps_id_str_set_value")] + pub fn set_value_with_id(&mut self, name: impl AsRef, value: glib::SendValue) { + unsafe { + cfg_if! { + if #[cfg(feature = "v1_26")] { + ffi::gst_caps_id_str_set_value( + self.as_mut_ptr(), + name.as_ref().as_ptr(), + value.to_glib_none().0, + ) + } else { + ffi::gst_caps_set_value(self.as_mut_ptr(), name.as_ref().as_gstr().as_ptr(), value.to_glib_none().0) + } + } + } + } + // rustdoc-stripper-ignore-next /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`. /// @@ -395,6 +639,40 @@ impl CapsRef { } } + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`. + /// + /// This has no effect if the `predicate` evaluates to `false`, + /// i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_set_value_static_str")] + pub fn set_value_with_static_if( + &mut self, + name: impl AsRef + 'static, + value: SendValue, + predicate: bool, + ) { + if predicate { + self.set_value_with_static(name, value); + } + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`. + /// + /// This has no effect if the `predicate` evaluates to `false`, + /// i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_id_str_set_value")] + pub fn set_value_with_id_if( + &mut self, + name: impl AsRef, + value: SendValue, + predicate: bool, + ) { + if predicate { + self.set_value_with_id(name, value); + } + } + // rustdoc-stripper-ignore-next /// Sets field `name` to the given inner value if `value` is `Some`. /// @@ -406,6 +684,32 @@ impl CapsRef { } } + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given inner value if `value` is `Some`. + /// + /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_set_value_static_str")] + pub fn set_value_with_static_if_some( + &mut self, + name: impl AsRef + 'static, + value: Option, + ) { + if let Some(value) = value { + self.set_value_with_static(name, value); + } + } + + // rustdoc-stripper-ignore-next + /// Sets field `name` to the given inner value if `value` is `Some`. + /// + /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept. + #[doc(alias = "gst_caps_id_str_set_value")] + pub fn set_value_with_id_if_some(&mut self, name: impl AsRef, value: Option) { + if let Some(value) = value { + self.set_value_with_id(name, value); + } + } + #[doc(alias = "get_structure")] #[doc(alias = "gst_caps_get_structure")] pub fn structure(&self, idx: usize) -> Option<&StructureRef> { @@ -700,7 +1004,7 @@ impl CapsRef { >( &mut self, mut func: F, - ) -> bool { + ) { unsafe { unsafe extern "C" fn trampoline< F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> std::ops::ControlFlow<()>, @@ -718,11 +1022,11 @@ impl CapsRef { matches!(res, std::ops::ControlFlow::Continue(_)).into_glib() } let func = &mut func as *mut F; - from_glib(ffi::gst_caps_map_in_place( + let _ = ffi::gst_caps_map_in_place( self.as_mut_ptr(), Some(trampoline::), func as glib::ffi::gpointer, - )) + ); } } @@ -1085,6 +1389,24 @@ impl Builder { } } + fn from_static(name: impl AsRef + 'static) -> Builder { + skip_assert_initialized!(); + Builder { + s: crate::Structure::new_empty_from_static(name), + features: None, + phantom: PhantomData, + } + } + + fn from_id(name: impl AsRef) -> Builder { + skip_assert_initialized!(); + Builder { + s: crate::Structure::new_empty_from_id(name), + features: None, + phantom: PhantomData, + } + } + pub fn features( self, features: impl IntoIterator, @@ -1096,6 +1418,28 @@ impl Builder { } } + pub fn features_from_statics( + self, + features: impl IntoIterator + 'static>, + ) -> Builder { + Builder { + s: self.s, + features: Some(CapsFeatures::new_from_static(features)), + phantom: PhantomData, + } + } + + pub fn features_from_ids( + self, + features: impl IntoIterator>, + ) -> Builder { + Builder { + s: self.s, + features: Some(CapsFeatures::new_from_id(features)), + phantom: PhantomData, + } + } + pub fn any_features(self) -> Builder { Builder { s: self.s, @@ -1285,6 +1629,7 @@ impl BuilderFull { mod tests { use super::*; use crate::{Array, Fraction}; + use glib::gstr; #[test] fn test_builder() { @@ -1292,10 +1637,10 @@ mod tests { let mut caps = Caps::builder("foo/bar") .field("int", 12) - .field("bool", true) - .field("string", "bla") + .field_with_static(gstr!("bool"), true) + .field_with_id(idstr!("string"), "bla") .field("fraction", Fraction::new(1, 2)) - .field("array", Array::new([1, 2])) + .field_with_id(idstr!("array"), Array::new([1, 2])) .build(); assert_eq!( caps.to_string(), @@ -1331,8 +1676,8 @@ mod tests { let caps = Caps::builder("foo/bar") .field_if_some("int0", Option::::None) .field_if_some("int1", Some(12)) - .field_if_some("string0", Option::::None) - .field_if_some("string1", Some("bla")) + .field_with_static_if_some(gstr!("string0"), Option::::None) + .field_with_id_if_some(idstr!("string1"), Some("bla")) .build(); assert_eq!( caps.to_string(), @@ -1397,7 +1742,7 @@ mod tests { .structure_with_any_features_if_some(Some(Structure::builder("audio/x-raw").build())) .structure_with_features_if_some( Some(Structure::builder("video/x-raw").build()), - CapsFeatures::new(["foo:bla", "foo:baz"]), + CapsFeatures::new_from_id([idstr!("foo:bla"), idstr!("foo:baz")]), ) .build(); assert_eq!( diff --git a/gstreamer/src/caps_features.rs b/gstreamer/src/caps_features.rs index eff81e6be..b3ac05e6d 100644 --- a/gstreamer/src/caps_features.rs +++ b/gstreamer/src/caps_features.rs @@ -9,7 +9,8 @@ use std::{ ptr, str, }; -use crate::ffi; +use crate::{ffi, IdStr}; +use cfg_if::cfg_if; use glib::{prelude::*, translate::*}; use std::sync::LazyLock; @@ -32,6 +33,34 @@ impl CapsFeatures { f } + #[doc(alias = "gst_caps_features_new_static_str")] + pub fn new_from_static( + features: impl IntoIterator + 'static>, + ) -> Self { + skip_assert_initialized!(); + let mut f = Self::new_empty(); + + for feature in features { + f.add_from_static(feature); + } + + f + } + + #[doc(alias = "gst_caps_features_new_id_str")] + pub fn new_from_id(features: impl IntoIterator>) -> Self { + skip_assert_initialized!(); + let mut f = Self::new_empty(); + + for feature in features { + f.add_from_id(feature); + } + + f + } + + #[deprecated = "use `new_by_id()` instead"] + #[allow(deprecated)] #[doc(alias = "gst_caps_features_new_id")] pub fn from_quarks(features: impl IntoIterator) -> Self { skip_assert_initialized!(); @@ -372,6 +401,26 @@ impl CapsFeaturesRef { } } + #[doc(alias = "gst_caps_features_contains_id_str")] + pub fn contains_by_id(&self, feature: impl AsRef) -> bool { + unsafe { + cfg_if! { + if #[cfg(feature = "v1_26")] { + from_glib(ffi::gst_caps_features_contains_id_str( + self.as_ptr(), + feature.as_ref().as_ptr(), + )) + } else { + from_glib(ffi::gst_caps_features_contains( + self.as_ptr(), + feature.as_ref().as_gstr().as_ptr(), + )) + } + } + } + } + + #[deprecated = "use `contains_by_id()` instead"] #[doc(alias = "gst_caps_features_contains_id")] pub fn contains_quark(&self, feature: glib::Quark) -> bool { unsafe { @@ -401,12 +450,29 @@ impl CapsFeaturesRef { return None; } - // Safety: we can return a GStr based on the feature here because - // the lifetime of the returned value is constrained by &self. Some(glib::GStr::from_ptr(feature)) } } + #[cfg(feature = "v1_26")] + #[doc(alias = "get_nth_by_id")] + #[doc(alias = "gst_caps_features_get_nth_id_str")] + pub fn nth_id(&self, idx: usize) -> Option<&IdStr> { + if idx >= self.size() { + return None; + } + + unsafe { + let feature = ffi::gst_caps_features_get_nth_id_str(self.as_ptr(), idx as u32); + if feature.is_null() { + return None; + } + + Some(&*(feature as *const IdStr)) + } + } + + #[deprecated = "use `nth_by_id()` instead"] #[doc(alias = "gst_caps_features_get_nth_id")] pub fn nth_quark(&self, idx: usize) -> Option { if idx >= self.size() { @@ -428,6 +494,32 @@ impl CapsFeaturesRef { } } + #[doc(alias = "gst_caps_features_add_static_str")] + pub fn add_from_static(&mut self, feature: impl AsRef + 'static) { + unsafe { + cfg_if! { + if #[cfg(feature = "v1_26")] { + ffi::gst_caps_features_add_static_str(self.as_mut_ptr(), feature.as_ref().as_ptr()) + } else { + ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ref().as_ptr()) + } + } + } + } + + #[doc(alias = "gst_caps_features_add_id_str")] + pub fn add_from_id(&mut self, feature: impl AsRef) { + unsafe { + cfg_if! { + if #[cfg(feature = "v1_26")] { + ffi::gst_caps_features_add_id_str(self.as_mut_ptr(), feature.as_ref().as_ptr()) + } else { + ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ref().as_gstr().as_ptr()) + } + } + } + } + #[doc(alias = "gst_caps_features_remove")] pub fn remove(&mut self, feature: impl IntoGStr) { unsafe { @@ -437,11 +529,26 @@ impl CapsFeaturesRef { } } + #[doc(alias = "gst_caps_features_remove_id_str")] + pub fn remove_by_id(&mut self, feature: impl AsRef) { + unsafe { + cfg_if! { + if #[cfg(feature = "v1_26")] { + ffi::gst_caps_features_remove_id_str(self.as_mut_ptr(), feature.as_ref().as_ptr()) + } else { + ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.as_ref().as_gstr().as_ptr()) + } + } + } + } + + #[deprecated = "use `add_by_id()` instead"] #[doc(alias = "gst_caps_features_add_id")] pub fn add_from_quark(&mut self, feature: glib::Quark) { unsafe { ffi::gst_caps_features_add_id(self.as_mut_ptr(), feature.into_glib()) } } + #[deprecated = "use `remove_by_id()` instead"] #[doc(alias = "gst_caps_features_remove_id")] pub fn remove_by_quark(&mut self, feature: glib::Quark) { unsafe { ffi::gst_caps_features_remove_id(self.as_mut_ptr(), feature.into_glib()) } @@ -494,7 +601,14 @@ impl std::iter::Extend for CapsFeaturesRef { } } +impl> std::iter::Extend for CapsFeaturesRef { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|f| self.add_from_id(f)); + } +} + impl std::iter::Extend for CapsFeaturesRef { + #[allow(deprecated)] fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add_from_quark(f)); } @@ -706,7 +820,19 @@ impl<'a> From<&'a glib::GStr> for CapsFeatures { } } +impl> From for CapsFeatures { + fn from(value: Id) -> Self { + skip_assert_initialized!(); + let mut features = CapsFeatures::new_empty(); + + features.add_from_id(value); + + features + } +} + impl From for CapsFeatures { + #[allow(deprecated)] fn from(value: glib::Quark) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); @@ -761,7 +887,19 @@ impl From<[glib::GString; N]> for CapsFeatures { } } +impl> From<[Id; N]> for CapsFeatures { + fn from(value: [Id; N]) -> Self { + skip_assert_initialized!(); + let mut features = CapsFeatures::new_empty(); + + value.into_iter().for_each(|f| features.add_from_id(f)); + + features + } +} + impl From<[glib::Quark; N]> for CapsFeatures { + #[allow(deprecated)] fn from(value: [glib::Quark; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); @@ -818,7 +956,20 @@ impl std::iter::FromIterator for CapsFeatures { } } +impl> std::iter::FromIterator for CapsFeatures { + #[allow(deprecated)] + fn from_iter>(iter: T) -> Self { + skip_assert_initialized!(); + let mut features = CapsFeatures::new_empty(); + + iter.into_iter().for_each(|f| features.add_from_id(f)); + + features + } +} + impl std::iter::FromIterator for CapsFeatures { + #[allow(deprecated)] fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); @@ -866,6 +1017,8 @@ pub static CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: LazyLock = #[cfg(test)] mod tests { use super::*; + use crate::idstr; + use glib::gstr; #[test] fn test_from_value_optional() { @@ -878,4 +1031,106 @@ mod tests { let b = glib::value::Value::from(&CapsFeatures::new_empty()); assert!(b.get::>().unwrap().is_some()); } + + #[test] + fn trait_impls() { + crate::init().unwrap(); + + let cf = CapsFeatures::from(gstr!("memory:DMABuf")); + assert!(cf.contains(gstr!("memory:DMABuf"))); + + let cf = CapsFeatures::from([ + gstr!("memory:DMABuf"), + gstr!("meta:GstVideoOverlayComposition"), + ]); + + assert!(cf.contains(gstr!("memory:DMABuf"))); + assert!(cf.contains("meta:GstVideoOverlayComposition")); + assert!(!cf.contains("memory:GLMemory")); + + let cf = CapsFeatures::from_iter(vec![ + gstr!("memory:DMABuf"), + gstr!("meta:GstVideoOverlayComposition"), + ]); + + assert!(cf.contains(gstr!("memory:DMABuf"))); + assert!(cf.contains("meta:GstVideoOverlayComposition")); + assert!(!cf.contains("memory:GLMemory")); + + let mut cf = CapsFeatures::new_empty(); + cf.extend([ + gstr!("memory:DMABuf"), + gstr!("meta:GstVideoOverlayComposition"), + ]); + + assert!(cf.contains(gstr!("memory:DMABuf"))); + assert!(cf.contains("meta:GstVideoOverlayComposition")); + assert!(!cf.contains("memory:GLMemory")); + } + + #[test] + fn trait_impls_from_id() { + crate::init().unwrap(); + + let cf = CapsFeatures::from(idstr!("memory:DMABuf")); + assert!(cf.contains_by_id(idstr!("memory:DMABuf"))); + + let cf = CapsFeatures::from([ + idstr!("memory:DMABuf"), + idstr!("meta:GstVideoOverlayComposition"), + ]); + + assert!(cf.contains_by_id(idstr!("memory:DMABuf"))); + assert!(cf.contains("meta:GstVideoOverlayComposition")); + assert!(!cf.contains("memory:GLMemory")); + + let cf = CapsFeatures::from_iter(vec![ + idstr!("memory:DMABuf"), + idstr!("meta:GstVideoOverlayComposition"), + ]); + + assert!(cf.contains_by_id(idstr!("memory:DMABuf"))); + assert!(cf.contains("meta:GstVideoOverlayComposition")); + assert!(!cf.contains("memory:GLMemory")); + + let mut cf = CapsFeatures::new_empty(); + cf.extend([ + idstr!("memory:DMABuf"), + idstr!("meta:GstVideoOverlayComposition"), + ]); + + assert!(cf.contains_by_id(idstr!("memory:DMABuf"))); + assert!(cf.contains("meta:GstVideoOverlayComposition")); + assert!(!cf.contains("memory:GLMemory")); + } + + #[test] + fn trait_impls_from_ref_id() { + crate::init().unwrap(); + + let dma_buf = idstr!("memory:DMABuf"); + let overlay_comp = idstr!("meta:GstVideoOverlayComposition"); + + let cf = CapsFeatures::from(&dma_buf); + assert!(cf.contains_by_id(&dma_buf)); + + let cf = CapsFeatures::from([&dma_buf, &overlay_comp]); + + assert!(cf.contains_by_id(&dma_buf)); + assert!(cf.contains_by_id(&overlay_comp)); + assert!(!cf.contains("memory:GLMemory")); + + let cf = CapsFeatures::from_iter(vec![&dma_buf, &overlay_comp]); + + assert!(cf.contains_by_id(&dma_buf)); + assert!(cf.contains_by_id(&overlay_comp)); + assert!(!cf.contains("memory:GLMemory")); + + let mut cf = CapsFeatures::new_empty(); + cf.extend([&dma_buf, &overlay_comp]); + + assert!(cf.contains_by_id(dma_buf)); + assert!(cf.contains_by_id(overlay_comp)); + assert!(!cf.contains("memory:GLMemory")); + } }