gstreamer/
caps_features.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    borrow::{Borrow, BorrowMut, ToOwned},
5    fmt,
6    marker::PhantomData,
7    mem,
8    ops::{Deref, DerefMut},
9    ptr, str,
10};
11
12use crate::{ffi, IdStr};
13use cfg_if::cfg_if;
14use glib::{prelude::*, translate::*};
15use std::sync::LazyLock;
16
17/// [`CapsFeatures`][crate::CapsFeatures] can optionally be set on a [`Caps`][crate::Caps] to add requirements
18/// for additional features for a specific [`Structure`][crate::Structure]. Caps structures with
19/// the same name but with a non-equal set of caps features are not compatible.
20/// If a pad supports multiple sets of features it has to add multiple equal
21/// structures with different feature sets to the caps.
22///
23/// Empty [`CapsFeatures`][crate::CapsFeatures] are equivalent with the [`CapsFeatures`][crate::CapsFeatures] that only
24/// contain `GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY`. ANY [`CapsFeatures`][crate::CapsFeatures] as
25/// created by [`new_any()`][Self::new_any()] are equal to any other [`CapsFeatures`][crate::CapsFeatures]
26/// and can be used to specify that any [`CapsFeatures`][crate::CapsFeatures] would be supported, e.g.
27/// for elements that don't touch buffer memory. [`Caps`][crate::Caps] with ANY [`CapsFeatures`][crate::CapsFeatures]
28/// are considered non-fixed and during negotiation some [`CapsFeatures`][crate::CapsFeatures] have
29/// to be selected.
30///
31/// Examples for caps features would be the requirement of a specific [`Memory`][crate::Memory]
32/// types or the requirement of having a specific `GstMeta` on the buffer. Features
33/// are given as a string of the format `memory:GstMemoryTypeName` or
34/// `meta:GstMetaAPIName`.
35#[doc(alias = "GstCapsFeatures")]
36#[repr(transparent)]
37pub struct CapsFeatures(ptr::NonNull<ffi::GstCapsFeatures>);
38unsafe impl Send for CapsFeatures {}
39unsafe impl Sync for CapsFeatures {}
40
41impl CapsFeatures {
42    /// Creates a new [`CapsFeatures`][crate::CapsFeatures] with the given features.
43    /// The last argument must be [`None`].
44    /// ## `feature1`
45    /// name of first feature to set
46    ///
47    /// # Returns
48    ///
49    /// a new, empty [`CapsFeatures`][crate::CapsFeatures]
50    #[doc(alias = "gst_caps_features_new")]
51    pub fn new<S: IntoGStr>(features: impl IntoIterator<Item = S>) -> Self {
52        skip_assert_initialized!();
53        let mut f = Self::new_empty();
54
55        for feature in features {
56            f.add(feature);
57        }
58
59        f
60    }
61
62    #[doc(alias = "gst_caps_features_new_static_str")]
63    pub fn new_from_static<S: AsRef<glib::GStr> + 'static>(
64        features: impl IntoIterator<Item = S>,
65    ) -> Self {
66        skip_assert_initialized!();
67        let mut f = Self::new_empty();
68
69        for feature in features {
70            f.add_from_static(feature);
71        }
72
73        f
74    }
75
76    #[doc(alias = "gst_caps_features_new_id_str")]
77    pub fn new_from_id<S: AsRef<IdStr>>(features: impl IntoIterator<Item = S>) -> Self {
78        skip_assert_initialized!();
79        let mut f = Self::new_empty();
80
81        for feature in features {
82            f.add_from_id(feature);
83        }
84
85        f
86    }
87
88    #[deprecated = "use `new_by_id()` instead"]
89    #[allow(deprecated)]
90    #[doc(alias = "gst_caps_features_new_id")]
91    pub fn from_quarks(features: impl IntoIterator<Item = glib::Quark>) -> Self {
92        skip_assert_initialized!();
93        let mut f = Self::new_empty();
94
95        for feature in features.into_iter() {
96            f.add_from_quark(feature);
97        }
98
99        f
100    }
101
102    /// Creates a new, empty [`CapsFeatures`][crate::CapsFeatures].
103    ///
104    /// # Returns
105    ///
106    /// a new, empty [`CapsFeatures`][crate::CapsFeatures]
107    #[doc(alias = "gst_caps_features_new_empty")]
108    pub fn new_empty() -> Self {
109        assert_initialized_main_thread!();
110        unsafe {
111            CapsFeatures(ptr::NonNull::new_unchecked(
112                ffi::gst_caps_features_new_empty(),
113            ))
114        }
115    }
116
117    /// Creates a new, ANY [`CapsFeatures`][crate::CapsFeatures]. This will be equal
118    /// to any other [`CapsFeatures`][crate::CapsFeatures] but caps with these are
119    /// unfixed.
120    ///
121    /// # Returns
122    ///
123    /// a new, ANY [`CapsFeatures`][crate::CapsFeatures]
124    #[doc(alias = "gst_caps_features_new_any")]
125    pub fn new_any() -> Self {
126        assert_initialized_main_thread!();
127        unsafe { CapsFeatures(ptr::NonNull::new_unchecked(ffi::gst_caps_features_new_any())) }
128    }
129}
130
131impl IntoGlibPtr<*mut ffi::GstCapsFeatures> for CapsFeatures {
132    #[inline]
133    fn into_glib_ptr(self) -> *mut ffi::GstCapsFeatures {
134        let s = mem::ManuallyDrop::new(self);
135        s.0.as_ptr()
136    }
137}
138
139impl Deref for CapsFeatures {
140    type Target = CapsFeaturesRef;
141
142    #[inline]
143    fn deref(&self) -> &CapsFeaturesRef {
144        unsafe { &*(self.0.as_ref() as *const ffi::GstCapsFeatures as *const CapsFeaturesRef) }
145    }
146}
147
148impl DerefMut for CapsFeatures {
149    #[inline]
150    fn deref_mut(&mut self) -> &mut CapsFeaturesRef {
151        unsafe { &mut *(self.0.as_mut() as *mut ffi::GstCapsFeatures as *mut CapsFeaturesRef) }
152    }
153}
154
155impl AsRef<CapsFeaturesRef> for CapsFeatures {
156    #[inline]
157    fn as_ref(&self) -> &CapsFeaturesRef {
158        self.deref()
159    }
160}
161
162impl AsMut<CapsFeaturesRef> for CapsFeatures {
163    #[inline]
164    fn as_mut(&mut self) -> &mut CapsFeaturesRef {
165        self.deref_mut()
166    }
167}
168
169impl Clone for CapsFeatures {
170    #[inline]
171    fn clone(&self) -> Self {
172        unsafe {
173            let ptr = ffi::gst_caps_features_copy(self.0.as_ref());
174            debug_assert!(!ptr.is_null());
175            CapsFeatures(ptr::NonNull::new_unchecked(ptr))
176        }
177    }
178}
179
180impl Drop for CapsFeatures {
181    #[inline]
182    fn drop(&mut self) {
183        unsafe { ffi::gst_caps_features_free(self.0.as_mut()) }
184    }
185}
186
187impl fmt::Debug for CapsFeatures {
188    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189        f.debug_tuple("CapsFeatures")
190            .field(&self.to_string())
191            .finish()
192    }
193}
194
195impl fmt::Display for CapsFeatures {
196    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197        // Need to make sure to not call ToString::to_string() here, which
198        // we have because of the Display impl. We need CapsFeaturesRef::to_string()
199        f.write_str(&CapsFeaturesRef::to_string(self.as_ref()))
200    }
201}
202
203impl str::FromStr for CapsFeatures {
204    type Err = glib::BoolError;
205
206    #[doc(alias = "gst_caps_features_from_string")]
207    fn from_str(s: &str) -> Result<Self, Self::Err> {
208        assert_initialized_main_thread!();
209        unsafe {
210            let ptr = s.run_with_gstr(|s| ffi::gst_caps_features_from_string(s.as_ptr()));
211            if ptr.is_null() {
212                return Err(glib::bool_error!(
213                    "Failed to parse caps features from string"
214                ));
215            }
216
217            Ok(Self(ptr::NonNull::new_unchecked(ptr)))
218        }
219    }
220}
221
222impl Borrow<CapsFeaturesRef> for CapsFeatures {
223    #[inline]
224    fn borrow(&self) -> &CapsFeaturesRef {
225        self.as_ref()
226    }
227}
228
229impl BorrowMut<CapsFeaturesRef> for CapsFeatures {
230    #[inline]
231    fn borrow_mut(&mut self) -> &mut CapsFeaturesRef {
232        self.as_mut()
233    }
234}
235
236impl glib::types::StaticType for CapsFeatures {
237    #[inline]
238    fn static_type() -> glib::types::Type {
239        unsafe { from_glib(ffi::gst_caps_features_get_type()) }
240    }
241}
242
243impl<'a> ToGlibPtr<'a, *const ffi::GstCapsFeatures> for CapsFeatures {
244    type Storage = PhantomData<&'a Self>;
245
246    #[inline]
247    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self> {
248        unsafe { Stash(self.0.as_ref(), PhantomData) }
249    }
250
251    #[inline]
252    fn to_glib_full(&self) -> *const ffi::GstCapsFeatures {
253        unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) }
254    }
255}
256
257impl<'a> ToGlibPtr<'a, *mut ffi::GstCapsFeatures> for CapsFeatures {
258    type Storage = PhantomData<&'a Self>;
259
260    #[inline]
261    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self> {
262        unsafe {
263            Stash(
264                self.0.as_ref() as *const ffi::GstCapsFeatures as *mut ffi::GstCapsFeatures,
265                PhantomData,
266            )
267        }
268    }
269
270    #[inline]
271    fn to_glib_full(&self) -> *mut ffi::GstCapsFeatures {
272        unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) }
273    }
274}
275
276impl<'a> ToGlibPtrMut<'a, *mut ffi::GstCapsFeatures> for CapsFeatures {
277    type Storage = PhantomData<&'a mut Self>;
278
279    #[inline]
280    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GstCapsFeatures, Self> {
281        unsafe { StashMut(self.0.as_mut(), PhantomData) }
282    }
283}
284
285impl FromGlibPtrNone<*const ffi::GstCapsFeatures> for CapsFeatures {
286    #[inline]
287    unsafe fn from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self {
288        debug_assert!(!ptr.is_null());
289        let ptr = ffi::gst_caps_features_copy(ptr);
290        debug_assert!(!ptr.is_null());
291        CapsFeatures(ptr::NonNull::new_unchecked(ptr))
292    }
293}
294
295impl FromGlibPtrNone<*mut ffi::GstCapsFeatures> for CapsFeatures {
296    #[inline]
297    unsafe fn from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self {
298        debug_assert!(!ptr.is_null());
299        let ptr = ffi::gst_caps_features_copy(ptr);
300        debug_assert!(!ptr.is_null());
301        CapsFeatures(ptr::NonNull::new_unchecked(ptr))
302    }
303}
304
305impl FromGlibPtrFull<*const ffi::GstCapsFeatures> for CapsFeatures {
306    #[inline]
307    unsafe fn from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self {
308        debug_assert!(!ptr.is_null());
309        CapsFeatures(ptr::NonNull::new_unchecked(
310            ptr as *mut ffi::GstCapsFeatures,
311        ))
312    }
313}
314
315impl FromGlibPtrFull<*mut ffi::GstCapsFeatures> for CapsFeatures {
316    #[inline]
317    unsafe fn from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self {
318        debug_assert!(!ptr.is_null());
319        CapsFeatures(ptr::NonNull::new_unchecked(ptr))
320    }
321}
322
323impl glib::value::ValueType for CapsFeatures {
324    type Type = Self;
325}
326
327impl glib::value::ValueTypeOptional for CapsFeatures {}
328
329unsafe impl<'a> glib::value::FromValue<'a> for CapsFeatures {
330    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
331
332    unsafe fn from_value(value: &'a glib::Value) -> Self {
333        skip_assert_initialized!();
334        from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0)
335            as *mut ffi::GstCapsFeatures)
336    }
337}
338
339impl glib::value::ToValue for CapsFeatures {
340    fn to_value(&self) -> glib::Value {
341        let mut value = glib::Value::for_value_type::<Self>();
342        unsafe {
343            glib::gobject_ffi::g_value_set_boxed(
344                value.to_glib_none_mut().0,
345                ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(self).0 as *mut _,
346            )
347        }
348        value
349    }
350
351    fn value_type(&self) -> glib::Type {
352        Self::static_type()
353    }
354}
355
356impl glib::value::ToValueOptional for CapsFeatures {
357    fn to_value_optional(s: Option<&Self>) -> glib::Value {
358        skip_assert_initialized!();
359        let mut value = glib::Value::for_value_type::<Self>();
360        unsafe {
361            glib::gobject_ffi::g_value_set_boxed(
362                value.to_glib_none_mut().0,
363                ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(&s).0 as *mut _,
364            )
365        }
366        value
367    }
368}
369
370impl From<CapsFeatures> for glib::Value {
371    fn from(v: CapsFeatures) -> glib::Value {
372        skip_assert_initialized!();
373        let mut value = glib::Value::for_value_type::<CapsFeatures>();
374        unsafe {
375            glib::gobject_ffi::g_value_take_boxed(
376                value.to_glib_none_mut().0,
377                IntoGlibPtr::<*mut ffi::GstCapsFeatures>::into_glib_ptr(v) as *mut _,
378            )
379        }
380        value
381    }
382}
383
384impl GlibPtrDefault for CapsFeatures {
385    type GlibType = *mut ffi::GstCapsFeatures;
386}
387
388unsafe impl TransparentPtrType for CapsFeatures {}
389
390#[repr(transparent)]
391#[doc(alias = "GstCapsFeatures")]
392pub struct CapsFeaturesRef(ffi::GstCapsFeatures);
393
394impl CapsFeaturesRef {
395    #[inline]
396    pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef {
397        debug_assert!(!ptr.is_null());
398
399        &*(ptr as *mut CapsFeaturesRef)
400    }
401
402    #[inline]
403    pub unsafe fn from_glib_borrow_mut<'a>(
404        ptr: *mut ffi::GstCapsFeatures,
405    ) -> &'a mut CapsFeaturesRef {
406        debug_assert!(!ptr.is_null());
407
408        &mut *(ptr as *mut CapsFeaturesRef)
409    }
410
411    #[inline]
412    pub fn as_ptr(&self) -> *const ffi::GstCapsFeatures {
413        self as *const Self as *const ffi::GstCapsFeatures
414    }
415
416    #[inline]
417    pub fn as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures {
418        self as *const Self as *mut ffi::GstCapsFeatures
419    }
420
421    pub fn is_empty(&self) -> bool {
422        self.size() == 0 && !self.is_any()
423    }
424
425    #[doc(alias = "gst_caps_features_is_any")]
426    pub fn is_any(&self) -> bool {
427        unsafe { from_glib(ffi::gst_caps_features_is_any(self.as_ptr())) }
428    }
429
430    #[doc(alias = "gst_caps_features_contains")]
431    pub fn contains(&self, feature: impl IntoGStr) -> bool {
432        unsafe {
433            feature.run_with_gstr(|feature| {
434                from_glib(ffi::gst_caps_features_contains(
435                    self.as_ptr(),
436                    feature.as_ptr(),
437                ))
438            })
439        }
440    }
441
442    #[doc(alias = "gst_caps_features_contains_id_str")]
443    pub fn contains_by_id(&self, feature: impl AsRef<IdStr>) -> bool {
444        unsafe {
445            cfg_if! {
446                if #[cfg(feature = "v1_26")] {
447                    from_glib(ffi::gst_caps_features_contains_id_str(
448                        self.as_ptr(),
449                        feature.as_ref().as_ptr(),
450                    ))
451                } else {
452                    from_glib(ffi::gst_caps_features_contains(
453                        self.as_ptr(),
454                        feature.as_ref().as_gstr().as_ptr(),
455                    ))
456                }
457            }
458        }
459    }
460
461    #[deprecated = "use `contains_by_id()` instead"]
462    #[doc(alias = "gst_caps_features_contains_id")]
463    pub fn contains_quark(&self, feature: glib::Quark) -> bool {
464        unsafe {
465            from_glib(ffi::gst_caps_features_contains_id(
466                self.as_ptr(),
467                feature.into_glib(),
468            ))
469        }
470    }
471
472    #[doc(alias = "get_size")]
473    #[doc(alias = "gst_caps_features_get_size")]
474    pub fn size(&self) -> usize {
475        unsafe { ffi::gst_caps_features_get_size(self.as_ptr()) as usize }
476    }
477
478    #[doc(alias = "get_nth")]
479    #[doc(alias = "gst_caps_features_get_nth")]
480    pub fn nth(&self, idx: usize) -> Option<&glib::GStr> {
481        if idx >= self.size() {
482            return None;
483        }
484
485        unsafe {
486            let feature = ffi::gst_caps_features_get_nth(self.as_ptr(), idx as u32);
487            if feature.is_null() {
488                return None;
489            }
490
491            Some(glib::GStr::from_ptr(feature))
492        }
493    }
494
495    #[cfg(feature = "v1_26")]
496    #[doc(alias = "get_nth_by_id")]
497    #[doc(alias = "gst_caps_features_get_nth_id_str")]
498    pub fn nth_id(&self, idx: usize) -> Option<&IdStr> {
499        if idx >= self.size() {
500            return None;
501        }
502
503        unsafe {
504            let feature = ffi::gst_caps_features_get_nth_id_str(self.as_ptr(), idx as u32);
505            if feature.is_null() {
506                return None;
507            }
508
509            Some(&*(feature as *const IdStr))
510        }
511    }
512
513    #[deprecated = "use `nth_by_id()` instead"]
514    #[doc(alias = "gst_caps_features_get_nth_id")]
515    pub fn nth_quark(&self, idx: usize) -> Option<glib::Quark> {
516        if idx >= self.size() {
517            return None;
518        }
519
520        unsafe {
521            let feature = ffi::gst_caps_features_get_nth_id(self.as_ptr(), idx as u32);
522            Some(from_glib(feature))
523        }
524    }
525
526    #[doc(alias = "gst_caps_features_add")]
527    pub fn add(&mut self, feature: impl IntoGStr) {
528        unsafe {
529            feature.run_with_gstr(|feature| {
530                ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ptr())
531            })
532        }
533    }
534
535    #[doc(alias = "gst_caps_features_add_static_str")]
536    pub fn add_from_static(&mut self, feature: impl AsRef<glib::GStr> + 'static) {
537        unsafe {
538            cfg_if! {
539                if #[cfg(feature = "v1_26")] {
540                    ffi::gst_caps_features_add_static_str(self.as_mut_ptr(), feature.as_ref().as_ptr())
541                } else {
542                    ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ref().as_ptr())
543                }
544            }
545        }
546    }
547
548    #[doc(alias = "gst_caps_features_add_id_str")]
549    pub fn add_from_id(&mut self, feature: impl AsRef<IdStr>) {
550        unsafe {
551            cfg_if! {
552                if #[cfg(feature = "v1_26")] {
553                    ffi::gst_caps_features_add_id_str(self.as_mut_ptr(), feature.as_ref().as_ptr())
554                } else {
555                    ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ref().as_gstr().as_ptr())
556                }
557            }
558        }
559    }
560
561    #[doc(alias = "gst_caps_features_remove")]
562    pub fn remove(&mut self, feature: impl IntoGStr) {
563        unsafe {
564            feature.run_with_gstr(|feature| {
565                ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.as_ptr())
566            })
567        }
568    }
569
570    #[doc(alias = "gst_caps_features_remove_id_str")]
571    pub fn remove_by_id(&mut self, feature: impl AsRef<IdStr>) {
572        unsafe {
573            cfg_if! {
574                if #[cfg(feature = "v1_26")] {
575                    ffi::gst_caps_features_remove_id_str(self.as_mut_ptr(), feature.as_ref().as_ptr())
576                } else {
577                    ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.as_ref().as_gstr().as_ptr())
578                }
579            }
580        }
581    }
582
583    #[deprecated = "use `add_by_id()` instead"]
584    #[doc(alias = "gst_caps_features_add_id")]
585    pub fn add_from_quark(&mut self, feature: glib::Quark) {
586        unsafe { ffi::gst_caps_features_add_id(self.as_mut_ptr(), feature.into_glib()) }
587    }
588
589    #[deprecated = "use `remove_by_id()` instead"]
590    #[doc(alias = "gst_caps_features_remove_id")]
591    pub fn remove_by_quark(&mut self, feature: glib::Quark) {
592        unsafe { ffi::gst_caps_features_remove_id(self.as_mut_ptr(), feature.into_glib()) }
593    }
594
595    pub fn iter(&self) -> Iter {
596        Iter::new(self)
597    }
598
599    // This is not an equivalence relation with regards to ANY. Everything is equal to ANY
600    #[doc(alias = "gst_caps_features_is_equal")]
601    pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool {
602        unsafe {
603            from_glib(ffi::gst_caps_features_is_equal(
604                self.as_ptr(),
605                other.as_ptr(),
606            ))
607        }
608    }
609}
610
611impl glib::types::StaticType for CapsFeaturesRef {
612    #[inline]
613    fn static_type() -> glib::types::Type {
614        unsafe { from_glib(ffi::gst_structure_get_type()) }
615    }
616}
617
618impl<'a> std::iter::Extend<&'a str> for CapsFeaturesRef {
619    fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
620        iter.into_iter().for_each(|f| self.add(f));
621    }
622}
623
624impl<'a> std::iter::Extend<&'a glib::GStr> for CapsFeaturesRef {
625    fn extend<T: IntoIterator<Item = &'a glib::GStr>>(&mut self, iter: T) {
626        iter.into_iter().for_each(|f| self.add(f));
627    }
628}
629
630impl std::iter::Extend<String> for CapsFeaturesRef {
631    fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
632        iter.into_iter().for_each(|f| self.add(&f));
633    }
634}
635
636impl std::iter::Extend<glib::GString> for CapsFeaturesRef {
637    fn extend<T: IntoIterator<Item = glib::GString>>(&mut self, iter: T) {
638        iter.into_iter().for_each(|f| self.add(&f));
639    }
640}
641
642impl<Id: AsRef<IdStr>> std::iter::Extend<Id> for CapsFeaturesRef {
643    fn extend<T: IntoIterator<Item = Id>>(&mut self, iter: T) {
644        iter.into_iter().for_each(|f| self.add_from_id(f));
645    }
646}
647
648impl std::iter::Extend<glib::Quark> for CapsFeaturesRef {
649    #[allow(deprecated)]
650    fn extend<T: IntoIterator<Item = glib::Quark>>(&mut self, iter: T) {
651        iter.into_iter().for_each(|f| self.add_from_quark(f));
652    }
653}
654
655unsafe impl<'a> glib::value::FromValue<'a> for &'a CapsFeaturesRef {
656    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
657
658    unsafe fn from_value(value: &'a glib::Value) -> Self {
659        skip_assert_initialized!();
660        &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const CapsFeaturesRef)
661    }
662}
663
664impl glib::value::ToValue for CapsFeaturesRef {
665    fn to_value(&self) -> glib::Value {
666        let mut value = glib::Value::for_value_type::<CapsFeatures>();
667        unsafe {
668            glib::gobject_ffi::g_value_set_boxed(
669                value.to_glib_none_mut().0,
670                self.as_mut_ptr() as *mut _,
671            )
672        }
673        value
674    }
675
676    fn value_type(&self) -> glib::Type {
677        Self::static_type()
678    }
679}
680
681impl glib::value::ToValueOptional for CapsFeaturesRef {
682    fn to_value_optional(s: Option<&Self>) -> glib::Value {
683        skip_assert_initialized!();
684        let mut value = glib::Value::for_value_type::<CapsFeatures>();
685        unsafe {
686            glib::gobject_ffi::g_value_set_boxed(
687                value.to_glib_none_mut().0,
688                s.map(|s| s.as_mut_ptr()).unwrap_or(ptr::null_mut()) as *mut _,
689            )
690        }
691        value
692    }
693}
694
695crate::utils::define_fixed_size_iter!(
696    Iter,
697    &'a CapsFeaturesRef,
698    &'a glib::GStr,
699    |collection: &CapsFeaturesRef| collection.size(),
700    |collection: &CapsFeaturesRef, idx: usize| unsafe {
701        let feature = ffi::gst_caps_features_get_nth(collection.as_ptr(), idx as u32);
702        glib::GStr::from_ptr(feature)
703    }
704);
705
706impl<'a> IntoIterator for &'a CapsFeaturesRef {
707    type IntoIter = Iter<'a>;
708    type Item = &'a glib::GStr;
709
710    fn into_iter(self) -> Self::IntoIter {
711        self.iter()
712    }
713}
714
715impl<'a> From<&'a str> for CapsFeatures {
716    fn from(value: &'a str) -> Self {
717        skip_assert_initialized!();
718        let mut features = CapsFeatures::new_empty();
719
720        features.add(value);
721
722        features
723    }
724}
725
726impl<'a> From<&'a glib::GStr> for CapsFeatures {
727    fn from(value: &'a glib::GStr) -> Self {
728        skip_assert_initialized!();
729        let mut features = CapsFeatures::new_empty();
730
731        features.add(value);
732
733        features
734    }
735}
736
737impl<Id: AsRef<IdStr>> From<Id> for CapsFeatures {
738    fn from(value: Id) -> Self {
739        skip_assert_initialized!();
740        let mut features = CapsFeatures::new_empty();
741
742        features.add_from_id(value);
743
744        features
745    }
746}
747
748impl From<glib::Quark> for CapsFeatures {
749    #[allow(deprecated)]
750    fn from(value: glib::Quark) -> Self {
751        skip_assert_initialized!();
752        let mut features = CapsFeatures::new_empty();
753
754        features.add_from_quark(value);
755
756        features
757    }
758}
759
760impl<'a, const N: usize> From<[&'a str; N]> for CapsFeatures {
761    fn from(value: [&'a str; N]) -> Self {
762        skip_assert_initialized!();
763        let mut features = CapsFeatures::new_empty();
764
765        value.into_iter().for_each(|f| features.add(f));
766
767        features
768    }
769}
770
771impl<'a, const N: usize> From<[&'a glib::GStr; N]> for CapsFeatures {
772    fn from(value: [&'a glib::GStr; N]) -> Self {
773        skip_assert_initialized!();
774        let mut features = CapsFeatures::new_empty();
775
776        value.into_iter().for_each(|f| features.add(f));
777
778        features
779    }
780}
781
782impl<const N: usize> From<[String; N]> for CapsFeatures {
783    fn from(value: [String; N]) -> Self {
784        skip_assert_initialized!();
785        let mut features = CapsFeatures::new_empty();
786
787        value.into_iter().for_each(|f| features.add(&f));
788
789        features
790    }
791}
792
793impl<const N: usize> From<[glib::GString; N]> for CapsFeatures {
794    fn from(value: [glib::GString; N]) -> Self {
795        skip_assert_initialized!();
796        let mut features = CapsFeatures::new_empty();
797
798        value.into_iter().for_each(|f| features.add(&f));
799
800        features
801    }
802}
803
804impl<const N: usize, Id: AsRef<IdStr>> From<[Id; N]> for CapsFeatures {
805    fn from(value: [Id; N]) -> Self {
806        skip_assert_initialized!();
807        let mut features = CapsFeatures::new_empty();
808
809        value.into_iter().for_each(|f| features.add_from_id(f));
810
811        features
812    }
813}
814
815impl<const N: usize> From<[glib::Quark; N]> for CapsFeatures {
816    #[allow(deprecated)]
817    fn from(value: [glib::Quark; N]) -> Self {
818        skip_assert_initialized!();
819        let mut features = CapsFeatures::new_empty();
820
821        value.into_iter().for_each(|f| features.add_from_quark(f));
822
823        features
824    }
825}
826
827impl<'a> std::iter::FromIterator<&'a str> for CapsFeatures {
828    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
829        skip_assert_initialized!();
830        let mut features = CapsFeatures::new_empty();
831
832        iter.into_iter().for_each(|f| features.add(f));
833
834        features
835    }
836}
837
838impl<'a> std::iter::FromIterator<&'a glib::GStr> for CapsFeatures {
839    fn from_iter<T: IntoIterator<Item = &'a glib::GStr>>(iter: T) -> Self {
840        assert_initialized_main_thread!();
841
842        let mut features = CapsFeatures::new_empty();
843
844        iter.into_iter().for_each(|f| features.add(f));
845
846        features
847    }
848}
849
850impl std::iter::FromIterator<String> for CapsFeatures {
851    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
852        skip_assert_initialized!();
853        let mut features = CapsFeatures::new_empty();
854
855        iter.into_iter().for_each(|f| features.add(&f));
856
857        features
858    }
859}
860
861impl std::iter::FromIterator<glib::GString> for CapsFeatures {
862    fn from_iter<T: IntoIterator<Item = glib::GString>>(iter: T) -> Self {
863        assert_initialized_main_thread!();
864
865        let mut features = CapsFeatures::new_empty();
866
867        iter.into_iter().for_each(|f| features.add(&f));
868
869        features
870    }
871}
872
873impl<Id: AsRef<IdStr>> std::iter::FromIterator<Id> for CapsFeatures {
874    #[allow(deprecated)]
875    fn from_iter<T: IntoIterator<Item = Id>>(iter: T) -> Self {
876        skip_assert_initialized!();
877        let mut features = CapsFeatures::new_empty();
878
879        iter.into_iter().for_each(|f| features.add_from_id(f));
880
881        features
882    }
883}
884
885impl std::iter::FromIterator<glib::Quark> for CapsFeatures {
886    #[allow(deprecated)]
887    fn from_iter<T: IntoIterator<Item = glib::Quark>>(iter: T) -> Self {
888        skip_assert_initialized!();
889        let mut features = CapsFeatures::new_empty();
890
891        iter.into_iter().for_each(|f| features.add_from_quark(f));
892
893        features
894    }
895}
896
897impl fmt::Debug for CapsFeaturesRef {
898    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
899        f.debug_tuple("CapsFeatures")
900            .field(&self.to_string())
901            .finish()
902    }
903}
904
905impl fmt::Display for CapsFeaturesRef {
906    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
907        let s = unsafe {
908            glib::GString::from_glib_full(ffi::gst_caps_features_to_string(self.as_ptr()))
909        };
910        f.write_str(&s)
911    }
912}
913
914impl ToOwned for CapsFeaturesRef {
915    type Owned = CapsFeatures;
916
917    #[inline]
918    fn to_owned(&self) -> CapsFeatures {
919        unsafe { from_glib_full(ffi::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) }
920    }
921}
922
923unsafe impl Sync for CapsFeaturesRef {}
924unsafe impl Send for CapsFeaturesRef {}
925
926pub static CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: &glib::GStr =
927    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) };
928pub static CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: LazyLock<CapsFeatures> =
929    LazyLock::new(|| CapsFeatures::new([CAPS_FEATURE_MEMORY_SYSTEM_MEMORY]));
930
931#[cfg(test)]
932mod tests {
933    use super::*;
934    use crate::idstr;
935    use glib::gstr;
936
937    #[test]
938    fn test_from_value_optional() {
939        use glib::value::ToValue;
940
941        crate::init().unwrap();
942
943        let a = None::<CapsFeatures>.to_value();
944        assert!(a.get::<Option<CapsFeatures>>().unwrap().is_none());
945        let b = glib::value::Value::from(&CapsFeatures::new_empty());
946        assert!(b.get::<Option<CapsFeatures>>().unwrap().is_some());
947    }
948
949    #[test]
950    fn trait_impls() {
951        crate::init().unwrap();
952
953        let cf = CapsFeatures::from(gstr!("memory:DMABuf"));
954        assert!(cf.contains(gstr!("memory:DMABuf")));
955
956        let cf = CapsFeatures::from([
957            gstr!("memory:DMABuf"),
958            gstr!("meta:GstVideoOverlayComposition"),
959        ]);
960
961        assert!(cf.contains(gstr!("memory:DMABuf")));
962        assert!(cf.contains("meta:GstVideoOverlayComposition"));
963        assert!(!cf.contains("memory:GLMemory"));
964
965        let cf = CapsFeatures::from_iter(vec![
966            gstr!("memory:DMABuf"),
967            gstr!("meta:GstVideoOverlayComposition"),
968        ]);
969
970        assert!(cf.contains(gstr!("memory:DMABuf")));
971        assert!(cf.contains("meta:GstVideoOverlayComposition"));
972        assert!(!cf.contains("memory:GLMemory"));
973
974        let mut cf = CapsFeatures::new_empty();
975        cf.extend([
976            gstr!("memory:DMABuf"),
977            gstr!("meta:GstVideoOverlayComposition"),
978        ]);
979
980        assert!(cf.contains(gstr!("memory:DMABuf")));
981        assert!(cf.contains("meta:GstVideoOverlayComposition"));
982        assert!(!cf.contains("memory:GLMemory"));
983    }
984
985    #[test]
986    fn trait_impls_from_id() {
987        crate::init().unwrap();
988
989        let cf = CapsFeatures::from(idstr!("memory:DMABuf"));
990        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
991
992        let cf = CapsFeatures::from([
993            idstr!("memory:DMABuf"),
994            idstr!("meta:GstVideoOverlayComposition"),
995        ]);
996
997        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
998        assert!(cf.contains("meta:GstVideoOverlayComposition"));
999        assert!(!cf.contains("memory:GLMemory"));
1000
1001        let cf = CapsFeatures::from_iter(vec![
1002            idstr!("memory:DMABuf"),
1003            idstr!("meta:GstVideoOverlayComposition"),
1004        ]);
1005
1006        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
1007        assert!(cf.contains("meta:GstVideoOverlayComposition"));
1008        assert!(!cf.contains("memory:GLMemory"));
1009
1010        let mut cf = CapsFeatures::new_empty();
1011        cf.extend([
1012            idstr!("memory:DMABuf"),
1013            idstr!("meta:GstVideoOverlayComposition"),
1014        ]);
1015
1016        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
1017        assert!(cf.contains("meta:GstVideoOverlayComposition"));
1018        assert!(!cf.contains("memory:GLMemory"));
1019    }
1020
1021    #[test]
1022    fn trait_impls_from_ref_id() {
1023        crate::init().unwrap();
1024
1025        let dma_buf = idstr!("memory:DMABuf");
1026        let overlay_comp = idstr!("meta:GstVideoOverlayComposition");
1027
1028        let cf = CapsFeatures::from(&dma_buf);
1029        assert!(cf.contains_by_id(&dma_buf));
1030
1031        let cf = CapsFeatures::from([&dma_buf, &overlay_comp]);
1032
1033        assert!(cf.contains_by_id(&dma_buf));
1034        assert!(cf.contains_by_id(&overlay_comp));
1035        assert!(!cf.contains("memory:GLMemory"));
1036
1037        let cf = CapsFeatures::from_iter(vec![&dma_buf, &overlay_comp]);
1038
1039        assert!(cf.contains_by_id(&dma_buf));
1040        assert!(cf.contains_by_id(&overlay_comp));
1041        assert!(!cf.contains("memory:GLMemory"));
1042
1043        let mut cf = CapsFeatures::new_empty();
1044        cf.extend([&dma_buf, &overlay_comp]);
1045
1046        assert!(cf.contains_by_id(dma_buf));
1047        assert!(cf.contains_by_id(overlay_comp));
1048        assert!(!cf.contains("memory:GLMemory"));
1049    }
1050}