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::{IdStr, ffi};
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        unsafe {
251            debug_assert!(!ptr.is_null());
252            let ptr = ffi::gst_caps_features_copy(ptr);
253            debug_assert!(!ptr.is_null());
254            CapsFeatures(ptr::NonNull::new_unchecked(ptr))
255        }
256    }
257}
258
259impl FromGlibPtrNone<*mut ffi::GstCapsFeatures> for CapsFeatures {
260    #[inline]
261    unsafe fn from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self {
262        unsafe {
263            debug_assert!(!ptr.is_null());
264            let ptr = ffi::gst_caps_features_copy(ptr);
265            debug_assert!(!ptr.is_null());
266            CapsFeatures(ptr::NonNull::new_unchecked(ptr))
267        }
268    }
269}
270
271impl FromGlibPtrFull<*const ffi::GstCapsFeatures> for CapsFeatures {
272    #[inline]
273    unsafe fn from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self {
274        unsafe {
275            debug_assert!(!ptr.is_null());
276            CapsFeatures(ptr::NonNull::new_unchecked(
277                ptr as *mut ffi::GstCapsFeatures,
278            ))
279        }
280    }
281}
282
283impl FromGlibPtrFull<*mut ffi::GstCapsFeatures> for CapsFeatures {
284    #[inline]
285    unsafe fn from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self {
286        unsafe {
287            debug_assert!(!ptr.is_null());
288            CapsFeatures(ptr::NonNull::new_unchecked(ptr))
289        }
290    }
291}
292
293impl glib::value::ValueType for CapsFeatures {
294    type Type = Self;
295}
296
297impl glib::value::ValueTypeOptional for CapsFeatures {}
298
299unsafe impl<'a> glib::value::FromValue<'a> for CapsFeatures {
300    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
301
302    unsafe fn from_value(value: &'a glib::Value) -> Self {
303        unsafe {
304            skip_assert_initialized!();
305            from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0)
306                as *mut ffi::GstCapsFeatures)
307        }
308    }
309}
310
311impl glib::value::ToValue for CapsFeatures {
312    fn to_value(&self) -> glib::Value {
313        let mut value = glib::Value::for_value_type::<Self>();
314        unsafe {
315            glib::gobject_ffi::g_value_set_boxed(
316                value.to_glib_none_mut().0,
317                ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(self).0 as *mut _,
318            )
319        }
320        value
321    }
322
323    fn value_type(&self) -> glib::Type {
324        Self::static_type()
325    }
326}
327
328impl glib::value::ToValueOptional for CapsFeatures {
329    fn to_value_optional(s: Option<&Self>) -> glib::Value {
330        skip_assert_initialized!();
331        let mut value = glib::Value::for_value_type::<Self>();
332        unsafe {
333            glib::gobject_ffi::g_value_set_boxed(
334                value.to_glib_none_mut().0,
335                ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(&s).0 as *mut _,
336            )
337        }
338        value
339    }
340}
341
342impl From<CapsFeatures> for glib::Value {
343    fn from(v: CapsFeatures) -> glib::Value {
344        skip_assert_initialized!();
345        let mut value = glib::Value::for_value_type::<CapsFeatures>();
346        unsafe {
347            glib::gobject_ffi::g_value_take_boxed(
348                value.to_glib_none_mut().0,
349                IntoGlibPtr::<*mut ffi::GstCapsFeatures>::into_glib_ptr(v) as *mut _,
350            )
351        }
352        value
353    }
354}
355
356impl GlibPtrDefault for CapsFeatures {
357    type GlibType = *mut ffi::GstCapsFeatures;
358}
359
360unsafe impl TransparentPtrType for CapsFeatures {}
361
362#[repr(transparent)]
363#[doc(alias = "GstCapsFeatures")]
364pub struct CapsFeaturesRef(ffi::GstCapsFeatures);
365
366impl CapsFeaturesRef {
367    #[inline]
368    pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef {
369        unsafe {
370            debug_assert!(!ptr.is_null());
371
372            &*(ptr as *mut CapsFeaturesRef)
373        }
374    }
375
376    #[inline]
377    pub unsafe fn from_glib_borrow_mut<'a>(
378        ptr: *mut ffi::GstCapsFeatures,
379    ) -> &'a mut CapsFeaturesRef {
380        unsafe {
381            debug_assert!(!ptr.is_null());
382
383            &mut *(ptr as *mut CapsFeaturesRef)
384        }
385    }
386
387    #[inline]
388    pub fn as_ptr(&self) -> *const ffi::GstCapsFeatures {
389        self as *const Self as *const ffi::GstCapsFeatures
390    }
391
392    #[inline]
393    pub fn as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures {
394        self as *const Self as *mut ffi::GstCapsFeatures
395    }
396
397    pub fn is_empty(&self) -> bool {
398        self.size() == 0 && !self.is_any()
399    }
400
401    #[doc(alias = "gst_caps_features_is_any")]
402    pub fn is_any(&self) -> bool {
403        unsafe { from_glib(ffi::gst_caps_features_is_any(self.as_ptr())) }
404    }
405
406    #[doc(alias = "gst_caps_features_contains")]
407    pub fn contains(&self, feature: impl IntoGStr) -> bool {
408        unsafe {
409            feature.run_with_gstr(|feature| {
410                from_glib(ffi::gst_caps_features_contains(
411                    self.as_ptr(),
412                    feature.as_ptr(),
413                ))
414            })
415        }
416    }
417
418    #[doc(alias = "gst_caps_features_contains_id_str")]
419    pub fn contains_by_id(&self, feature: impl AsRef<IdStr>) -> bool {
420        unsafe {
421            cfg_if! {
422                if #[cfg(feature = "v1_26")] {
423                    from_glib(ffi::gst_caps_features_contains_id_str(
424                        self.as_ptr(),
425                        feature.as_ref().as_ptr(),
426                    ))
427                } else {
428                    from_glib(ffi::gst_caps_features_contains(
429                        self.as_ptr(),
430                        feature.as_ref().as_gstr().as_ptr(),
431                    ))
432                }
433            }
434        }
435    }
436
437    #[deprecated = "use `contains_by_id()` instead"]
438    #[doc(alias = "gst_caps_features_contains_id")]
439    pub fn contains_quark(&self, feature: glib::Quark) -> bool {
440        unsafe {
441            from_glib(ffi::gst_caps_features_contains_id(
442                self.as_ptr(),
443                feature.into_glib(),
444            ))
445        }
446    }
447
448    #[doc(alias = "get_size")]
449    #[doc(alias = "gst_caps_features_get_size")]
450    pub fn size(&self) -> usize {
451        unsafe { ffi::gst_caps_features_get_size(self.as_ptr()) as usize }
452    }
453
454    #[doc(alias = "get_nth")]
455    #[doc(alias = "gst_caps_features_get_nth")]
456    pub fn nth(&self, idx: usize) -> Option<&glib::GStr> {
457        if idx >= self.size() {
458            return None;
459        }
460
461        unsafe {
462            let feature = ffi::gst_caps_features_get_nth(self.as_ptr(), idx as u32);
463            if feature.is_null() {
464                return None;
465            }
466
467            Some(glib::GStr::from_ptr(feature))
468        }
469    }
470
471    #[cfg(feature = "v1_26")]
472    #[doc(alias = "get_nth_by_id")]
473    #[doc(alias = "gst_caps_features_get_nth_id_str")]
474    pub fn nth_id(&self, idx: usize) -> Option<&IdStr> {
475        if idx >= self.size() {
476            return None;
477        }
478
479        unsafe {
480            let feature = ffi::gst_caps_features_get_nth_id_str(self.as_ptr(), idx as u32);
481            if feature.is_null() {
482                return None;
483            }
484
485            Some(&*(feature as *const IdStr))
486        }
487    }
488
489    #[deprecated = "use `nth_by_id()` instead"]
490    #[doc(alias = "gst_caps_features_get_nth_id")]
491    pub fn nth_quark(&self, idx: usize) -> Option<glib::Quark> {
492        if idx >= self.size() {
493            return None;
494        }
495
496        unsafe {
497            let feature = ffi::gst_caps_features_get_nth_id(self.as_ptr(), idx as u32);
498            Some(from_glib(feature))
499        }
500    }
501
502    #[doc(alias = "gst_caps_features_add")]
503    pub fn add(&mut self, feature: impl IntoGStr) {
504        unsafe {
505            feature.run_with_gstr(|feature| {
506                ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ptr())
507            })
508        }
509    }
510
511    #[doc(alias = "gst_caps_features_add_static_str")]
512    pub fn add_from_static(&mut self, feature: impl AsRef<glib::GStr> + 'static) {
513        unsafe {
514            cfg_if! {
515                if #[cfg(feature = "v1_26")] {
516                    ffi::gst_caps_features_add_static_str(self.as_mut_ptr(), feature.as_ref().as_ptr())
517                } else {
518                    ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ref().as_ptr())
519                }
520            }
521        }
522    }
523
524    #[doc(alias = "gst_caps_features_add_id_str")]
525    pub fn add_from_id(&mut self, feature: impl AsRef<IdStr>) {
526        unsafe {
527            cfg_if! {
528                if #[cfg(feature = "v1_26")] {
529                    ffi::gst_caps_features_add_id_str(self.as_mut_ptr(), feature.as_ref().as_ptr())
530                } else {
531                    ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ref().as_gstr().as_ptr())
532                }
533            }
534        }
535    }
536
537    #[doc(alias = "gst_caps_features_remove")]
538    pub fn remove(&mut self, feature: impl IntoGStr) {
539        unsafe {
540            feature.run_with_gstr(|feature| {
541                ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.as_ptr())
542            })
543        }
544    }
545
546    #[doc(alias = "gst_caps_features_remove_id_str")]
547    pub fn remove_by_id(&mut self, feature: impl AsRef<IdStr>) {
548        unsafe {
549            cfg_if! {
550                if #[cfg(feature = "v1_26")] {
551                    ffi::gst_caps_features_remove_id_str(self.as_mut_ptr(), feature.as_ref().as_ptr())
552                } else {
553                    ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.as_ref().as_gstr().as_ptr())
554                }
555            }
556        }
557    }
558
559    #[deprecated = "use `add_by_id()` instead"]
560    #[doc(alias = "gst_caps_features_add_id")]
561    pub fn add_from_quark(&mut self, feature: glib::Quark) {
562        unsafe { ffi::gst_caps_features_add_id(self.as_mut_ptr(), feature.into_glib()) }
563    }
564
565    #[deprecated = "use `remove_by_id()` instead"]
566    #[doc(alias = "gst_caps_features_remove_id")]
567    pub fn remove_by_quark(&mut self, feature: glib::Quark) {
568        unsafe { ffi::gst_caps_features_remove_id(self.as_mut_ptr(), feature.into_glib()) }
569    }
570
571    pub fn iter(&self) -> Iter<'_> {
572        Iter::new(self)
573    }
574
575    // This is not an equivalence relation with regards to ANY. Everything is equal to ANY
576    #[doc(alias = "gst_caps_features_is_equal")]
577    pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool {
578        unsafe {
579            from_glib(ffi::gst_caps_features_is_equal(
580                self.as_ptr(),
581                other.as_ptr(),
582            ))
583        }
584    }
585}
586
587impl glib::types::StaticType for CapsFeaturesRef {
588    #[inline]
589    fn static_type() -> glib::types::Type {
590        unsafe { from_glib(ffi::gst_structure_get_type()) }
591    }
592}
593
594impl<'a> std::iter::Extend<&'a str> for CapsFeaturesRef {
595    fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
596        iter.into_iter().for_each(|f| self.add(f));
597    }
598}
599
600impl<'a> std::iter::Extend<&'a glib::GStr> for CapsFeaturesRef {
601    fn extend<T: IntoIterator<Item = &'a glib::GStr>>(&mut self, iter: T) {
602        iter.into_iter().for_each(|f| self.add(f));
603    }
604}
605
606impl std::iter::Extend<String> for CapsFeaturesRef {
607    fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
608        iter.into_iter().for_each(|f| self.add(&f));
609    }
610}
611
612impl std::iter::Extend<glib::GString> for CapsFeaturesRef {
613    fn extend<T: IntoIterator<Item = glib::GString>>(&mut self, iter: T) {
614        iter.into_iter().for_each(|f| self.add(&f));
615    }
616}
617
618impl<Id: AsRef<IdStr>> std::iter::Extend<Id> for CapsFeaturesRef {
619    fn extend<T: IntoIterator<Item = Id>>(&mut self, iter: T) {
620        iter.into_iter().for_each(|f| self.add_from_id(f));
621    }
622}
623
624impl std::iter::Extend<glib::Quark> for CapsFeaturesRef {
625    #[allow(deprecated)]
626    fn extend<T: IntoIterator<Item = glib::Quark>>(&mut self, iter: T) {
627        iter.into_iter().for_each(|f| self.add_from_quark(f));
628    }
629}
630
631unsafe impl<'a> glib::value::FromValue<'a> for &'a CapsFeaturesRef {
632    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
633
634    unsafe fn from_value(value: &'a glib::Value) -> Self {
635        unsafe {
636            skip_assert_initialized!();
637            &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0)
638                as *const CapsFeaturesRef)
639        }
640    }
641}
642
643impl glib::value::ToValue for CapsFeaturesRef {
644    fn to_value(&self) -> glib::Value {
645        let mut value = glib::Value::for_value_type::<CapsFeatures>();
646        unsafe {
647            glib::gobject_ffi::g_value_set_boxed(
648                value.to_glib_none_mut().0,
649                self.as_mut_ptr() as *mut _,
650            )
651        }
652        value
653    }
654
655    fn value_type(&self) -> glib::Type {
656        Self::static_type()
657    }
658}
659
660impl glib::value::ToValueOptional for CapsFeaturesRef {
661    fn to_value_optional(s: Option<&Self>) -> glib::Value {
662        skip_assert_initialized!();
663        let mut value = glib::Value::for_value_type::<CapsFeatures>();
664        unsafe {
665            glib::gobject_ffi::g_value_set_boxed(
666                value.to_glib_none_mut().0,
667                s.map(|s| s.as_mut_ptr()).unwrap_or(ptr::null_mut()) as *mut _,
668            )
669        }
670        value
671    }
672}
673
674crate::utils::define_fixed_size_iter!(
675    Iter,
676    &'a CapsFeaturesRef,
677    &'a glib::GStr,
678    |collection: &CapsFeaturesRef| collection.size(),
679    |collection: &CapsFeaturesRef, idx: usize| unsafe {
680        let feature = ffi::gst_caps_features_get_nth(collection.as_ptr(), idx as u32);
681        glib::GStr::from_ptr(feature)
682    }
683);
684
685impl<'a> IntoIterator for &'a CapsFeaturesRef {
686    type IntoIter = Iter<'a>;
687    type Item = &'a glib::GStr;
688
689    fn into_iter(self) -> Self::IntoIter {
690        self.iter()
691    }
692}
693
694impl<'a> From<&'a str> for CapsFeatures {
695    fn from(value: &'a str) -> Self {
696        skip_assert_initialized!();
697        let mut features = CapsFeatures::new_empty();
698
699        features.add(value);
700
701        features
702    }
703}
704
705impl<'a> From<&'a glib::GStr> for CapsFeatures {
706    fn from(value: &'a glib::GStr) -> Self {
707        skip_assert_initialized!();
708        let mut features = CapsFeatures::new_empty();
709
710        features.add(value);
711
712        features
713    }
714}
715
716impl<Id: AsRef<IdStr>> From<Id> for CapsFeatures {
717    fn from(value: Id) -> Self {
718        skip_assert_initialized!();
719        let mut features = CapsFeatures::new_empty();
720
721        features.add_from_id(value);
722
723        features
724    }
725}
726
727impl From<glib::Quark> for CapsFeatures {
728    #[allow(deprecated)]
729    fn from(value: glib::Quark) -> Self {
730        skip_assert_initialized!();
731        let mut features = CapsFeatures::new_empty();
732
733        features.add_from_quark(value);
734
735        features
736    }
737}
738
739impl<'a, const N: usize> From<[&'a str; N]> for CapsFeatures {
740    fn from(value: [&'a str; N]) -> Self {
741        skip_assert_initialized!();
742        let mut features = CapsFeatures::new_empty();
743
744        value.into_iter().for_each(|f| features.add(f));
745
746        features
747    }
748}
749
750impl<'a, const N: usize> From<[&'a glib::GStr; N]> for CapsFeatures {
751    fn from(value: [&'a glib::GStr; N]) -> Self {
752        skip_assert_initialized!();
753        let mut features = CapsFeatures::new_empty();
754
755        value.into_iter().for_each(|f| features.add(f));
756
757        features
758    }
759}
760
761impl<const N: usize> From<[String; N]> for CapsFeatures {
762    fn from(value: [String; N]) -> Self {
763        skip_assert_initialized!();
764        let mut features = CapsFeatures::new_empty();
765
766        value.into_iter().for_each(|f| features.add(&f));
767
768        features
769    }
770}
771
772impl<const N: usize> From<[glib::GString; N]> for CapsFeatures {
773    fn from(value: [glib::GString; N]) -> Self {
774        skip_assert_initialized!();
775        let mut features = CapsFeatures::new_empty();
776
777        value.into_iter().for_each(|f| features.add(&f));
778
779        features
780    }
781}
782
783impl<const N: usize, Id: AsRef<IdStr>> From<[Id; N]> for CapsFeatures {
784    fn from(value: [Id; N]) -> Self {
785        skip_assert_initialized!();
786        let mut features = CapsFeatures::new_empty();
787
788        value.into_iter().for_each(|f| features.add_from_id(f));
789
790        features
791    }
792}
793
794impl<const N: usize> From<[glib::Quark; N]> for CapsFeatures {
795    #[allow(deprecated)]
796    fn from(value: [glib::Quark; N]) -> Self {
797        skip_assert_initialized!();
798        let mut features = CapsFeatures::new_empty();
799
800        value.into_iter().for_each(|f| features.add_from_quark(f));
801
802        features
803    }
804}
805
806impl<'a> std::iter::FromIterator<&'a str> for CapsFeatures {
807    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
808        skip_assert_initialized!();
809        let mut features = CapsFeatures::new_empty();
810
811        iter.into_iter().for_each(|f| features.add(f));
812
813        features
814    }
815}
816
817impl<'a> std::iter::FromIterator<&'a glib::GStr> for CapsFeatures {
818    fn from_iter<T: IntoIterator<Item = &'a glib::GStr>>(iter: T) -> Self {
819        assert_initialized_main_thread!();
820
821        let mut features = CapsFeatures::new_empty();
822
823        iter.into_iter().for_each(|f| features.add(f));
824
825        features
826    }
827}
828
829impl std::iter::FromIterator<String> for CapsFeatures {
830    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
831        skip_assert_initialized!();
832        let mut features = CapsFeatures::new_empty();
833
834        iter.into_iter().for_each(|f| features.add(&f));
835
836        features
837    }
838}
839
840impl std::iter::FromIterator<glib::GString> for CapsFeatures {
841    fn from_iter<T: IntoIterator<Item = glib::GString>>(iter: T) -> Self {
842        assert_initialized_main_thread!();
843
844        let mut features = CapsFeatures::new_empty();
845
846        iter.into_iter().for_each(|f| features.add(&f));
847
848        features
849    }
850}
851
852impl<Id: AsRef<IdStr>> std::iter::FromIterator<Id> for CapsFeatures {
853    #[allow(deprecated)]
854    fn from_iter<T: IntoIterator<Item = Id>>(iter: T) -> Self {
855        skip_assert_initialized!();
856        let mut features = CapsFeatures::new_empty();
857
858        iter.into_iter().for_each(|f| features.add_from_id(f));
859
860        features
861    }
862}
863
864impl std::iter::FromIterator<glib::Quark> for CapsFeatures {
865    #[allow(deprecated)]
866    fn from_iter<T: IntoIterator<Item = glib::Quark>>(iter: T) -> Self {
867        skip_assert_initialized!();
868        let mut features = CapsFeatures::new_empty();
869
870        iter.into_iter().for_each(|f| features.add_from_quark(f));
871
872        features
873    }
874}
875
876impl fmt::Debug for CapsFeaturesRef {
877    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
878        f.debug_tuple("CapsFeatures")
879            .field(&self.to_string())
880            .finish()
881    }
882}
883
884impl fmt::Display for CapsFeaturesRef {
885    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
886        let s = unsafe {
887            glib::GString::from_glib_full(ffi::gst_caps_features_to_string(self.as_ptr()))
888        };
889        f.write_str(&s)
890    }
891}
892
893impl ToOwned for CapsFeaturesRef {
894    type Owned = CapsFeatures;
895
896    #[inline]
897    fn to_owned(&self) -> CapsFeatures {
898        unsafe { from_glib_full(ffi::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) }
899    }
900}
901
902impl std::hash::Hash for CapsFeaturesRef {
903    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
904        use std::hash::{DefaultHasher, Hasher};
905
906        // re-implement gst_hash_caps_features so the hashing is not depending on the features order.
907        if self.is_any() {
908            "ANY".hash(state);
909        } else if self.is_empty() {
910            "EMPTY".hash(state);
911        } else {
912            let mut features_hash = 0;
913            for f in self.iter() {
914                let mut field_hasher = DefaultHasher::new();
915                f.hash(&mut field_hasher);
916
917                features_hash ^= field_hasher.finish();
918            }
919            features_hash.hash(state);
920        }
921    }
922}
923
924impl std::hash::Hash for CapsFeatures {
925    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
926        self.as_ref().hash(state);
927    }
928}
929
930unsafe impl Sync for CapsFeaturesRef {}
931unsafe impl Send for CapsFeaturesRef {}
932
933pub static CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: &glib::GStr =
934    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) };
935pub static CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: LazyLock<CapsFeatures> =
936    LazyLock::new(|| CapsFeatures::new([CAPS_FEATURE_MEMORY_SYSTEM_MEMORY]));
937
938#[cfg(test)]
939mod tests {
940    use super::*;
941    use glib::gstr;
942
943    #[test]
944    fn test_from_value_optional() {
945        use glib::value::ToValue;
946
947        crate::init().unwrap();
948
949        let a = None::<CapsFeatures>.to_value();
950        assert!(a.get::<Option<CapsFeatures>>().unwrap().is_none());
951        let b = glib::value::Value::from(&CapsFeatures::new_empty());
952        assert!(b.get::<Option<CapsFeatures>>().unwrap().is_some());
953    }
954
955    #[test]
956    fn trait_impls() {
957        crate::init().unwrap();
958
959        let cf = CapsFeatures::from(gstr!("memory:DMABuf"));
960        assert!(cf.contains(gstr!("memory:DMABuf")));
961
962        let cf = CapsFeatures::from([
963            gstr!("memory:DMABuf"),
964            gstr!("meta:GstVideoOverlayComposition"),
965        ]);
966
967        assert!(cf.contains(gstr!("memory:DMABuf")));
968        assert!(cf.contains("meta:GstVideoOverlayComposition"));
969        assert!(!cf.contains("memory:GLMemory"));
970
971        let cf = CapsFeatures::from_iter(vec![
972            gstr!("memory:DMABuf"),
973            gstr!("meta:GstVideoOverlayComposition"),
974        ]);
975
976        assert!(cf.contains(gstr!("memory:DMABuf")));
977        assert!(cf.contains("meta:GstVideoOverlayComposition"));
978        assert!(!cf.contains("memory:GLMemory"));
979
980        let mut cf = CapsFeatures::new_empty();
981        cf.extend([
982            gstr!("memory:DMABuf"),
983            gstr!("meta:GstVideoOverlayComposition"),
984        ]);
985
986        assert!(cf.contains(gstr!("memory:DMABuf")));
987        assert!(cf.contains("meta:GstVideoOverlayComposition"));
988        assert!(!cf.contains("memory:GLMemory"));
989    }
990
991    #[test]
992    fn trait_impls_from_id() {
993        crate::init().unwrap();
994
995        let cf = CapsFeatures::from(idstr!("memory:DMABuf"));
996        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
997
998        let cf = CapsFeatures::from([
999            idstr!("memory:DMABuf"),
1000            idstr!("meta:GstVideoOverlayComposition"),
1001        ]);
1002
1003        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
1004        assert!(cf.contains("meta:GstVideoOverlayComposition"));
1005        assert!(!cf.contains("memory:GLMemory"));
1006
1007        let cf = CapsFeatures::from_iter(vec![
1008            idstr!("memory:DMABuf"),
1009            idstr!("meta:GstVideoOverlayComposition"),
1010        ]);
1011
1012        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
1013        assert!(cf.contains("meta:GstVideoOverlayComposition"));
1014        assert!(!cf.contains("memory:GLMemory"));
1015
1016        let mut cf = CapsFeatures::new_empty();
1017        cf.extend([
1018            idstr!("memory:DMABuf"),
1019            idstr!("meta:GstVideoOverlayComposition"),
1020        ]);
1021
1022        assert!(cf.contains_by_id(idstr!("memory:DMABuf")));
1023        assert!(cf.contains("meta:GstVideoOverlayComposition"));
1024        assert!(!cf.contains("memory:GLMemory"));
1025    }
1026
1027    #[test]
1028    fn trait_impls_from_ref_id() {
1029        crate::init().unwrap();
1030
1031        let dma_buf = idstr!("memory:DMABuf");
1032        let overlay_comp = idstr!("meta:GstVideoOverlayComposition");
1033
1034        let cf = CapsFeatures::from(&dma_buf);
1035        assert!(cf.contains_by_id(&dma_buf));
1036
1037        let cf = CapsFeatures::from([&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 cf = CapsFeatures::from_iter(vec![&dma_buf, &overlay_comp]);
1044
1045        assert!(cf.contains_by_id(&dma_buf));
1046        assert!(cf.contains_by_id(&overlay_comp));
1047        assert!(!cf.contains("memory:GLMemory"));
1048
1049        let mut cf = CapsFeatures::new_empty();
1050        cf.extend([&dma_buf, &overlay_comp]);
1051
1052        assert!(cf.contains_by_id(dma_buf));
1053        assert!(cf.contains_by_id(overlay_comp));
1054        assert!(!cf.contains("memory:GLMemory"));
1055    }
1056
1057    #[test]
1058    fn test_hash() {
1059        crate::init().unwrap();
1060
1061        use std::hash::BuildHasher;
1062        let bh = std::hash::RandomState::new();
1063
1064        let any = CapsFeatures::new_any();
1065        let empty = CapsFeatures::new_empty();
1066        assert_eq!(bh.hash_one(&any), bh.hash_one(&any));
1067        assert_eq!(bh.hash_one(&empty), bh.hash_one(&empty));
1068        assert_ne!(bh.hash_one(&any), bh.hash_one(&empty));
1069
1070        // Different names
1071        let cf1 = CapsFeatures::from(gstr!("memory:DMABuf"));
1072        let cf2 = CapsFeatures::from(gstr!("memory:GLMemory"));
1073        assert_eq!(bh.hash_one(&cf1), bh.hash_one(&cf1));
1074        assert_eq!(bh.hash_one(&cf2), bh.hash_one(&cf2));
1075        assert_ne!(bh.hash_one(&cf1), bh.hash_one(&cf2));
1076
1077        // Same features, different order
1078        let cf1 = CapsFeatures::from([
1079            gstr!("memory:DMABuf"),
1080            gstr!("meta:GstVideoOverlayComposition"),
1081        ]);
1082        let cf2 = CapsFeatures::from([
1083            gstr!("meta:GstVideoOverlayComposition"),
1084            gstr!("memory:DMABuf"),
1085        ]);
1086        assert_eq!(bh.hash_one(&cf1), bh.hash_one(&cf1));
1087        assert_eq!(bh.hash_one(&cf2), bh.hash_one(&cf2));
1088        assert_eq!(bh.hash_one(&cf1), bh.hash_one(&cf2));
1089    }
1090}