1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::caps_features::*;
4 use crate::structure::*;
5 use std::fmt;
6 use std::marker::PhantomData;
7 use std::ptr;
8 use std::str;
9 
10 use crate::CapsIntersectMode;
11 
12 use glib::translate::{from_glib, from_glib_full, FromGlibPtrFull, IntoGlib, ToGlibPtr};
13 use glib::value::ToSendValue;
14 
15 mini_object_wrapper!(Caps, CapsRef, ffi::GstCaps, || { ffi::gst_caps_get_type() });
16 
17 impl Caps {
builder(name: &str) -> Builder<NoFeature>18     pub fn builder(name: &str) -> Builder<NoFeature> {
19         assert_initialized_main_thread!();
20         Builder::new(name)
21     }
22 
builder_full() -> BuilderFull<SomeFeatures>23     pub fn builder_full() -> BuilderFull<SomeFeatures> {
24         assert_initialized_main_thread!();
25         BuilderFull::new()
26     }
27 
builder_full_with_features(features: CapsFeatures) -> BuilderFull<SomeFeatures>28     pub fn builder_full_with_features(features: CapsFeatures) -> BuilderFull<SomeFeatures> {
29         assert_initialized_main_thread!();
30         BuilderFull::with_features(features)
31     }
32 
builder_full_with_any_features() -> BuilderFull<AnyFeatures>33     pub fn builder_full_with_any_features() -> BuilderFull<AnyFeatures> {
34         assert_initialized_main_thread!();
35         BuilderFull::with_any_features()
36     }
37 
38     #[doc(alias = "gst_caps_new_empty")]
new_empty() -> Self39     pub fn new_empty() -> Self {
40         assert_initialized_main_thread!();
41         unsafe { from_glib_full(ffi::gst_caps_new_empty()) }
42     }
43 
44     #[doc(alias = "gst_caps_new_any")]
new_any() -> Self45     pub fn new_any() -> Self {
46         assert_initialized_main_thread!();
47         unsafe { from_glib_full(ffi::gst_caps_new_any()) }
48     }
49 
new_simple(name: &str, values: &[(&str, &(dyn ToSendValue + Sync))]) -> Self50     pub fn new_simple(name: &str, values: &[(&str, &(dyn ToSendValue + Sync))]) -> Self {
51         assert_initialized_main_thread!();
52         let mut caps = Caps::new_empty();
53 
54         let structure = Structure::new(name, values);
55         caps.get_mut().unwrap().append_structure(structure);
56 
57         caps
58     }
59 
60     #[allow(clippy::should_implement_trait)]
from_iter<'a, I>(iter: I) -> Self where I: IntoIterator<Item = &'a StructureRef>,61     pub fn from_iter<'a, I>(iter: I) -> Self
62     where
63         I: IntoIterator<Item = &'a StructureRef>,
64     {
65         assert_initialized_main_thread!();
66         let mut caps = Caps::new_empty();
67 
68         iter.into_iter()
69             .for_each(|s| caps.get_mut().unwrap().append_structure(s.to_owned()));
70 
71         caps
72     }
73 
from_iter_with_features<'a, 'b, I>(iter: I) -> Self where I: IntoIterator<Item = (&'a StructureRef, &'b CapsFeaturesRef)>,74     pub fn from_iter_with_features<'a, 'b, I>(iter: I) -> Self
75     where
76         I: IntoIterator<Item = (&'a StructureRef, &'b CapsFeaturesRef)>,
77     {
78         assert_initialized_main_thread!();
79         let mut caps = Caps::new_empty();
80 
81         iter.into_iter().for_each(|(s, f)| {
82             caps.get_mut()
83                 .unwrap()
84                 .append_structure_full(s.to_owned(), Some(f.to_owned()))
85         });
86 
87         caps
88     }
89 
90     #[doc(alias = "gst_caps_fixate")]
fixate(&mut self)91     pub fn fixate(&mut self) {
92         skip_assert_initialized!();
93         unsafe {
94             // See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/388
95             assert!(!self.is_any());
96             let ptr = if self.is_empty() {
97                 ffi::gst_caps_new_empty()
98             } else {
99                 ffi::gst_caps_fixate(self.as_mut_ptr())
100             };
101             self.replace_ptr(ptr);
102         }
103     }
104 
105     #[doc(alias = "gst_caps_merge")]
merge(&mut self, other: Self)106     pub fn merge(&mut self, other: Self) {
107         skip_assert_initialized!();
108         unsafe {
109             let ptr = ffi::gst_caps_merge(self.as_mut_ptr(), other.into_ptr());
110             self.replace_ptr(ptr);
111         }
112     }
113 
114     #[doc(alias = "gst_caps_merge_structure")]
merge_structure(&mut self, structure: Structure)115     pub fn merge_structure(&mut self, structure: Structure) {
116         skip_assert_initialized!();
117         unsafe {
118             let ptr = ffi::gst_caps_merge_structure(self.as_mut_ptr(), structure.into_ptr());
119             self.replace_ptr(ptr);
120         }
121     }
122 
123     #[doc(alias = "gst_caps_merge_structure_full")]
merge_structure_full(&mut self, structure: Structure, features: Option<CapsFeatures>)124     pub fn merge_structure_full(&mut self, structure: Structure, features: Option<CapsFeatures>) {
125         skip_assert_initialized!();
126         unsafe {
127             let ptr = ffi::gst_caps_merge_structure_full(
128                 self.as_mut_ptr(),
129                 structure.into_ptr(),
130                 features.map(|f| f.into_ptr()).unwrap_or(ptr::null_mut()),
131             );
132             self.replace_ptr(ptr);
133         }
134     }
135 
136     #[doc(alias = "gst_caps_normalize")]
normalize(&mut self)137     pub fn normalize(&mut self) {
138         skip_assert_initialized!();
139         unsafe {
140             let ptr = ffi::gst_caps_normalize(self.as_mut_ptr());
141             self.replace_ptr(ptr);
142         }
143     }
144 
145     #[doc(alias = "gst_caps_simplify")]
simplify(&mut self)146     pub fn simplify(&mut self) {
147         skip_assert_initialized!();
148         unsafe {
149             let ptr = ffi::gst_caps_simplify(self.as_mut_ptr());
150             self.replace_ptr(ptr);
151         }
152     }
153 
154     #[doc(alias = "gst_caps_truncate")]
truncate(&mut self)155     pub fn truncate(&mut self) {
156         skip_assert_initialized!();
157         unsafe {
158             let ptr = ffi::gst_caps_truncate(self.as_mut_ptr());
159             self.replace_ptr(ptr);
160         }
161     }
162 }
163 
164 impl str::FromStr for Caps {
165     type Err = glib::BoolError;
166 
167     #[doc(alias = "gst_caps_from_string")]
from_str(s: &str) -> Result<Self, Self::Err>168     fn from_str(s: &str) -> Result<Self, Self::Err> {
169         assert_initialized_main_thread!();
170         unsafe {
171             Option::<_>::from_glib_full(ffi::gst_caps_from_string(s.to_glib_none().0))
172                 .ok_or_else(|| glib::bool_error!("Failed to parse caps from string"))
173         }
174     }
175 }
176 
177 impl CapsRef {
set_simple(&mut self, values: &[(&str, &(dyn ToSendValue + Sync))])178     pub fn set_simple(&mut self, values: &[(&str, &(dyn ToSendValue + Sync))]) {
179         for &(name, value) in values {
180             let value = value.to_value();
181 
182             unsafe {
183                 ffi::gst_caps_set_value(
184                     self.as_mut_ptr(),
185                     name.to_glib_none().0,
186                     value.to_glib_none().0,
187                 );
188             }
189         }
190     }
191 
192     #[doc(alias = "get_structure")]
193     #[doc(alias = "gst_caps_get_structure")]
structure(&self, idx: u32) -> Option<&StructureRef>194     pub fn structure(&self, idx: u32) -> Option<&StructureRef> {
195         if idx >= self.size() {
196             return None;
197         }
198 
199         unsafe {
200             let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx);
201             if structure.is_null() {
202                 return None;
203             }
204 
205             Some(StructureRef::from_glib_borrow(structure))
206         }
207     }
208 
209     #[doc(alias = "get_mut_structure")]
structure_mut(&mut self, idx: u32) -> Option<&mut StructureRef>210     pub fn structure_mut(&mut self, idx: u32) -> Option<&mut StructureRef> {
211         if idx >= self.size() {
212             return None;
213         }
214 
215         unsafe {
216             let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx);
217             if structure.is_null() {
218                 return None;
219             }
220 
221             Some(StructureRef::from_glib_borrow_mut(structure))
222         }
223     }
224 
225     #[doc(alias = "get_features")]
226     #[doc(alias = "gst_caps_get_features")]
features(&self, idx: u32) -> Option<&CapsFeaturesRef>227     pub fn features(&self, idx: u32) -> Option<&CapsFeaturesRef> {
228         if idx >= self.size() {
229             return None;
230         }
231 
232         unsafe {
233             let features = ffi::gst_caps_get_features(self.as_ptr(), idx);
234             Some(CapsFeaturesRef::from_glib_borrow(features))
235         }
236     }
237 
238     #[doc(alias = "get_mut_features")]
features_mut(&mut self, idx: u32) -> Option<&mut CapsFeaturesRef>239     pub fn features_mut(&mut self, idx: u32) -> Option<&mut CapsFeaturesRef> {
240         if idx >= self.size() {
241             return None;
242         }
243 
244         unsafe {
245             let features = ffi::gst_caps_get_features(self.as_ptr(), idx);
246             Some(CapsFeaturesRef::from_glib_borrow_mut(features))
247         }
248     }
249 
250     #[doc(alias = "gst_caps_set_features")]
set_features(&mut self, idx: u32, features: Option<CapsFeatures>)251     pub fn set_features(&mut self, idx: u32, features: Option<CapsFeatures>) {
252         assert!(idx < self.size());
253 
254         unsafe {
255             ffi::gst_caps_set_features(
256                 self.as_mut_ptr(),
257                 idx,
258                 features.map(|f| f.into_ptr()).unwrap_or(ptr::null_mut()),
259             )
260         }
261     }
262 
263     #[cfg(any(feature = "v1_16", feature = "dox"))]
264     #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))]
265     #[doc(alias = "gst_caps_set_features_simple")]
set_features_simple(&mut self, features: Option<CapsFeatures>)266     pub fn set_features_simple(&mut self, features: Option<CapsFeatures>) {
267         unsafe {
268             ffi::gst_caps_set_features_simple(
269                 self.as_mut_ptr(),
270                 features.map(|f| f.into_ptr()).unwrap_or(ptr::null_mut()),
271             )
272         }
273     }
274 
275     #[doc(alias = "get_size")]
276     #[doc(alias = "gst_caps_get_size")]
size(&self) -> u32277     pub fn size(&self) -> u32 {
278         unsafe { ffi::gst_caps_get_size(self.as_ptr()) }
279     }
280 
iter(&self) -> Iter281     pub fn iter(&self) -> Iter {
282         Iter::new(self)
283     }
284 
iter_mut(&mut self) -> IterMut285     pub fn iter_mut(&mut self) -> IterMut {
286         IterMut::new(self)
287     }
288 
iter_with_features(&self) -> IterFeatures289     pub fn iter_with_features(&self) -> IterFeatures {
290         IterFeatures::new(self)
291     }
292 
iter_with_features_mut(&mut self) -> IterFeaturesMut293     pub fn iter_with_features_mut(&mut self) -> IterFeaturesMut {
294         IterFeaturesMut::new(self)
295     }
296 
297     #[doc(alias = "gst_caps_append_structure")]
append_structure(&mut self, structure: Structure)298     pub fn append_structure(&mut self, structure: Structure) {
299         unsafe { ffi::gst_caps_append_structure(self.as_mut_ptr(), structure.into_ptr()) }
300     }
301 
302     #[doc(alias = "gst_caps_append_structure_full")]
append_structure_full(&mut self, structure: Structure, features: Option<CapsFeatures>)303     pub fn append_structure_full(&mut self, structure: Structure, features: Option<CapsFeatures>) {
304         unsafe {
305             ffi::gst_caps_append_structure_full(
306                 self.as_mut_ptr(),
307                 structure.into_ptr(),
308                 features.map(|f| f.into_ptr()).unwrap_or(ptr::null_mut()),
309             )
310         }
311     }
312 
313     #[doc(alias = "gst_caps_remove_structure")]
remove_structure(&mut self, idx: u32)314     pub fn remove_structure(&mut self, idx: u32) {
315         unsafe { ffi::gst_caps_remove_structure(self.as_mut_ptr(), idx) }
316     }
317 
318     #[doc(alias = "gst_caps_append")]
append(&mut self, other: Caps)319     pub fn append(&mut self, other: Caps) {
320         unsafe { ffi::gst_caps_append(self.as_mut_ptr(), other.into_ptr()) }
321     }
322 
323     #[doc(alias = "gst_caps_can_intersect")]
can_intersect(&self, other: &Self) -> bool324     pub fn can_intersect(&self, other: &Self) -> bool {
325         unsafe { from_glib(ffi::gst_caps_can_intersect(self.as_ptr(), other.as_ptr())) }
326     }
327 
328     #[doc(alias = "gst_caps_intersect")]
intersect(&self, other: &Self) -> Caps329     pub fn intersect(&self, other: &Self) -> Caps {
330         unsafe {
331             from_glib_full(ffi::gst_caps_intersect(
332                 self.as_mut_ptr(),
333                 other.as_mut_ptr(),
334             ))
335         }
336     }
337 
intersect_with_mode(&self, other: &Self, mode: CapsIntersectMode) -> Caps338     pub fn intersect_with_mode(&self, other: &Self, mode: CapsIntersectMode) -> Caps {
339         unsafe {
340             from_glib_full(ffi::gst_caps_intersect_full(
341                 self.as_mut_ptr(),
342                 other.as_mut_ptr(),
343                 mode.into_glib(),
344             ))
345         }
346     }
347 
348     #[doc(alias = "gst_caps_is_always_compatible")]
is_always_compatible(&self, other: &Self) -> bool349     pub fn is_always_compatible(&self, other: &Self) -> bool {
350         unsafe {
351             from_glib(ffi::gst_caps_is_always_compatible(
352                 self.as_ptr(),
353                 other.as_ptr(),
354             ))
355         }
356     }
357 
358     #[doc(alias = "gst_caps_is_any")]
is_any(&self) -> bool359     pub fn is_any(&self) -> bool {
360         unsafe { from_glib(ffi::gst_caps_is_any(self.as_ptr())) }
361     }
362 
363     #[doc(alias = "gst_caps_is_empty")]
is_empty(&self) -> bool364     pub fn is_empty(&self) -> bool {
365         unsafe { from_glib(ffi::gst_caps_is_empty(self.as_ptr())) }
366     }
367 
368     #[doc(alias = "gst_caps_is_fixed")]
is_fixed(&self) -> bool369     pub fn is_fixed(&self) -> bool {
370         unsafe { from_glib(ffi::gst_caps_is_fixed(self.as_ptr())) }
371     }
372 
373     #[doc(alias = "gst_caps_is_equal_fixed")]
is_equal_fixed(&self, other: &Self) -> bool374     pub fn is_equal_fixed(&self, other: &Self) -> bool {
375         unsafe { from_glib(ffi::gst_caps_is_equal_fixed(self.as_ptr(), other.as_ptr())) }
376     }
377 
378     #[doc(alias = "gst_caps_is_strictly_equal")]
is_strictly_equal(&self, other: &Self) -> bool379     pub fn is_strictly_equal(&self, other: &Self) -> bool {
380         unsafe {
381             from_glib(ffi::gst_caps_is_strictly_equal(
382                 self.as_ptr(),
383                 other.as_ptr(),
384             ))
385         }
386     }
387 
388     #[doc(alias = "gst_caps_is_subset")]
is_subset(&self, superset: &Self) -> bool389     pub fn is_subset(&self, superset: &Self) -> bool {
390         unsafe { from_glib(ffi::gst_caps_is_subset(self.as_ptr(), superset.as_ptr())) }
391     }
392 
393     #[doc(alias = "gst_caps_is_subset_structure")]
is_subset_structure(&self, structure: &StructureRef) -> bool394     pub fn is_subset_structure(&self, structure: &StructureRef) -> bool {
395         unsafe {
396             from_glib(ffi::gst_caps_is_subset_structure(
397                 self.as_ptr(),
398                 structure.as_ptr(),
399             ))
400         }
401     }
402 
403     #[doc(alias = "gst_caps_is_subset_structure_full")]
is_subset_structure_full( &self, structure: &StructureRef, features: Option<&CapsFeaturesRef>, ) -> bool404     pub fn is_subset_structure_full(
405         &self,
406         structure: &StructureRef,
407         features: Option<&CapsFeaturesRef>,
408     ) -> bool {
409         unsafe {
410             from_glib(ffi::gst_caps_is_subset_structure_full(
411                 self.as_ptr(),
412                 structure.as_ptr(),
413                 features.map(|f| f.as_ptr()).unwrap_or(ptr::null()),
414             ))
415         }
416     }
417 
418     #[doc(alias = "gst_caps_subtract")]
subtract(&self, other: &Self) -> Caps419     pub fn subtract(&self, other: &Self) -> Caps {
420         skip_assert_initialized!();
421         unsafe {
422             from_glib_full(ffi::gst_caps_subtract(
423                 self.as_mut_ptr(),
424                 other.as_mut_ptr(),
425             ))
426         }
427     }
428 
429     #[cfg(any(feature = "v1_20", feature = "dox"))]
430     #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
431     #[doc(alias = "gst_caps_serialize")]
serialize(&self, flags: crate::SerializeFlags) -> glib::GString432     pub fn serialize(&self, flags: crate::SerializeFlags) -> glib::GString {
433         unsafe { from_glib_full(ffi::gst_caps_serialize(&self.0, flags.into_glib())) }
434     }
435 }
436 
437 macro_rules! define_iter(
438     ($name:ident, $typ:ty, $styp:ty, $get_item:expr) => {
439     #[derive(Debug)]
440     pub struct $name<'a> {
441         caps: $typ,
442         idx: u32,
443         n_structures: u32,
444     }
445 
446     impl<'a> $name<'a> {
447         fn new(caps: $typ) -> $name<'a> {
448             skip_assert_initialized!();
449             let n_structures = caps.size();
450 
451             $name {
452                 caps,
453                 idx: 0,
454                 n_structures,
455             }
456         }
457     }
458 
459     impl<'a> Iterator for $name<'a> {
460         type Item = $styp;
461 
462         fn next(&mut self) -> Option<Self::Item> {
463             if self.idx >= self.n_structures {
464                 return None;
465             }
466 
467             unsafe {
468                 let item = $get_item(self.caps, self.idx)?;
469                 self.idx += 1;
470                 Some(item)
471             }
472         }
473 
474         fn size_hint(&self) -> (usize, Option<usize>) {
475             if self.idx == self.n_structures {
476                 return (0, Some(0));
477             }
478 
479             let remaining = (self.n_structures - self.idx) as usize;
480 
481             (remaining, Some(remaining))
482         }
483     }
484 
485     impl<'a> DoubleEndedIterator for $name<'a> {
486         fn next_back(&mut self) -> Option<Self::Item> {
487             if self.idx == self.n_structures {
488                 return None;
489             }
490 
491             self.n_structures -= 1;
492 
493             unsafe {
494                 $get_item(self.caps, self.n_structures)
495             }
496         }
497     }
498 
499     impl<'a> ExactSizeIterator for $name<'a> {}
500     }
501 );
502 
503 define_iter!(
504     Iter,
505     &'a CapsRef,
506     &'a StructureRef,
507     |caps: &CapsRef, idx| {
508         let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
509         if ptr.is_null() {
510             None
511         } else {
512             Some(StructureRef::from_glib_borrow(
513                 ptr as *const ffi::GstStructure,
514             ))
515         }
516     }
517 );
518 define_iter!(
519     IterMut,
520     &'a mut CapsRef,
521     &'a mut StructureRef,
522     |caps: &CapsRef, idx| {
523         let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
524         if ptr.is_null() {
525             None
526         } else {
527             Some(StructureRef::from_glib_borrow_mut(
528                 ptr as *mut ffi::GstStructure,
529             ))
530         }
531     }
532 );
533 define_iter!(
534     IterFeatures,
535     &'a CapsRef,
536     (&'a StructureRef, &'a CapsFeaturesRef),
537     |caps: &CapsRef, idx| {
538         let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
539         let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx);
540         if ptr1.is_null() || ptr2.is_null() {
541             None
542         } else {
543             Some((
544                 StructureRef::from_glib_borrow(ptr1 as *const ffi::GstStructure),
545                 CapsFeaturesRef::from_glib_borrow(ptr2 as *const ffi::GstCapsFeatures),
546             ))
547         }
548     }
549 );
550 define_iter!(
551     IterFeaturesMut,
552     &'a mut CapsRef,
553     (&'a mut StructureRef, &'a mut CapsFeaturesRef),
554     |caps: &CapsRef, idx| {
555         let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
556         let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx);
557         if ptr1.is_null() || ptr2.is_null() {
558             None
559         } else {
560             Some((
561                 StructureRef::from_glib_borrow_mut(ptr1 as *mut ffi::GstStructure),
562                 CapsFeaturesRef::from_glib_borrow_mut(ptr2 as *mut ffi::GstCapsFeatures),
563             ))
564         }
565     }
566 );
567 
568 impl fmt::Debug for Caps {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result569     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
570         <CapsRef as fmt::Debug>::fmt(self, f)
571     }
572 }
573 
574 impl fmt::Display for Caps {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result575     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
576         <CapsRef as fmt::Display>::fmt(self, f)
577     }
578 }
579 
580 impl PartialEq for Caps {
eq(&self, other: &Caps) -> bool581     fn eq(&self, other: &Caps) -> bool {
582         CapsRef::eq(self, other)
583     }
584 }
585 
586 impl Eq for Caps {}
587 
588 impl fmt::Debug for CapsRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result589     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
590         f.debug_tuple("Caps").field(&self.to_string()).finish()
591     }
592 }
593 
594 impl fmt::Display for CapsRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result595     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
596         let s = unsafe { glib::GString::from_glib_full(ffi::gst_caps_to_string(self.as_ptr())) };
597         f.write_str(&s)
598     }
599 }
600 
601 impl PartialEq for CapsRef {
602     #[doc(alias = "gst_caps_is_equal")]
eq(&self, other: &CapsRef) -> bool603     fn eq(&self, other: &CapsRef) -> bool {
604         unsafe { from_glib(ffi::gst_caps_is_equal(self.as_ptr(), other.as_ptr())) }
605     }
606 }
607 
608 impl Eq for CapsRef {}
609 
610 pub enum NoFeature {}
611 pub enum HasFeatures {}
612 
613 pub struct Builder<T> {
614     s: crate::Structure,
615     features: Option<CapsFeatures>,
616     phantom: PhantomData<T>,
617 }
618 
619 impl<T> fmt::Debug for Builder<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result620     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
621         f.debug_struct("Builder")
622             .field("s", &self.s)
623             .field("features", &self.features)
624             .field("phantom", &self.phantom)
625             .finish()
626     }
627 }
628 
629 impl Builder<NoFeature> {
new(name: &str) -> Builder<NoFeature>630     fn new(name: &str) -> Builder<NoFeature> {
631         skip_assert_initialized!();
632         Builder {
633             s: crate::Structure::new_empty(name),
634             features: None,
635             phantom: PhantomData,
636         }
637     }
638 
features(self, features: &[&str]) -> Builder<HasFeatures>639     pub fn features(self, features: &[&str]) -> Builder<HasFeatures> {
640         Builder {
641             s: self.s,
642             features: Some(CapsFeatures::new(features)),
643             phantom: PhantomData,
644         }
645     }
646 
any_features(self) -> Builder<HasFeatures>647     pub fn any_features(self) -> Builder<HasFeatures> {
648         Builder {
649             s: self.s,
650             features: Some(CapsFeatures::new_any()),
651             phantom: PhantomData,
652         }
653     }
654 }
655 
656 impl<T> Builder<T> {
field<V: ToSendValue + Sync>(mut self, name: &str, value: V) -> Self657     pub fn field<V: ToSendValue + Sync>(mut self, name: &str, value: V) -> Self {
658         self.s.set(name, value);
659         self
660     }
661 
build(self) -> Caps662     pub fn build(self) -> Caps {
663         let mut caps = Caps::new_empty();
664 
665         caps.get_mut()
666             .unwrap()
667             .append_structure_full(self.s, self.features);
668         caps
669     }
670 }
671 
672 pub enum AnyFeatures {}
673 pub enum SomeFeatures {}
674 
675 pub struct BuilderFull<T> {
676     caps: crate::Caps,
677     features: Option<CapsFeatures>,
678     phantom: PhantomData<T>,
679 }
680 
681 impl<T> fmt::Debug for BuilderFull<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result682     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
683         f.debug_struct("Builder")
684             .field("caps", &self.caps)
685             .field("features", &self.features)
686             .field("phantom", &self.phantom)
687             .finish()
688     }
689 }
690 
691 impl BuilderFull<SomeFeatures> {
new() -> Self692     fn new() -> Self {
693         BuilderFull {
694             caps: Caps::new_empty(),
695             features: None,
696             phantom: PhantomData,
697         }
698     }
699 
with_features(features: CapsFeatures) -> Self700     fn with_features(features: CapsFeatures) -> Self {
701         skip_assert_initialized!();
702         BuilderFull {
703             caps: Caps::new_empty(),
704             features: Some(features),
705             phantom: PhantomData,
706         }
707     }
708 
structure_with_features(self, structure: Structure, features: CapsFeatures) -> Self709     pub fn structure_with_features(self, structure: Structure, features: CapsFeatures) -> Self {
710         self.append_structure(structure, Some(features))
711     }
712 
structure_with_any_features(self, structure: Structure) -> Self713     pub fn structure_with_any_features(self, structure: Structure) -> Self {
714         self.append_structure(structure, Some(CapsFeatures::new_any()))
715     }
716 }
717 
718 impl BuilderFull<AnyFeatures> {
with_any_features() -> Self719     fn with_any_features() -> Self {
720         BuilderFull {
721             caps: Caps::new_empty(),
722             features: Some(CapsFeatures::new_any()),
723             phantom: PhantomData,
724         }
725     }
726 }
727 
728 impl<T> BuilderFull<T> {
append_structure(mut self, structure: Structure, features: Option<CapsFeatures>) -> Self729     fn append_structure(mut self, structure: Structure, features: Option<CapsFeatures>) -> Self {
730         let features = {
731             match self.features {
732                 None => features,
733                 Some(ref result) => {
734                     let mut result = result.clone();
735                     match features {
736                         None => Some(result),
737                         Some(features) => {
738                             features.iter().for_each(|feat| result.add(feat));
739                             Some(result)
740                         }
741                     }
742                 }
743             }
744         };
745 
746         self.caps
747             .get_mut()
748             .unwrap()
749             .append_structure_full(structure, features);
750         self
751     }
752 
structure(self, structure: Structure) -> Self753     pub fn structure(self, structure: Structure) -> Self {
754         self.append_structure(structure, None)
755     }
756 
build(self) -> Caps757     pub fn build(self) -> Caps {
758         self.caps
759     }
760 }
761 
762 #[cfg(test)]
763 mod tests {
764     use super::*;
765     use crate::Array;
766     use crate::Fraction;
767 
768     #[test]
test_simple()769     fn test_simple() {
770         crate::init().unwrap();
771 
772         let mut caps = Caps::new_simple(
773             "foo/bar",
774             &[
775                 ("int", &12),
776                 ("bool", &true),
777                 ("string", &"bla"),
778                 ("fraction", &Fraction::new(1, 2)),
779                 ("array", &Array::new(&[&1, &2])),
780             ],
781         );
782         assert_eq!(
783             caps.to_string(),
784             "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >"
785         );
786 
787         {
788             let s = caps.structure(0).unwrap();
789             assert_eq!(
790                 s,
791                 Structure::new(
792                     "foo/bar",
793                     &[
794                         ("int", &12),
795                         ("bool", &true),
796                         ("string", &"bla"),
797                         ("fraction", &Fraction::new(1, 2)),
798                         ("array", &Array::new(&[&1, &2])),
799                     ],
800                 )
801                 .as_ref()
802             );
803         }
804         assert!(caps
805             .features(0)
806             .unwrap()
807             .is_equal(crate::CAPS_FEATURES_MEMORY_SYSTEM_MEMORY.as_ref()));
808 
809         {
810             let caps = caps.get_mut().unwrap();
811             caps.set_features(0, Some(CapsFeatures::new(&["foo:bla"])));
812         }
813         assert!(caps
814             .features(0)
815             .unwrap()
816             .is_equal(CapsFeatures::new(&["foo:bla"]).as_ref()));
817     }
818 
819     #[test]
test_builder()820     fn test_builder() {
821         crate::init().unwrap();
822 
823         let caps = Caps::builder("foo/bar")
824             .field("int", 12)
825             .field("bool", true)
826             .field("string", "bla")
827             .field("fraction", Fraction::new(1, 2))
828             .field("array", Array::new(&[&1, &2]))
829             .build();
830         assert_eq!(
831             caps.to_string(),
832             "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >"
833         );
834 
835         let caps = Caps::builder("foo/bar")
836             .field("int", &12)
837             .any_features()
838             .build();
839         assert_eq!(caps.to_string(), "foo/bar(ANY), int=(int)12");
840 
841         let caps = Caps::builder("foo/bar")
842             .field("int", &12)
843             .features(&["foo:bla", "foo:baz"])
844             .build();
845         assert_eq!(caps.to_string(), "foo/bar(foo:bla, foo:baz), int=(int)12");
846     }
847 
848     #[test]
test_display()849     fn test_display() {
850         crate::init().unwrap();
851 
852         let caps = Caps::new_simple("foo/bar", &[]);
853         format!("{}", caps);
854     }
855 
856     #[test]
test_builder_full()857     fn test_builder_full() {
858         crate::init().unwrap();
859 
860         let caps = Caps::builder_full()
861             .structure(Structure::builder("audio/x-raw").build())
862             .structure(Structure::builder("video/x-raw").build())
863             .build();
864         assert_eq!(caps.to_string(), "audio/x-raw; video/x-raw");
865 
866         let caps = Caps::builder_full()
867             .structure(
868                 Structure::builder("audio/x-raw")
869                     .field("format", &"S16LE")
870                     .build(),
871             )
872             .structure(Structure::builder("video/x-raw").build())
873             .build();
874         assert_eq!(
875             caps.to_string(),
876             "audio/x-raw, format=(string)S16LE; video/x-raw"
877         );
878 
879         let caps = Caps::builder_full()
880             .structure_with_any_features(Structure::builder("audio/x-raw").build())
881             .structure_with_features(
882                 Structure::builder("video/x-raw").build(),
883                 CapsFeatures::new(&["foo:bla", "foo:baz"]),
884             )
885             .build();
886         assert_eq!(
887             caps.to_string(),
888             "audio/x-raw(ANY); video/x-raw(foo:bla, foo:baz)"
889         );
890     }
891 
892     #[test]
test_builder_full_with_features()893     fn test_builder_full_with_features() {
894         crate::init().unwrap();
895 
896         let caps = Caps::builder_full_with_features(CapsFeatures::new(&["foo:bla"]))
897             .structure(Structure::builder("audio/x-raw").build())
898             .structure_with_features(
899                 Structure::builder("video/x-raw").build(),
900                 CapsFeatures::new(&["foo:baz"]),
901             )
902             .build();
903         assert_eq!(
904             caps.to_string(),
905             "audio/x-raw(foo:bla); video/x-raw(foo:bla, foo:baz)"
906         );
907     }
908 
909     #[test]
test_builder_full_with_any_features()910     fn test_builder_full_with_any_features() {
911         crate::init().unwrap();
912 
913         let caps = Caps::builder_full_with_any_features()
914             .structure(Structure::builder("audio/x-raw").build())
915             .structure(Structure::builder("video/x-raw").build())
916             .build();
917         assert_eq!(caps.to_string(), "audio/x-raw(ANY); video/x-raw(ANY)");
918 
919         let caps = Caps::builder_full_with_any_features()
920             .structure(Structure::builder("audio/x-raw").build())
921             .build();
922         assert_eq!(caps.to_string(), "audio/x-raw(ANY)");
923     }
924 
925     #[test]
test_new_from_iter()926     fn test_new_from_iter() {
927         crate::init().unwrap();
928 
929         let caps = Caps::builder_full_with_any_features()
930             .structure(Structure::builder("audio/x-raw").build())
931             .structure(Structure::builder("video/x-raw").build())
932             .build();
933 
934         let audio = Caps::from_iter(caps.iter().filter(|s| s.name() == "audio/x-raw"));
935         assert_eq!(audio.to_string(), "audio/x-raw");
936 
937         let audio = Caps::from_iter_with_features(
938             caps.iter_with_features()
939                 .filter(|(s, _)| s.name() == "audio/x-raw"),
940         );
941         assert_eq!(audio.to_string(), "audio/x-raw(ANY)");
942     }
943 }
944