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