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