gstreamer/
caps.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, ptr, str};
4
5use glib::{
6    prelude::*,
7    translate::*,
8    value::{SendValue, ToSendValue},
9};
10
11use crate::{caps_features::*, ffi, structure::*, CapsIntersectMode};
12
13mini_object_wrapper!(Caps, CapsRef, ffi::GstCaps, || { ffi::gst_caps_get_type() });
14
15impl Caps {
16    #[doc(alias = "gst_caps_new_simple")]
17    pub fn builder(name: impl IntoGStr) -> Builder<NoFeature> {
18        assert_initialized_main_thread!();
19        Builder::new(name)
20    }
21
22    #[doc(alias = "gst_caps_new_full")]
23    pub fn builder_full() -> BuilderFull<SomeFeatures> {
24        assert_initialized_main_thread!();
25        BuilderFull::new()
26    }
27
28    #[doc(alias = "gst_caps_new_full")]
29    pub fn builder_full_with_features(features: CapsFeatures) -> BuilderFull<SomeFeatures> {
30        assert_initialized_main_thread!();
31        BuilderFull::with_features(features)
32    }
33
34    #[doc(alias = "gst_caps_new_full")]
35    pub fn builder_full_with_any_features() -> BuilderFull<AnyFeatures> {
36        assert_initialized_main_thread!();
37        BuilderFull::with_any_features()
38    }
39
40    #[doc(alias = "gst_caps_new_empty")]
41    pub fn new_empty() -> Self {
42        assert_initialized_main_thread!();
43        unsafe { from_glib_full(ffi::gst_caps_new_empty()) }
44    }
45
46    #[doc(alias = "gst_caps_new_any")]
47    pub fn new_any() -> Self {
48        assert_initialized_main_thread!();
49        unsafe { from_glib_full(ffi::gst_caps_new_any()) }
50    }
51
52    #[doc(alias = "gst_caps_new_empty_simple")]
53    pub fn new_empty_simple(name: impl IntoGStr) -> Self {
54        skip_assert_initialized!();
55        let mut caps = Caps::new_empty();
56
57        let structure = Structure::new_empty(name);
58        caps.get_mut().unwrap().append_structure(structure);
59
60        caps
61    }
62
63    #[doc(alias = "gst_caps_fixate")]
64    pub fn fixate(&mut self) {
65        unsafe {
66            // See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/388
67            assert!(!self.is_any());
68            let ptr = if self.is_empty() {
69                ffi::gst_caps_new_empty()
70            } else {
71                ffi::gst_caps_fixate(self.as_mut_ptr())
72            };
73            self.replace_ptr(ptr);
74        }
75    }
76
77    #[doc(alias = "gst_caps_merge")]
78    pub fn merge(&mut self, other: Self) {
79        unsafe {
80            let ptr = ffi::gst_caps_merge(self.as_mut_ptr(), other.into_glib_ptr());
81            self.replace_ptr(ptr);
82        }
83    }
84
85    #[doc(alias = "gst_caps_merge_structure")]
86    pub fn merge_structure(&mut self, structure: Structure) {
87        unsafe {
88            let ptr = ffi::gst_caps_merge_structure(self.as_mut_ptr(), structure.into_glib_ptr());
89            self.replace_ptr(ptr);
90        }
91    }
92
93    #[doc(alias = "gst_caps_merge_structure_full")]
94    pub fn merge_structure_full(&mut self, structure: Structure, features: Option<CapsFeatures>) {
95        unsafe {
96            let ptr = ffi::gst_caps_merge_structure_full(
97                self.as_mut_ptr(),
98                structure.into_glib_ptr(),
99                features
100                    .map(|f| f.into_glib_ptr())
101                    .unwrap_or(ptr::null_mut()),
102            );
103            self.replace_ptr(ptr);
104        }
105    }
106
107    #[doc(alias = "gst_caps_normalize")]
108    pub fn normalize(&mut self) {
109        unsafe {
110            let ptr = ffi::gst_caps_normalize(self.as_mut_ptr());
111            self.replace_ptr(ptr);
112        }
113    }
114
115    #[doc(alias = "gst_caps_simplify")]
116    pub fn simplify(&mut self) {
117        unsafe {
118            let ptr = ffi::gst_caps_simplify(self.as_mut_ptr());
119            self.replace_ptr(ptr);
120        }
121    }
122
123    #[doc(alias = "gst_caps_truncate")]
124    pub fn truncate(&mut self) {
125        unsafe {
126            let ptr = ffi::gst_caps_truncate(self.as_mut_ptr());
127            self.replace_ptr(ptr);
128        }
129    }
130}
131
132impl str::FromStr for Caps {
133    type Err = glib::BoolError;
134
135    #[doc(alias = "gst_caps_from_string")]
136    fn from_str(s: &str) -> Result<Self, Self::Err> {
137        assert_initialized_main_thread!();
138        unsafe {
139            s.run_with_gstr(|s| {
140                Option::<_>::from_glib_full(ffi::gst_caps_from_string(s.as_ptr()))
141                    .ok_or_else(|| glib::bool_error!("Failed to parse caps from string"))
142            })
143        }
144    }
145}
146
147impl From<Structure> for Caps {
148    fn from(v: Structure) -> Caps {
149        skip_assert_initialized!();
150        let mut caps = Caps::new_empty();
151
152        {
153            let caps = caps.get_mut().unwrap();
154            caps.append_structure(v);
155        }
156
157        caps
158    }
159}
160
161impl<const N: usize> From<[Structure; N]> for Caps {
162    fn from(v: [Structure; N]) -> Caps {
163        skip_assert_initialized!();
164        let mut caps = Caps::new_empty();
165
166        {
167            let caps = caps.get_mut().unwrap();
168            v.into_iter().for_each(|s| caps.append_structure(s));
169        }
170
171        caps
172    }
173}
174
175impl From<(Structure, CapsFeatures)> for Caps {
176    fn from(v: (Structure, CapsFeatures)) -> Caps {
177        skip_assert_initialized!();
178        let mut caps = Caps::new_empty();
179
180        {
181            let caps = caps.get_mut().unwrap();
182            caps.append_structure_full(v.0, Some(v.1));
183        }
184
185        caps
186    }
187}
188
189impl<const N: usize> From<[(Structure, CapsFeatures); N]> for Caps {
190    fn from(v: [(Structure, CapsFeatures); N]) -> Caps {
191        skip_assert_initialized!();
192        let mut caps = Caps::new_empty();
193
194        {
195            let caps = caps.get_mut().unwrap();
196            v.into_iter()
197                .for_each(|s| caps.append_structure_full(s.0, Some(s.1)));
198        }
199
200        caps
201    }
202}
203
204impl<const N: usize> From<[(Structure, Option<CapsFeatures>); N]> for Caps {
205    fn from(v: [(Structure, Option<CapsFeatures>); N]) -> Caps {
206        skip_assert_initialized!();
207        let mut caps = Caps::new_empty();
208
209        {
210            let caps = caps.get_mut().unwrap();
211            v.into_iter()
212                .for_each(|s| caps.append_structure_full(s.0, s.1));
213        }
214
215        caps
216    }
217}
218
219impl std::iter::FromIterator<Structure> for Caps {
220    fn from_iter<T: IntoIterator<Item = Structure>>(iter: T) -> Self {
221        skip_assert_initialized!();
222        let mut caps = Caps::new_empty();
223
224        {
225            let caps = caps.get_mut().unwrap();
226            iter.into_iter().for_each(|s| caps.append_structure(s));
227        }
228
229        caps
230    }
231}
232
233impl std::iter::FromIterator<(Structure, CapsFeatures)> for Caps {
234    fn from_iter<T: IntoIterator<Item = (Structure, CapsFeatures)>>(iter: T) -> Self {
235        skip_assert_initialized!();
236        let mut caps = Caps::new_empty();
237
238        {
239            let caps = caps.get_mut().unwrap();
240            iter.into_iter()
241                .for_each(|(s, f)| caps.append_structure_full(s, Some(f)));
242        }
243
244        caps
245    }
246}
247
248impl std::iter::FromIterator<(Structure, Option<CapsFeatures>)> for Caps {
249    fn from_iter<T: IntoIterator<Item = (Structure, Option<CapsFeatures>)>>(iter: T) -> Self {
250        skip_assert_initialized!();
251        let mut caps = Caps::new_empty();
252
253        {
254            let caps = caps.get_mut().unwrap();
255            iter.into_iter()
256                .for_each(|(s, f)| caps.append_structure_full(s, f));
257        }
258
259        caps
260    }
261}
262
263impl std::iter::FromIterator<Caps> for Caps {
264    fn from_iter<T: IntoIterator<Item = Caps>>(iter: T) -> Self {
265        skip_assert_initialized!();
266        let mut caps = Caps::new_empty();
267
268        {
269            let caps = caps.get_mut().unwrap();
270            iter.into_iter()
271                .for_each(|other_caps| caps.append(other_caps));
272        }
273
274        caps
275    }
276}
277
278impl std::iter::Extend<Structure> for CapsRef {
279    fn extend<T: IntoIterator<Item = Structure>>(&mut self, iter: T) {
280        iter.into_iter().for_each(|s| self.append_structure(s));
281    }
282}
283
284impl std::iter::Extend<(Structure, CapsFeatures)> for CapsRef {
285    fn extend<T: IntoIterator<Item = (Structure, CapsFeatures)>>(&mut self, iter: T) {
286        iter.into_iter()
287            .for_each(|(s, f)| self.append_structure_full(s, Some(f)));
288    }
289}
290
291impl std::iter::Extend<(Structure, Option<CapsFeatures>)> for CapsRef {
292    fn extend<T: IntoIterator<Item = (Structure, Option<CapsFeatures>)>>(&mut self, iter: T) {
293        iter.into_iter()
294            .for_each(|(s, f)| self.append_structure_full(s, f));
295    }
296}
297
298impl std::iter::Extend<Caps> for CapsRef {
299    fn extend<T: IntoIterator<Item = Caps>>(&mut self, iter: T) {
300        iter.into_iter().for_each(|caps| self.append(caps));
301    }
302}
303
304impl CapsRef {
305    // rustdoc-stripper-ignore-next
306    /// Sets field `name` to the given value `value`.
307    ///
308    /// Overrides any default or previously defined value for `name`.
309    #[doc(alias = "gst_caps_set_value")]
310    #[doc(alias = "gst_caps_set_simple")]
311    pub fn set(&mut self, name: impl IntoGStr, value: impl ToSendValue + Sync) {
312        let value = value.to_send_value();
313        self.set_value(name, value);
314    }
315
316    // rustdoc-stripper-ignore-next
317    /// Sets field `name` to the given value if the `predicate` evaluates to `true`.
318    ///
319    /// This has no effect if the `predicate` evaluates to `false`,
320    /// i.e. default or previous value for `name` is kept.
321    #[doc(alias = "gst_caps_set_value")]
322    #[doc(alias = "gst_caps_set_simple")]
323    pub fn set_if(&mut self, name: impl IntoGStr, value: impl ToSendValue + Sync, predicate: bool) {
324        if predicate {
325            self.set(name, value);
326        }
327    }
328
329    // rustdoc-stripper-ignore-next
330    /// Sets field `name` to the given inner value if `value` is `Some`.
331    ///
332    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
333    #[doc(alias = "gst_caps_set_value")]
334    #[doc(alias = "gst_caps_set_simple")]
335    pub fn set_if_some(&mut self, name: impl IntoGStr, value: Option<impl ToSendValue + Sync>) {
336        if let Some(value) = value {
337            self.set(name, value);
338        }
339    }
340
341    // rustdoc-stripper-ignore-next
342    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s.
343    ///
344    /// Overrides any default or previously defined value for `name`.
345    #[inline]
346    pub fn set_from_iter<V: ValueType + ToSendValue + FromIterator<SendValue> + Sync>(
347        &mut self,
348        name: impl IntoGStr,
349        iter: impl IntoIterator<Item = impl ToSendValue>,
350    ) {
351        let iter = iter.into_iter().map(|item| item.to_send_value());
352        self.set(name, V::from_iter(iter));
353    }
354
355    // rustdoc-stripper-ignore-next
356    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s,
357    /// if `iter` is not empty.
358    ///
359    /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged.
360    #[inline]
361    pub fn set_if_not_empty<V: ValueType + ToSendValue + FromIterator<SendValue> + Sync>(
362        &mut self,
363        name: impl IntoGStr,
364        iter: impl IntoIterator<Item = impl ToSendValue>,
365    ) {
366        let mut iter = iter.into_iter().peekable();
367        if iter.peek().is_some() {
368            let iter = iter.map(|item| item.to_send_value());
369            self.set(name, V::from_iter(iter));
370        }
371    }
372
373    // rustdoc-stripper-ignore-next
374    /// Sets field `name` to the given value `value`.
375    ///
376    /// Overrides any default or previously defined value for `name`.
377    #[doc(alias = "gst_caps_set_value")]
378    pub fn set_value(&mut self, name: impl IntoGStr, value: glib::SendValue) {
379        unsafe {
380            name.run_with_gstr(|name| {
381                ffi::gst_caps_set_value(self.as_mut_ptr(), name.as_ptr(), value.to_glib_none().0)
382            });
383        }
384    }
385
386    // rustdoc-stripper-ignore-next
387    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
388    ///
389    /// This has no effect if the `predicate` evaluates to `false`,
390    /// i.e. default or previous value for `name` is kept.
391    #[doc(alias = "gst_caps_set_value")]
392    pub fn set_value_if(&mut self, name: impl IntoGStr, value: SendValue, predicate: bool) {
393        if predicate {
394            self.set_value(name, value);
395        }
396    }
397
398    // rustdoc-stripper-ignore-next
399    /// Sets field `name` to the given inner value if `value` is `Some`.
400    ///
401    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
402    #[doc(alias = "gst_caps_set_value")]
403    pub fn set_value_if_some(&mut self, name: impl IntoGStr, value: Option<SendValue>) {
404        if let Some(value) = value {
405            self.set_value(name, value);
406        }
407    }
408
409    #[doc(alias = "get_structure")]
410    #[doc(alias = "gst_caps_get_structure")]
411    pub fn structure(&self, idx: usize) -> Option<&StructureRef> {
412        if idx >= self.size() {
413            return None;
414        }
415
416        unsafe {
417            let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx as u32);
418            if structure.is_null() {
419                return None;
420            }
421
422            Some(StructureRef::from_glib_borrow(structure))
423        }
424    }
425
426    #[doc(alias = "get_mut_structure")]
427    #[doc(alias = "gst_caps_get_structure")]
428    pub fn structure_mut(&mut self, idx: usize) -> Option<&mut StructureRef> {
429        if idx >= self.size() {
430            return None;
431        }
432
433        unsafe {
434            let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx as u32);
435            if structure.is_null() {
436                return None;
437            }
438
439            Some(StructureRef::from_glib_borrow_mut(structure))
440        }
441    }
442
443    #[doc(alias = "get_features")]
444    #[doc(alias = "gst_caps_get_features")]
445    pub fn features(&self, idx: usize) -> Option<&CapsFeaturesRef> {
446        if idx >= self.size() {
447            return None;
448        }
449
450        unsafe {
451            let features = ffi::gst_caps_get_features(self.as_ptr(), idx as u32);
452            Some(CapsFeaturesRef::from_glib_borrow(features))
453        }
454    }
455
456    #[doc(alias = "get_mut_features")]
457    #[doc(alias = "gst_caps_get_features")]
458    pub fn features_mut(&mut self, idx: usize) -> Option<&mut CapsFeaturesRef> {
459        if idx >= self.size() {
460            return None;
461        }
462
463        unsafe {
464            let features = ffi::gst_caps_get_features(self.as_ptr(), idx as u32);
465            Some(CapsFeaturesRef::from_glib_borrow_mut(features))
466        }
467    }
468
469    #[doc(alias = "gst_caps_set_features")]
470    pub fn set_features(&mut self, idx: usize, features: Option<CapsFeatures>) {
471        assert!(idx < self.size());
472
473        unsafe {
474            ffi::gst_caps_set_features(
475                self.as_mut_ptr(),
476                idx as u32,
477                features
478                    .map(|f| f.into_glib_ptr())
479                    .unwrap_or(ptr::null_mut()),
480            )
481        }
482    }
483
484    #[cfg(feature = "v1_16")]
485    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
486    #[doc(alias = "gst_caps_set_features_simple")]
487    pub fn set_features_simple(&mut self, features: Option<CapsFeatures>) {
488        unsafe {
489            ffi::gst_caps_set_features_simple(
490                self.as_mut_ptr(),
491                features
492                    .map(|f| f.into_glib_ptr())
493                    .unwrap_or(ptr::null_mut()),
494            )
495        }
496    }
497
498    #[doc(alias = "get_size")]
499    #[doc(alias = "gst_caps_get_size")]
500    pub fn size(&self) -> usize {
501        unsafe { ffi::gst_caps_get_size(self.as_ptr()) as usize }
502    }
503
504    pub fn len(&self) -> usize {
505        self.size()
506    }
507
508    pub fn iter(&self) -> Iter {
509        Iter::new(self)
510    }
511
512    pub fn iter_mut(&mut self) -> IterMut {
513        IterMut::new(self)
514    }
515
516    pub fn iter_with_features(&self) -> IterFeatures {
517        IterFeatures::new(self)
518    }
519
520    pub fn iter_with_features_mut(&mut self) -> IterFeaturesMut {
521        IterFeaturesMut::new(self)
522    }
523
524    #[doc(alias = "gst_caps_append_structure")]
525    pub fn append_structure(&mut self, structure: Structure) {
526        unsafe { ffi::gst_caps_append_structure(self.as_mut_ptr(), structure.into_glib_ptr()) }
527    }
528
529    #[doc(alias = "gst_caps_append_structure_full")]
530    pub fn append_structure_full(&mut self, structure: Structure, features: Option<CapsFeatures>) {
531        unsafe {
532            ffi::gst_caps_append_structure_full(
533                self.as_mut_ptr(),
534                structure.into_glib_ptr(),
535                features
536                    .map(|f| f.into_glib_ptr())
537                    .unwrap_or(ptr::null_mut()),
538            )
539        }
540    }
541
542    #[doc(alias = "gst_caps_remove_structure")]
543    pub fn remove_structure(&mut self, idx: usize) {
544        assert!(idx < self.size());
545
546        unsafe { ffi::gst_caps_remove_structure(self.as_mut_ptr(), idx as u32) }
547    }
548
549    #[doc(alias = "gst_caps_append")]
550    pub fn append(&mut self, other: Caps) {
551        unsafe { ffi::gst_caps_append(self.as_mut_ptr(), other.into_glib_ptr()) }
552    }
553
554    #[doc(alias = "gst_caps_can_intersect")]
555    pub fn can_intersect(&self, other: &Self) -> bool {
556        unsafe { from_glib(ffi::gst_caps_can_intersect(self.as_ptr(), other.as_ptr())) }
557    }
558
559    #[doc(alias = "gst_caps_intersect")]
560    pub fn intersect(&self, other: &Self) -> Caps {
561        unsafe {
562            from_glib_full(ffi::gst_caps_intersect(
563                self.as_mut_ptr(),
564                other.as_mut_ptr(),
565            ))
566        }
567    }
568
569    #[doc(alias = "gst_caps_intersect_full")]
570    pub fn intersect_with_mode(&self, other: &Self, mode: CapsIntersectMode) -> Caps {
571        unsafe {
572            from_glib_full(ffi::gst_caps_intersect_full(
573                self.as_mut_ptr(),
574                other.as_mut_ptr(),
575                mode.into_glib(),
576            ))
577        }
578    }
579
580    #[doc(alias = "gst_caps_is_always_compatible")]
581    pub fn is_always_compatible(&self, other: &Self) -> bool {
582        unsafe {
583            from_glib(ffi::gst_caps_is_always_compatible(
584                self.as_ptr(),
585                other.as_ptr(),
586            ))
587        }
588    }
589
590    #[doc(alias = "gst_caps_is_any")]
591    pub fn is_any(&self) -> bool {
592        unsafe { from_glib(ffi::gst_caps_is_any(self.as_ptr())) }
593    }
594
595    #[doc(alias = "gst_caps_is_empty")]
596    pub fn is_empty(&self) -> bool {
597        unsafe { from_glib(ffi::gst_caps_is_empty(self.as_ptr())) }
598    }
599
600    #[doc(alias = "gst_caps_is_fixed")]
601    pub fn is_fixed(&self) -> bool {
602        unsafe { from_glib(ffi::gst_caps_is_fixed(self.as_ptr())) }
603    }
604
605    #[doc(alias = "gst_caps_is_equal_fixed")]
606    pub fn is_equal_fixed(&self, other: &Self) -> bool {
607        unsafe { from_glib(ffi::gst_caps_is_equal_fixed(self.as_ptr(), other.as_ptr())) }
608    }
609
610    #[doc(alias = "gst_caps_is_strictly_equal")]
611    pub fn is_strictly_equal(&self, other: &Self) -> bool {
612        unsafe {
613            from_glib(ffi::gst_caps_is_strictly_equal(
614                self.as_ptr(),
615                other.as_ptr(),
616            ))
617        }
618    }
619
620    #[doc(alias = "gst_caps_is_subset")]
621    pub fn is_subset(&self, superset: &Self) -> bool {
622        unsafe { from_glib(ffi::gst_caps_is_subset(self.as_ptr(), superset.as_ptr())) }
623    }
624
625    #[doc(alias = "gst_caps_is_subset_structure")]
626    pub fn is_subset_structure(&self, structure: &StructureRef) -> bool {
627        unsafe {
628            from_glib(ffi::gst_caps_is_subset_structure(
629                self.as_ptr(),
630                structure.as_ptr(),
631            ))
632        }
633    }
634
635    #[doc(alias = "gst_caps_is_subset_structure_full")]
636    pub fn is_subset_structure_full(
637        &self,
638        structure: &StructureRef,
639        features: Option<&CapsFeaturesRef>,
640    ) -> bool {
641        unsafe {
642            from_glib(ffi::gst_caps_is_subset_structure_full(
643                self.as_ptr(),
644                structure.as_ptr(),
645                features.map(|f| f.as_ptr()).unwrap_or(ptr::null()),
646            ))
647        }
648    }
649
650    #[doc(alias = "gst_caps_subtract")]
651    pub fn subtract(&self, other: &Self) -> Caps {
652        unsafe {
653            from_glib_full(ffi::gst_caps_subtract(
654                self.as_mut_ptr(),
655                other.as_mut_ptr(),
656            ))
657        }
658    }
659
660    #[cfg(feature = "v1_20")]
661    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
662    #[doc(alias = "gst_caps_serialize")]
663    pub fn serialize(&self, flags: crate::SerializeFlags) -> glib::GString {
664        unsafe { from_glib_full(ffi::gst_caps_serialize(&self.0, flags.into_glib())) }
665    }
666
667    #[doc(alias = "gst_caps_foreach")]
668    pub fn foreach<F: FnMut(&CapsFeaturesRef, &StructureRef) -> std::ops::ControlFlow<()>>(
669        &self,
670        mut func: F,
671    ) -> bool {
672        unsafe {
673            unsafe extern "C" fn trampoline<
674                F: FnMut(&CapsFeaturesRef, &StructureRef) -> std::ops::ControlFlow<()>,
675            >(
676                features: *mut ffi::GstCapsFeatures,
677                s: *mut ffi::GstStructure,
678                user_data: glib::ffi::gpointer,
679            ) -> glib::ffi::gboolean {
680                let func = &mut *(user_data as *mut F);
681                let res = func(
682                    CapsFeaturesRef::from_glib_borrow(features),
683                    StructureRef::from_glib_borrow(s),
684                );
685
686                matches!(res, std::ops::ControlFlow::Continue(_)).into_glib()
687            }
688            let func = &mut func as *mut F;
689            from_glib(ffi::gst_caps_foreach(
690                self.as_ptr(),
691                Some(trampoline::<F>),
692                func as glib::ffi::gpointer,
693            ))
694        }
695    }
696
697    #[doc(alias = "gst_caps_map_in_place")]
698    pub fn map_in_place<
699        F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> std::ops::ControlFlow<()>,
700    >(
701        &mut self,
702        mut func: F,
703    ) -> bool {
704        unsafe {
705            unsafe extern "C" fn trampoline<
706                F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> std::ops::ControlFlow<()>,
707            >(
708                features: *mut ffi::GstCapsFeatures,
709                s: *mut ffi::GstStructure,
710                user_data: glib::ffi::gpointer,
711            ) -> glib::ffi::gboolean {
712                let func = &mut *(user_data as *mut F);
713                let res = func(
714                    CapsFeaturesRef::from_glib_borrow_mut(features),
715                    StructureRef::from_glib_borrow_mut(s),
716                );
717
718                matches!(res, std::ops::ControlFlow::Continue(_)).into_glib()
719            }
720            let func = &mut func as *mut F;
721            from_glib(ffi::gst_caps_map_in_place(
722                self.as_mut_ptr(),
723                Some(trampoline::<F>),
724                func as glib::ffi::gpointer,
725            ))
726        }
727    }
728
729    #[doc(alias = "gst_caps_filter_and_map_in_place")]
730    pub fn filter_map_in_place<
731        F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> CapsFilterMapAction,
732    >(
733        &mut self,
734        mut func: F,
735    ) {
736        unsafe {
737            unsafe extern "C" fn trampoline<
738                F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> CapsFilterMapAction,
739            >(
740                features: *mut ffi::GstCapsFeatures,
741                s: *mut ffi::GstStructure,
742                user_data: glib::ffi::gpointer,
743            ) -> glib::ffi::gboolean {
744                let func = &mut *(user_data as *mut F);
745
746                let res = func(
747                    CapsFeaturesRef::from_glib_borrow_mut(features),
748                    StructureRef::from_glib_borrow_mut(s),
749                );
750
751                match res {
752                    CapsFilterMapAction::Keep => glib::ffi::GTRUE,
753                    CapsFilterMapAction::Remove => glib::ffi::GFALSE,
754                }
755            }
756
757            let func = &mut func as *mut F;
758            ffi::gst_caps_filter_and_map_in_place(
759                self.as_mut_ptr(),
760                Some(trampoline::<F>),
761                func as glib::ffi::gpointer,
762            );
763        }
764    }
765}
766
767#[derive(Debug)]
768pub enum CapsFilterMapAction {
769    Keep,
770    Remove,
771}
772
773macro_rules! define_iter(
774    ($name:ident, $typ:ty, $styp:ty, $get_item:expr) => {
775    #[derive(Debug)]
776    pub struct $name<'a> {
777        caps: $typ,
778        idx: usize,
779        n_structures: usize,
780    }
781
782    impl<'a> $name<'a> {
783        fn new(caps: $typ) -> $name<'a> {
784            skip_assert_initialized!();
785            let n_structures = caps.size();
786
787            $name {
788                caps,
789                idx: 0,
790                n_structures: n_structures as usize,
791            }
792        }
793    }
794
795    #[allow(clippy::redundant_closure_call)]
796    impl<'a> Iterator for $name<'a> {
797        type Item = $styp;
798
799        fn next(&mut self) -> Option<Self::Item> {
800            if self.idx >= self.n_structures {
801                return None;
802            }
803
804            unsafe {
805                let item = $get_item(self.caps, self.idx).unwrap();
806                self.idx += 1;
807                Some(item)
808            }
809        }
810
811        fn size_hint(&self) -> (usize, Option<usize>) {
812            let remaining = self.n_structures - self.idx;
813
814            (remaining, Some(remaining))
815        }
816
817        fn count(self) -> usize {
818            self.n_structures - self.idx
819        }
820
821        fn nth(&mut self, n: usize) -> Option<Self::Item> {
822            let (end, overflow) = self.idx.overflowing_add(n);
823            if end >= self.n_structures || overflow {
824                self.idx = self.n_structures;
825                None
826            } else {
827                unsafe {
828                    self.idx = end + 1;
829                    Some($get_item(self.caps, end).unwrap())
830                }
831            }
832        }
833
834        fn last(self) -> Option<Self::Item> {
835            if self.idx == self.n_structures {
836                None
837            } else {
838                unsafe {
839                    Some($get_item(self.caps, self.n_structures - 1).unwrap())
840                }
841            }
842        }
843    }
844
845    #[allow(clippy::redundant_closure_call)]
846    impl<'a> DoubleEndedIterator for $name<'a> {
847        fn next_back(&mut self) -> Option<Self::Item> {
848            if self.idx == self.n_structures {
849                return None;
850            }
851
852            self.n_structures -= 1;
853
854            unsafe {
855                Some($get_item(self.caps, self.n_structures).unwrap())
856            }
857        }
858
859        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
860            let (end, overflow) = self.n_structures.overflowing_sub(n);
861            if end <= self.idx || overflow {
862                self.idx = self.n_structures;
863                None
864            } else {
865                self.n_structures = end - 1;
866                unsafe {
867                    Some($get_item(self.caps, self.n_structures).unwrap())
868                }
869            }
870        }
871    }
872
873    impl<'a> ExactSizeIterator for $name<'a> {}
874
875    impl<'a> std::iter::FusedIterator for $name<'a> {}
876    }
877);
878
879define_iter!(
880    Iter,
881    &'a CapsRef,
882    &'a StructureRef,
883    |caps: &CapsRef, idx| {
884        let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32);
885        if ptr.is_null() {
886            None
887        } else {
888            Some(StructureRef::from_glib_borrow(
889                ptr as *const ffi::GstStructure,
890            ))
891        }
892    }
893);
894define_iter!(
895    IterMut,
896    &'a mut CapsRef,
897    &'a mut StructureRef,
898    |caps: &CapsRef, idx| {
899        let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32);
900        if ptr.is_null() {
901            None
902        } else {
903            Some(StructureRef::from_glib_borrow_mut(ptr))
904        }
905    }
906);
907define_iter!(
908    IterFeatures,
909    &'a CapsRef,
910    (&'a StructureRef, &'a CapsFeaturesRef),
911    |caps: &CapsRef, idx| {
912        let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32);
913        let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx as u32);
914        if ptr1.is_null() || ptr2.is_null() {
915            None
916        } else {
917            Some((
918                StructureRef::from_glib_borrow(ptr1),
919                CapsFeaturesRef::from_glib_borrow(ptr2),
920            ))
921        }
922    }
923);
924define_iter!(
925    IterFeaturesMut,
926    &'a mut CapsRef,
927    (&'a mut StructureRef, &'a mut CapsFeaturesRef),
928    |caps: &CapsRef, idx| {
929        let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32);
930        let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx as u32);
931        if ptr1.is_null() || ptr2.is_null() {
932            None
933        } else {
934            Some((
935                StructureRef::from_glib_borrow_mut(ptr1),
936                CapsFeaturesRef::from_glib_borrow_mut(ptr2),
937            ))
938        }
939    }
940);
941
942impl<'a> IntoIterator for &'a CapsRef {
943    type IntoIter = IterFeatures<'a>;
944    type Item = (&'a StructureRef, &'a CapsFeaturesRef);
945
946    fn into_iter(self) -> Self::IntoIter {
947        self.iter_with_features()
948    }
949}
950
951impl<'a> IntoIterator for &'a mut CapsRef {
952    type IntoIter = IterFeaturesMut<'a>;
953    type Item = (&'a mut StructureRef, &'a mut CapsFeaturesRef);
954
955    fn into_iter(self) -> Self::IntoIter {
956        self.iter_with_features_mut()
957    }
958}
959
960impl fmt::Debug for Caps {
961    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
962        <CapsRef as fmt::Debug>::fmt(self, f)
963    }
964}
965
966impl fmt::Display for Caps {
967    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
968        <CapsRef as fmt::Display>::fmt(self, f)
969    }
970}
971
972impl PartialEq for Caps {
973    fn eq(&self, other: &Caps) -> bool {
974        CapsRef::eq(self, other)
975    }
976}
977
978impl Eq for Caps {}
979
980impl PartialEq<CapsRef> for Caps {
981    fn eq(&self, other: &CapsRef) -> bool {
982        CapsRef::eq(self, other)
983    }
984}
985
986impl PartialEq<Caps> for CapsRef {
987    fn eq(&self, other: &Caps) -> bool {
988        CapsRef::eq(other, self)
989    }
990}
991
992impl fmt::Debug for CapsRef {
993    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
994        if self.is_any() {
995            f.debug_tuple("Caps(\"ANY\")").finish()
996        } else if self.is_empty() {
997            f.debug_tuple("Caps(\"EMPTY\")").finish()
998        } else {
999            let mut debug = f.debug_tuple("Caps");
1000
1001            for (structure, features) in self.iter_with_features() {
1002                struct WithFeatures<'a> {
1003                    features: &'a CapsFeaturesRef,
1004                    structure: &'a StructureRef,
1005                }
1006
1007                impl fmt::Debug for WithFeatures<'_> {
1008                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1009                        let name = format!("{}({})", self.structure.name(), self.features);
1010                        let mut debug = f.debug_struct(&name);
1011
1012                        for (id, field) in self.structure.iter() {
1013                            if field.type_() == Structure::static_type() {
1014                                let s = field.get::<Structure>().unwrap();
1015                                debug.field(id, &s);
1016                            } else if field.type_() == crate::Array::static_type() {
1017                                let arr = field.get::<crate::Array>().unwrap();
1018                                debug.field(id, &arr);
1019                            } else if field.type_() == crate::List::static_type() {
1020                                let list = field.get::<crate::List>().unwrap();
1021                                debug.field(id, &list);
1022                            } else {
1023                                debug.field(id, &field);
1024                            }
1025                        }
1026
1027                        debug.finish()
1028                    }
1029                }
1030
1031                debug.field(&WithFeatures {
1032                    structure,
1033                    features,
1034                });
1035            }
1036
1037            debug.finish()
1038        }
1039    }
1040}
1041
1042impl fmt::Display for CapsRef {
1043    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1044        let s = unsafe { glib::GString::from_glib_full(ffi::gst_caps_to_string(self.as_ptr())) };
1045        f.write_str(&s)
1046    }
1047}
1048
1049impl PartialEq for CapsRef {
1050    #[doc(alias = "gst_caps_is_equal")]
1051    fn eq(&self, other: &CapsRef) -> bool {
1052        unsafe { from_glib(ffi::gst_caps_is_equal(self.as_ptr(), other.as_ptr())) }
1053    }
1054}
1055
1056impl Eq for CapsRef {}
1057
1058pub enum NoFeature {}
1059pub enum HasFeatures {}
1060
1061#[must_use = "The builder must be built to be used"]
1062pub struct Builder<T> {
1063    s: crate::Structure,
1064    features: Option<CapsFeatures>,
1065    phantom: PhantomData<T>,
1066}
1067
1068impl<T> fmt::Debug for Builder<T> {
1069    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1070        f.debug_struct("Builder")
1071            .field("s", &self.s)
1072            .field("features", &self.features)
1073            .field("phantom", &self.phantom)
1074            .finish()
1075    }
1076}
1077
1078impl Builder<NoFeature> {
1079    fn new(name: impl IntoGStr) -> Builder<NoFeature> {
1080        skip_assert_initialized!();
1081        Builder {
1082            s: crate::Structure::new_empty(name),
1083            features: None,
1084            phantom: PhantomData,
1085        }
1086    }
1087
1088    pub fn features(
1089        self,
1090        features: impl IntoIterator<Item = impl IntoGStr>,
1091    ) -> Builder<HasFeatures> {
1092        Builder {
1093            s: self.s,
1094            features: Some(CapsFeatures::new(features)),
1095            phantom: PhantomData,
1096        }
1097    }
1098
1099    pub fn any_features(self) -> Builder<HasFeatures> {
1100        Builder {
1101            s: self.s,
1102            features: Some(CapsFeatures::new_any()),
1103            phantom: PhantomData,
1104        }
1105    }
1106}
1107
1108impl<T> Builder<T> {
1109    // rustdoc-stripper-ignore-next
1110    /// Sets field `name` to the given value `value`.
1111    ///
1112    /// Overrides any default or previously defined value for `name`.
1113    #[inline]
1114    pub fn field(mut self, name: impl IntoGStr, value: impl Into<glib::Value> + Send) -> Self {
1115        self.s.set(name, value);
1116        self
1117    }
1118
1119    impl_builder_gvalue_extra_setters!(field);
1120
1121    #[must_use = "Building the caps without using them has no effect"]
1122    pub fn build(self) -> Caps {
1123        let mut caps = Caps::new_empty();
1124
1125        caps.get_mut()
1126            .unwrap()
1127            .append_structure_full(self.s, self.features);
1128        caps
1129    }
1130
1131    pub fn structure(&self) -> &crate::Structure {
1132        &self.s
1133    }
1134}
1135
1136pub enum AnyFeatures {}
1137pub enum SomeFeatures {}
1138
1139#[must_use = "The builder must be built to be used"]
1140pub struct BuilderFull<T> {
1141    caps: crate::Caps,
1142    features: Option<CapsFeatures>,
1143    phantom: PhantomData<T>,
1144}
1145
1146impl<T> fmt::Debug for BuilderFull<T> {
1147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1148        f.debug_struct("Builder")
1149            .field("caps", &self.caps)
1150            .field("features", &self.features)
1151            .field("phantom", &self.phantom)
1152            .finish()
1153    }
1154}
1155
1156impl BuilderFull<SomeFeatures> {
1157    fn new() -> Self {
1158        BuilderFull {
1159            caps: Caps::new_empty(),
1160            features: None,
1161            phantom: PhantomData,
1162        }
1163    }
1164
1165    fn with_features(features: CapsFeatures) -> Self {
1166        skip_assert_initialized!();
1167        BuilderFull {
1168            caps: Caps::new_empty(),
1169            features: Some(features),
1170            phantom: PhantomData,
1171        }
1172    }
1173
1174    pub fn structure_with_features(self, structure: Structure, features: CapsFeatures) -> Self {
1175        self.append_structure(structure, Some(features))
1176    }
1177
1178    pub fn structure_with_features_if_some(
1179        self,
1180        structure: Option<Structure>,
1181        features: CapsFeatures,
1182    ) -> Self {
1183        if let Some(structure) = structure {
1184            self.structure_with_features(structure, features)
1185        } else {
1186            self
1187        }
1188    }
1189
1190    pub fn structure_with_any_features(self, structure: Structure) -> Self {
1191        self.append_structure(structure, Some(CapsFeatures::new_any()))
1192    }
1193
1194    pub fn structure_with_any_features_if_some(self, structure: Option<Structure>) -> Self {
1195        if let Some(structure) = structure {
1196            self.structure_with_any_features(structure)
1197        } else {
1198            self
1199        }
1200    }
1201}
1202
1203impl BuilderFull<AnyFeatures> {
1204    fn with_any_features() -> Self {
1205        BuilderFull {
1206            caps: Caps::new_empty(),
1207            features: Some(CapsFeatures::new_any()),
1208            phantom: PhantomData,
1209        }
1210    }
1211}
1212
1213impl<T> BuilderFull<T> {
1214    fn append_structure(mut self, structure: Structure, features: Option<CapsFeatures>) -> Self {
1215        let features = {
1216            match self.features {
1217                None => features,
1218                Some(ref result) => {
1219                    let mut result = result.clone();
1220                    match features {
1221                        None => Some(result),
1222                        Some(features) => {
1223                            features.iter().for_each(|feat| result.add(feat));
1224                            Some(result)
1225                        }
1226                    }
1227                }
1228            }
1229        };
1230
1231        self.caps
1232            .get_mut()
1233            .unwrap()
1234            .append_structure_full(structure, features);
1235        self
1236    }
1237
1238    pub fn structure(self, structure: Structure) -> Self {
1239        self.append_structure(structure, None)
1240    }
1241
1242    pub fn structure_if_some(self, structure: Option<Structure>) -> Self {
1243        if let Some(structure) = structure {
1244            self.structure(structure)
1245        } else {
1246            self
1247        }
1248    }
1249
1250    #[must_use = "Building the caps without using them has no effect"]
1251    pub fn build(self) -> Caps {
1252        self.caps
1253    }
1254}
1255
1256#[cfg(test)]
1257mod tests {
1258    use super::*;
1259    use crate::{Array, Fraction};
1260
1261    #[test]
1262    fn test_builder() {
1263        crate::init().unwrap();
1264
1265        let mut caps = Caps::builder("foo/bar")
1266            .field("int", 12)
1267            .field("bool", true)
1268            .field("string", "bla")
1269            .field("fraction", Fraction::new(1, 2))
1270            .field("array", Array::new([1, 2]))
1271            .build();
1272        assert_eq!(
1273            caps.to_string(),
1274            "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >"
1275        );
1276
1277        assert!(caps
1278            .features(0)
1279            .unwrap()
1280            .is_equal(crate::CAPS_FEATURES_MEMORY_SYSTEM_MEMORY.as_ref()));
1281
1282        {
1283            let caps = caps.get_mut().unwrap();
1284            caps.set_features(0, Some(CapsFeatures::new(["foo:bla"])));
1285        }
1286        assert!(caps
1287            .features(0)
1288            .unwrap()
1289            .is_equal(CapsFeatures::new(["foo:bla"]).as_ref()));
1290
1291        let caps = Caps::builder("foo/bar")
1292            .field("int", 12)
1293            .any_features()
1294            .build();
1295        assert_eq!(caps.to_string(), "foo/bar(ANY), int=(int)12");
1296
1297        let caps = Caps::builder("foo/bar")
1298            .field("int", 12)
1299            .features(["foo:bla", "foo:baz"])
1300            .build();
1301        assert_eq!(caps.to_string(), "foo/bar(foo:bla, foo:baz), int=(int)12");
1302
1303        let caps = Caps::builder("foo/bar")
1304            .field_if_some("int0", Option::<i32>::None)
1305            .field_if_some("int1", Some(12))
1306            .field_if_some("string0", Option::<String>::None)
1307            .field_if_some("string1", Some("bla"))
1308            .build();
1309        assert_eq!(
1310            caps.to_string(),
1311            "foo/bar, int1=(int)12, string1=(string)bla"
1312        );
1313    }
1314
1315    #[test]
1316    fn test_display() {
1317        crate::init().unwrap();
1318
1319        let caps = Caps::builder("foo/bar").build();
1320        let _ = format!("{caps}");
1321    }
1322
1323    #[test]
1324    fn test_builder_full() {
1325        crate::init().unwrap();
1326
1327        let caps = Caps::builder_full()
1328            .structure(Structure::builder("audio/x-raw").build())
1329            .structure(Structure::builder("video/x-raw").build())
1330            .build();
1331        assert_eq!(caps.to_string(), "audio/x-raw; video/x-raw");
1332
1333        let caps = Caps::builder_full()
1334            .structure(
1335                Structure::builder("audio/x-raw")
1336                    .field("format", "S16LE")
1337                    .build(),
1338            )
1339            .structure(Structure::builder("video/x-raw").build())
1340            .build();
1341        assert_eq!(
1342            caps.to_string(),
1343            "audio/x-raw, format=(string)S16LE; video/x-raw"
1344        );
1345
1346        let caps = Caps::builder_full()
1347            .structure_with_any_features(Structure::builder("audio/x-raw").build())
1348            .structure_with_features(
1349                Structure::builder("video/x-raw").build(),
1350                CapsFeatures::new(["foo:bla", "foo:baz"]),
1351            )
1352            .build();
1353        assert_eq!(
1354            caps.to_string(),
1355            "audio/x-raw(ANY); video/x-raw(foo:bla, foo:baz)"
1356        );
1357
1358        let caps = Caps::builder_full()
1359            .structure_if_some(Option::<Structure>::None)
1360            .build();
1361        assert!(caps.is_empty());
1362
1363        let caps = Caps::builder_full()
1364            .structure_if_some(Some(Structure::builder("audio/x-raw").build()))
1365            .build();
1366        assert_eq!(caps.to_string(), "audio/x-raw");
1367
1368        let caps = Caps::builder_full()
1369            .structure_with_any_features_if_some(Some(Structure::builder("audio/x-raw").build()))
1370            .structure_with_features_if_some(
1371                Some(Structure::builder("video/x-raw").build()),
1372                CapsFeatures::new(["foo:bla", "foo:baz"]),
1373            )
1374            .build();
1375        assert_eq!(
1376            caps.to_string(),
1377            "audio/x-raw(ANY); video/x-raw(foo:bla, foo:baz)"
1378        );
1379
1380        let caps = Caps::builder_full()
1381            .structure_with_any_features_if_some(Option::<Structure>::None)
1382            .structure_with_features_if_some(
1383                Option::<Structure>::None,
1384                CapsFeatures::new(["foo:bla", "foo:baz"]),
1385            )
1386            .build();
1387        assert!(caps.is_empty());
1388    }
1389
1390    #[test]
1391    fn test_builder_full_with_features() {
1392        crate::init().unwrap();
1393
1394        let caps = Caps::builder_full_with_features(CapsFeatures::new(["foo:bla"]))
1395            .structure(Structure::builder("audio/x-raw").build())
1396            .structure_with_features(
1397                Structure::builder("video/x-raw").build(),
1398                CapsFeatures::new(["foo:baz"]),
1399            )
1400            .build();
1401        assert_eq!(
1402            caps.to_string(),
1403            "audio/x-raw(foo:bla); video/x-raw(foo:bla, foo:baz)"
1404        );
1405    }
1406
1407    #[test]
1408    fn test_builder_full_with_any_features() {
1409        crate::init().unwrap();
1410
1411        let caps = Caps::builder_full_with_any_features()
1412            .structure(Structure::builder("audio/x-raw").build())
1413            .structure(Structure::builder("video/x-raw").build())
1414            .build();
1415        assert_eq!(caps.to_string(), "audio/x-raw(ANY); video/x-raw(ANY)");
1416
1417        let caps = Caps::builder_full_with_any_features()
1418            .structure(Structure::builder("audio/x-raw").build())
1419            .build();
1420        assert_eq!(caps.to_string(), "audio/x-raw(ANY)");
1421    }
1422
1423    #[test]
1424    fn test_new_from_iter() {
1425        crate::init().unwrap();
1426
1427        let caps = Caps::builder_full_with_any_features()
1428            .structure(Structure::builder("audio/x-raw").build())
1429            .structure(Structure::builder("video/x-raw").build())
1430            .build();
1431
1432        let audio = caps
1433            .iter()
1434            .filter(|s| s.name() == "audio/x-raw")
1435            .map(|s| s.to_owned())
1436            .collect::<Caps>();
1437        assert_eq!(audio.to_string(), "audio/x-raw");
1438
1439        let audio = caps
1440            .iter_with_features()
1441            .filter(|(s, _)| s.name() == "audio/x-raw")
1442            .map(|(s, c)| (s.to_owned(), c.to_owned()))
1443            .collect::<Caps>();
1444        assert_eq!(audio.to_string(), "audio/x-raw(ANY)");
1445    }
1446
1447    #[test]
1448    fn test_debug() {
1449        crate::init().unwrap();
1450
1451        let caps = Caps::new_any();
1452        assert_eq!(format!("{caps:?}"), "Caps(\"ANY\")");
1453
1454        let caps = Caps::new_empty();
1455        assert_eq!(format!("{caps:?}"), "Caps(\"EMPTY\")");
1456
1457        let caps = Caps::builder_full_with_any_features()
1458            .structure(Structure::builder("audio/x-raw").build())
1459            .build();
1460        assert_eq!(format!("{caps:?}"), "Caps(audio/x-raw(ANY))");
1461
1462        let caps = Caps::builder_full_with_features(CapsFeatures::new(["foo:bla"]))
1463            .structure(
1464                Structure::builder("audio/x-raw")
1465                    .field(
1466                        "struct",
1467                        Structure::builder("nested").field("badger", true).build(),
1468                    )
1469                    .build(),
1470            )
1471            .structure(
1472                Structure::builder("video/x-raw")
1473                    .field("width", 800u32)
1474                    .build(),
1475            )
1476            .build();
1477
1478        assert_eq!(format!("{caps:?}"), "Caps(audio/x-raw(foo:bla) { struct: Structure(nested { badger: (gboolean) TRUE }) }, video/x-raw(foo:bla) { width: (guint) 800 })");
1479
1480        let caps = Caps::builder_full()
1481            .structure(
1482                Structure::builder("video/x-raw")
1483                    .field("array", crate::Array::new(["a", "b", "c"]))
1484                    .field("list", crate::List::new(["d", "e", "f"]))
1485                    .build(),
1486            )
1487            .build();
1488
1489        assert_eq!(format!("{caps:?}"), "Caps(video/x-raw(memory:SystemMemory) { array: Array([(gchararray) \"a\", (gchararray) \"b\", (gchararray) \"c\"]), list: List([(gchararray) \"d\", (gchararray) \"e\", (gchararray) \"f\"]) })");
1490    }
1491}