1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use std::borrow::{Borrow, BorrowMut, ToOwned};
4 use std::ffi::CStr;
5 use std::fmt;
6 use std::mem;
7 use std::ops::{Deref, DerefMut};
8 use std::ptr;
9 use std::str;
10 
11 use once_cell::sync::Lazy;
12 
13 use glib::translate::*;
14 use glib::StaticType;
15 
16 #[doc(alias = "GstCapsFeatures")]
17 pub struct CapsFeatures(ptr::NonNull<ffi::GstCapsFeatures>);
18 unsafe impl Send for CapsFeatures {}
19 unsafe impl Sync for CapsFeatures {}
20 
21 impl CapsFeatures {
new(features: &[&str]) -> Self22     pub fn new(features: &[&str]) -> Self {
23         assert_initialized_main_thread!();
24         let mut f = Self::new_empty();
25 
26         for feature in features {
27             f.add(feature);
28         }
29 
30         f
31     }
32 
from_quarks(features: &[glib::Quark]) -> Self33     pub fn from_quarks(features: &[glib::Quark]) -> Self {
34         assert_initialized_main_thread!();
35         let mut f = Self::new_empty();
36 
37         for feature in features {
38             f.add_from_quark(*feature);
39         }
40 
41         f
42     }
43 
44     #[doc(alias = "gst_caps_features_new_empty")]
new_empty() -> Self45     pub fn new_empty() -> Self {
46         assert_initialized_main_thread!();
47         unsafe {
48             CapsFeatures(ptr::NonNull::new_unchecked(
49                 ffi::gst_caps_features_new_empty(),
50             ))
51         }
52     }
53 
54     #[doc(alias = "gst_caps_features_new_any")]
new_any() -> Self55     pub fn new_any() -> Self {
56         assert_initialized_main_thread!();
57         unsafe { CapsFeatures(ptr::NonNull::new_unchecked(ffi::gst_caps_features_new_any())) }
58     }
59 
into_ptr(self) -> *mut ffi::GstCapsFeatures60     pub unsafe fn into_ptr(self) -> *mut ffi::GstCapsFeatures {
61         let s = mem::ManuallyDrop::new(self);
62         s.0.as_ptr()
63     }
64 }
65 
66 impl Deref for CapsFeatures {
67     type Target = CapsFeaturesRef;
68 
deref(&self) -> &CapsFeaturesRef69     fn deref(&self) -> &CapsFeaturesRef {
70         unsafe { &*(self.0.as_ref() as *const ffi::GstCapsFeatures as *const CapsFeaturesRef) }
71     }
72 }
73 
74 impl DerefMut for CapsFeatures {
deref_mut(&mut self) -> &mut CapsFeaturesRef75     fn deref_mut(&mut self) -> &mut CapsFeaturesRef {
76         unsafe { &mut *(self.0.as_mut() as *mut ffi::GstCapsFeatures as *mut CapsFeaturesRef) }
77     }
78 }
79 
80 impl AsRef<CapsFeaturesRef> for CapsFeatures {
as_ref(&self) -> &CapsFeaturesRef81     fn as_ref(&self) -> &CapsFeaturesRef {
82         self.deref()
83     }
84 }
85 
86 impl AsMut<CapsFeaturesRef> for CapsFeatures {
as_mut(&mut self) -> &mut CapsFeaturesRef87     fn as_mut(&mut self) -> &mut CapsFeaturesRef {
88         self.deref_mut()
89     }
90 }
91 
92 impl Clone for CapsFeatures {
clone(&self) -> Self93     fn clone(&self) -> Self {
94         unsafe {
95             let ptr = ffi::gst_caps_features_copy(self.0.as_ref());
96             assert!(!ptr.is_null());
97             CapsFeatures(ptr::NonNull::new_unchecked(ptr))
98         }
99     }
100 }
101 
102 impl Drop for CapsFeatures {
drop(&mut self)103     fn drop(&mut self) {
104         unsafe { ffi::gst_caps_features_free(self.0.as_mut()) }
105     }
106 }
107 
108 impl fmt::Debug for CapsFeatures {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result109     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110         f.debug_tuple("CapsFeatures")
111             .field(&self.to_string())
112             .finish()
113     }
114 }
115 
116 impl fmt::Display for CapsFeatures {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result117     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118         // Need to make sure to not call ToString::to_string() here, which
119         // we have because of the Display impl. We need CapsFeaturesRef::to_string()
120         f.write_str(&CapsFeaturesRef::to_string(self.as_ref()))
121     }
122 }
123 
124 impl str::FromStr for CapsFeatures {
125     type Err = glib::BoolError;
126 
127     #[doc(alias = "gst_caps_features_from_string")]
from_str(s: &str) -> Result<Self, Self::Err>128     fn from_str(s: &str) -> Result<Self, Self::Err> {
129         assert_initialized_main_thread!();
130         unsafe {
131             let ptr = ffi::gst_caps_features_from_string(s.to_glib_none().0);
132             if ptr.is_null() {
133                 return Err(glib::bool_error!(
134                     "Failed to parse caps features from string"
135                 ));
136             }
137 
138             Ok(Self(ptr::NonNull::new_unchecked(ptr)))
139         }
140     }
141 }
142 
143 impl Borrow<CapsFeaturesRef> for CapsFeatures {
borrow(&self) -> &CapsFeaturesRef144     fn borrow(&self) -> &CapsFeaturesRef {
145         self.as_ref()
146     }
147 }
148 
149 impl BorrowMut<CapsFeaturesRef> for CapsFeatures {
borrow_mut(&mut self) -> &mut CapsFeaturesRef150     fn borrow_mut(&mut self) -> &mut CapsFeaturesRef {
151         self.as_mut()
152     }
153 }
154 
155 impl glib::types::StaticType for CapsFeatures {
static_type() -> glib::types::Type156     fn static_type() -> glib::types::Type {
157         unsafe { from_glib(ffi::gst_caps_features_get_type()) }
158     }
159 }
160 
161 impl<'a> ToGlibPtr<'a, *const ffi::GstCapsFeatures> for CapsFeatures {
162     type Storage = &'a Self;
163 
to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self>164     fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self> {
165         unsafe { Stash(self.0.as_ref(), self) }
166     }
167 
to_glib_full(&self) -> *const ffi::GstCapsFeatures168     fn to_glib_full(&self) -> *const ffi::GstCapsFeatures {
169         unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) }
170     }
171 }
172 
173 impl<'a> ToGlibPtr<'a, *mut ffi::GstCapsFeatures> for CapsFeatures {
174     type Storage = &'a Self;
175 
to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self>176     fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self> {
177         unsafe {
178             Stash(
179                 self.0.as_ref() as *const ffi::GstCapsFeatures as *mut ffi::GstCapsFeatures,
180                 self,
181             )
182         }
183     }
184 
to_glib_full(&self) -> *mut ffi::GstCapsFeatures185     fn to_glib_full(&self) -> *mut ffi::GstCapsFeatures {
186         unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) }
187     }
188 }
189 
190 impl<'a> ToGlibPtrMut<'a, *mut ffi::GstCapsFeatures> for CapsFeatures {
191     type Storage = &'a mut Self;
192 
to_glib_none_mut(&'a mut self) -> StashMut<*mut ffi::GstCapsFeatures, Self>193     fn to_glib_none_mut(&'a mut self) -> StashMut<*mut ffi::GstCapsFeatures, Self> {
194         unsafe { StashMut(self.0.as_mut(), self) }
195     }
196 }
197 
198 impl FromGlibPtrNone<*const ffi::GstCapsFeatures> for CapsFeatures {
from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self199     unsafe fn from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self {
200         assert!(!ptr.is_null());
201         let ptr = ffi::gst_caps_features_copy(ptr);
202         assert!(!ptr.is_null());
203         CapsFeatures(ptr::NonNull::new_unchecked(ptr))
204     }
205 }
206 
207 impl FromGlibPtrNone<*mut ffi::GstCapsFeatures> for CapsFeatures {
from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self208     unsafe fn from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self {
209         assert!(!ptr.is_null());
210         let ptr = ffi::gst_caps_features_copy(ptr);
211         assert!(!ptr.is_null());
212         CapsFeatures(ptr::NonNull::new_unchecked(ptr))
213     }
214 }
215 
216 impl FromGlibPtrFull<*const ffi::GstCapsFeatures> for CapsFeatures {
from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self217     unsafe fn from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self {
218         assert!(!ptr.is_null());
219         CapsFeatures(ptr::NonNull::new_unchecked(
220             ptr as *mut ffi::GstCapsFeatures,
221         ))
222     }
223 }
224 
225 impl FromGlibPtrFull<*mut ffi::GstCapsFeatures> for CapsFeatures {
from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self226     unsafe fn from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self {
227         assert!(!ptr.is_null());
228         CapsFeatures(ptr::NonNull::new_unchecked(ptr))
229     }
230 }
231 
232 impl glib::value::ValueType for CapsFeatures {
233     type Type = Self;
234 }
235 
236 unsafe impl<'a> glib::value::FromValue<'a> for CapsFeatures {
237     type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
238 
from_value(value: &'a glib::Value) -> Self239     unsafe fn from_value(value: &'a glib::Value) -> Self {
240         skip_assert_initialized!();
241         from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0)
242             as *mut ffi::GstCapsFeatures)
243     }
244 }
245 
246 impl glib::value::ToValue for CapsFeatures {
to_value(&self) -> glib::Value247     fn to_value(&self) -> glib::Value {
248         let mut value = glib::Value::for_value_type::<Self>();
249         unsafe {
250             glib::gobject_ffi::g_value_set_boxed(
251                 value.to_glib_none_mut().0,
252                 ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(self).0 as *mut _,
253             )
254         }
255         value
256     }
257 
value_type(&self) -> glib::Type258     fn value_type(&self) -> glib::Type {
259         Self::static_type()
260     }
261 }
262 
263 impl glib::value::ToValueOptional for CapsFeatures {
to_value_optional(s: Option<&Self>) -> glib::Value264     fn to_value_optional(s: Option<&Self>) -> glib::Value {
265         skip_assert_initialized!();
266         let mut value = glib::Value::for_value_type::<Self>();
267         unsafe {
268             glib::gobject_ffi::g_value_set_boxed(
269                 value.to_glib_none_mut().0,
270                 ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(&s).0 as *mut _,
271             )
272         }
273         value
274     }
275 }
276 
277 impl GlibPtrDefault for CapsFeatures {
278     type GlibType = *mut ffi::GstCapsFeatures;
279 }
280 
281 #[repr(transparent)]
282 #[doc(alias = "GstCapsFeatures")]
283 pub struct CapsFeaturesRef(ffi::GstCapsFeatures);
284 
285 impl CapsFeaturesRef {
from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef286     pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef {
287         assert!(!ptr.is_null());
288 
289         &*(ptr as *mut CapsFeaturesRef)
290     }
291 
from_glib_borrow_mut<'a>( ptr: *mut ffi::GstCapsFeatures, ) -> &'a mut CapsFeaturesRef292     pub unsafe fn from_glib_borrow_mut<'a>(
293         ptr: *mut ffi::GstCapsFeatures,
294     ) -> &'a mut CapsFeaturesRef {
295         assert!(!ptr.is_null());
296 
297         &mut *(ptr as *mut CapsFeaturesRef)
298     }
299 
as_ptr(&self) -> *const ffi::GstCapsFeatures300     pub unsafe fn as_ptr(&self) -> *const ffi::GstCapsFeatures {
301         self as *const Self as *const ffi::GstCapsFeatures
302     }
303 
as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures304     pub unsafe fn as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures {
305         self as *const Self as *mut ffi::GstCapsFeatures
306     }
307 
is_empty(&self) -> bool308     pub fn is_empty(&self) -> bool {
309         self.size() == 0 && !self.is_any()
310     }
311 
312     #[doc(alias = "gst_caps_features_is_any")]
is_any(&self) -> bool313     pub fn is_any(&self) -> bool {
314         unsafe { from_glib(ffi::gst_caps_features_is_any(self.as_ptr())) }
315     }
316 
317     #[doc(alias = "gst_caps_features_contains")]
contains(&self, feature: &str) -> bool318     pub fn contains(&self, feature: &str) -> bool {
319         unsafe {
320             from_glib(ffi::gst_caps_features_contains(
321                 self.as_ptr(),
322                 feature.to_glib_none().0,
323             ))
324         }
325     }
326 
contains_quark(&self, feature: glib::Quark) -> bool327     pub fn contains_quark(&self, feature: glib::Quark) -> bool {
328         unsafe {
329             from_glib(ffi::gst_caps_features_contains_id(
330                 self.as_ptr(),
331                 feature.into_glib(),
332             ))
333         }
334     }
335 
336     #[doc(alias = "get_size")]
337     #[doc(alias = "gst_caps_features_get_size")]
size(&self) -> u32338     pub fn size(&self) -> u32 {
339         unsafe { ffi::gst_caps_features_get_size(self.as_ptr()) }
340     }
341 
342     #[doc(alias = "get_nth")]
343     #[doc(alias = "gst_caps_features_get_nth")]
nth(&self, idx: u32) -> Option<&str>344     pub fn nth(&self, idx: u32) -> Option<&str> {
345         if idx >= self.size() {
346             return None;
347         }
348 
349         unsafe {
350             let feature = ffi::gst_caps_features_get_nth(self.as_ptr(), idx);
351             if feature.is_null() {
352                 return None;
353             }
354 
355             Some(CStr::from_ptr(feature).to_str().unwrap())
356         }
357     }
358 
nth_quark(&self, idx: u32) -> Option<glib::Quark>359     pub fn nth_quark(&self, idx: u32) -> Option<glib::Quark> {
360         if idx >= self.size() {
361             return None;
362         }
363 
364         unsafe {
365             let feature = ffi::gst_caps_features_get_nth_id(self.as_ptr(), idx);
366             Some(from_glib(feature))
367         }
368     }
369 
370     #[doc(alias = "gst_caps_features_add")]
add(&mut self, feature: &str)371     pub fn add(&mut self, feature: &str) {
372         unsafe { ffi::gst_caps_features_add(self.as_mut_ptr(), feature.to_glib_none().0) }
373     }
374 
375     #[doc(alias = "gst_caps_features_remove")]
remove(&mut self, feature: &str)376     pub fn remove(&mut self, feature: &str) {
377         unsafe { ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.to_glib_none().0) }
378     }
379 
add_from_quark(&mut self, feature: glib::Quark)380     pub fn add_from_quark(&mut self, feature: glib::Quark) {
381         unsafe { ffi::gst_caps_features_add_id(self.as_mut_ptr(), feature.into_glib()) }
382     }
383 
remove_by_quark(&mut self, feature: glib::Quark)384     pub fn remove_by_quark(&mut self, feature: glib::Quark) {
385         unsafe { ffi::gst_caps_features_remove_id(self.as_mut_ptr(), feature.into_glib()) }
386     }
387 
iter(&self) -> Iter388     pub fn iter(&self) -> Iter {
389         Iter::new(self)
390     }
391 
392     // This is not an equivalence relation with regards to ANY. Everything is equal to ANY
393     #[doc(alias = "gst_caps_features_is_equal")]
is_equal(&self, other: &CapsFeaturesRef) -> bool394     pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool {
395         unsafe {
396             from_glib(ffi::gst_caps_features_is_equal(
397                 self.as_ptr(),
398                 other.as_ptr(),
399             ))
400         }
401     }
402 }
403 
404 impl glib::types::StaticType for CapsFeaturesRef {
static_type() -> glib::types::Type405     fn static_type() -> glib::types::Type {
406         unsafe { from_glib(ffi::gst_structure_get_type()) }
407     }
408 }
409 
410 unsafe impl<'a> glib::value::FromValue<'a> for &'a CapsFeaturesRef {
411     type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
412 
from_value(value: &'a glib::Value) -> Self413     unsafe fn from_value(value: &'a glib::Value) -> Self {
414         skip_assert_initialized!();
415         &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const CapsFeaturesRef)
416     }
417 }
418 
419 impl glib::value::ToValue for CapsFeaturesRef {
to_value(&self) -> glib::Value420     fn to_value(&self) -> glib::Value {
421         let mut value = glib::Value::for_value_type::<CapsFeatures>();
422         unsafe {
423             glib::gobject_ffi::g_value_set_boxed(
424                 value.to_glib_none_mut().0,
425                 self.as_mut_ptr() as *mut _,
426             )
427         }
428         value
429     }
430 
value_type(&self) -> glib::Type431     fn value_type(&self) -> glib::Type {
432         Self::static_type()
433     }
434 }
435 
436 impl glib::value::ToValueOptional for CapsFeaturesRef {
to_value_optional(s: Option<&Self>) -> glib::Value437     fn to_value_optional(s: Option<&Self>) -> glib::Value {
438         skip_assert_initialized!();
439         let mut value = glib::Value::for_value_type::<CapsFeatures>();
440         unsafe {
441             glib::gobject_ffi::g_value_set_boxed(
442                 value.to_glib_none_mut().0,
443                 s.map(|s| s.as_mut_ptr()).unwrap_or(ptr::null_mut()) as *mut _,
444             )
445         }
446         value
447     }
448 }
449 
450 #[derive(Debug)]
451 pub struct Iter<'a> {
452     caps_features: &'a CapsFeaturesRef,
453     idx: u32,
454     n_features: u32,
455 }
456 
457 impl<'a> Iter<'a> {
new(caps_features: &'a CapsFeaturesRef) -> Iter<'a>458     fn new(caps_features: &'a CapsFeaturesRef) -> Iter<'a> {
459         skip_assert_initialized!();
460         let n_features = caps_features.size();
461 
462         Iter {
463             caps_features,
464             idx: 0,
465             n_features,
466         }
467     }
468 }
469 
470 impl<'a> Iterator for Iter<'a> {
471     type Item = &'a str;
472 
next(&mut self) -> Option<Self::Item>473     fn next(&mut self) -> Option<Self::Item> {
474         if self.idx >= self.n_features {
475             return None;
476         }
477 
478         unsafe {
479             let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.idx);
480             if feature.is_null() {
481                 return None;
482             }
483 
484             self.idx += 1;
485 
486             Some(CStr::from_ptr(feature).to_str().unwrap())
487         }
488     }
489 
size_hint(&self) -> (usize, Option<usize>)490     fn size_hint(&self) -> (usize, Option<usize>) {
491         if self.idx == self.n_features {
492             return (0, Some(0));
493         }
494 
495         let remaining = (self.n_features - self.idx) as usize;
496 
497         (remaining, Some(remaining))
498     }
499 }
500 
501 impl<'a> DoubleEndedIterator for Iter<'a> {
next_back(&mut self) -> Option<Self::Item>502     fn next_back(&mut self) -> Option<Self::Item> {
503         if self.idx == self.n_features {
504             return None;
505         }
506 
507         self.n_features -= 1;
508 
509         unsafe {
510             let feature =
511                 ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.n_features);
512             if feature.is_null() {
513                 return None;
514             }
515 
516             Some(CStr::from_ptr(feature).to_str().unwrap())
517         }
518     }
519 }
520 
521 impl<'a> ExactSizeIterator for Iter<'a> {}
522 
523 impl fmt::Debug for CapsFeaturesRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result524     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
525         f.debug_tuple("CapsFeatures")
526             .field(&self.to_string())
527             .finish()
528     }
529 }
530 
531 impl fmt::Display for CapsFeaturesRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result532     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
533         let s = unsafe {
534             glib::GString::from_glib_full(ffi::gst_caps_features_to_string(self.as_ptr()))
535         };
536         f.write_str(&s)
537     }
538 }
539 
540 impl ToOwned for CapsFeaturesRef {
541     type Owned = CapsFeatures;
542 
to_owned(&self) -> CapsFeatures543     fn to_owned(&self) -> CapsFeatures {
544         unsafe { from_glib_full(ffi::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) }
545     }
546 }
547 
548 unsafe impl Sync for CapsFeaturesRef {}
549 unsafe impl Send for CapsFeaturesRef {}
550 
551 pub static CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: Lazy<&'static str> = Lazy::new(|| unsafe {
552     CStr::from_ptr(ffi::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)
553         .to_str()
554         .unwrap()
555 });
556 pub static CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: Lazy<CapsFeatures> =
557     Lazy::new(|| CapsFeatures::new(&[*CAPS_FEATURE_MEMORY_SYSTEM_MEMORY]));
558 
559 #[cfg(test)]
560 mod tests {
561     use super::*;
562 
563     #[test]
test_from_value_optional()564     fn test_from_value_optional() {
565         use glib::ToValue;
566 
567         crate::init().unwrap();
568 
569         let a = None::<CapsFeatures>.to_value();
570         assert!(a.get::<Option<CapsFeatures>>().unwrap().is_none());
571         let b = glib::value::Value::from(&CapsFeatures::new_empty());
572         assert!(b.get::<Option<CapsFeatures>>().unwrap().is_some());
573     }
574 }
575