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