1 // Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 use std::borrow::{Borrow, BorrowMut, ToOwned};
10 use std::ffi::CStr;
11 use std::fmt;
12 use std::marker::PhantomData;
13 use std::mem;
14 use std::ops::{Deref, DerefMut};
15 use std::ptr;
16 use std::str;
17 
18 use glib;
19 use glib::translate::{
20     from_glib, from_glib_full, FromGlibPtrFull, FromGlibPtrNone, GlibPtrDefault, Stash, StashMut,
21     ToGlibPtr, ToGlibPtrMut,
22 };
23 use glib_sys::gpointer;
24 use gobject_sys;
25 use gst_sys;
26 
27 pub struct CapsFeatures(ptr::NonNull<CapsFeaturesRef>, PhantomData<CapsFeaturesRef>);
28 unsafe impl Send for CapsFeatures {}
29 unsafe impl Sync for CapsFeatures {}
30 
31 impl CapsFeatures {
new(features: &[&str]) -> Self32     pub fn new(features: &[&str]) -> Self {
33         let mut f = Self::new_empty();
34 
35         for feature in features {
36             f.add(feature);
37         }
38 
39         f
40     }
41 
new_empty() -> Self42     pub fn new_empty() -> Self {
43         assert_initialized_main_thread!();
44         unsafe {
45             CapsFeatures(
46                 ptr::NonNull::new_unchecked(
47                     gst_sys::gst_caps_features_new_empty() as *mut CapsFeaturesRef
48                 ),
49                 PhantomData,
50             )
51         }
52     }
53 
new_any() -> Self54     pub fn new_any() -> Self {
55         assert_initialized_main_thread!();
56         unsafe {
57             CapsFeatures(
58                 ptr::NonNull::new_unchecked(
59                     gst_sys::gst_caps_features_new_any() as *mut CapsFeaturesRef
60                 ),
61                 PhantomData,
62             )
63         }
64     }
65 
into_ptr(self) -> *mut gst_sys::GstCapsFeatures66     pub unsafe fn into_ptr(self) -> *mut gst_sys::GstCapsFeatures {
67         let s = mem::ManuallyDrop::new(self);
68         let ptr = s.0.as_ptr() as *mut CapsFeaturesRef as *mut gst_sys::GstCapsFeatures;
69 
70         ptr
71     }
72 }
73 
74 impl Deref for CapsFeatures {
75     type Target = CapsFeaturesRef;
76 
deref(&self) -> &CapsFeaturesRef77     fn deref(&self) -> &CapsFeaturesRef {
78         unsafe { self.0.as_ref() }
79     }
80 }
81 
82 impl DerefMut for CapsFeatures {
deref_mut(&mut self) -> &mut CapsFeaturesRef83     fn deref_mut(&mut self) -> &mut CapsFeaturesRef {
84         unsafe { self.0.as_mut() }
85     }
86 }
87 
88 impl AsRef<CapsFeaturesRef> for CapsFeatures {
as_ref(&self) -> &CapsFeaturesRef89     fn as_ref(&self) -> &CapsFeaturesRef {
90         self.deref()
91     }
92 }
93 
94 impl AsMut<CapsFeaturesRef> for CapsFeatures {
as_mut(&mut self) -> &mut CapsFeaturesRef95     fn as_mut(&mut self) -> &mut CapsFeaturesRef {
96         self.deref_mut()
97     }
98 }
99 
100 impl Clone for CapsFeatures {
clone(&self) -> Self101     fn clone(&self) -> Self {
102         unsafe {
103             let ptr = gst_sys::gst_caps_features_copy(&self.0.as_ref().0) as *mut CapsFeaturesRef;
104             assert!(!ptr.is_null());
105             CapsFeatures(ptr::NonNull::new_unchecked(ptr), PhantomData)
106         }
107     }
108 }
109 
110 impl Drop for CapsFeatures {
drop(&mut self)111     fn drop(&mut self) {
112         unsafe { gst_sys::gst_caps_features_free(&mut self.0.as_mut().0) }
113     }
114 }
115 
116 impl fmt::Debug for CapsFeatures {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result117     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118         f.debug_tuple("CapsFeatures")
119             .field(&self.to_string())
120             .finish()
121     }
122 }
123 
124 impl fmt::Display for CapsFeatures {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result125     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126         // Need to make sure to not call ToString::to_string() here, which
127         // we have because of the Display impl. We need CapsFeaturesRef::to_string()
128         f.write_str(&CapsFeaturesRef::to_string(self.as_ref()))
129     }
130 }
131 
132 impl str::FromStr for CapsFeatures {
133     type Err = glib::BoolError;
134 
from_str(s: &str) -> Result<Self, glib::BoolError>135     fn from_str(s: &str) -> Result<Self, glib::BoolError> {
136         assert_initialized_main_thread!();
137         unsafe {
138             let ptr = gst_sys::gst_caps_features_from_string(s.to_glib_none().0);
139             if ptr.is_null() {
140                 return Err(glib_bool_error!(
141                     "Failed to parse caps features from string"
142                 ));
143             }
144 
145             Ok(CapsFeatures(
146                 ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
147                 PhantomData,
148             ))
149         }
150     }
151 }
152 
153 impl Borrow<CapsFeaturesRef> for CapsFeatures {
borrow(&self) -> &CapsFeaturesRef154     fn borrow(&self) -> &CapsFeaturesRef {
155         unsafe { self.0.as_ref() }
156     }
157 }
158 
159 impl BorrowMut<CapsFeaturesRef> for CapsFeatures {
borrow_mut(&mut self) -> &mut CapsFeaturesRef160     fn borrow_mut(&mut self) -> &mut CapsFeaturesRef {
161         unsafe { self.0.as_mut() }
162     }
163 }
164 
165 impl glib::types::StaticType for CapsFeatures {
static_type() -> glib::types::Type166     fn static_type() -> glib::types::Type {
167         unsafe { from_glib(gst_sys::gst_caps_features_get_type()) }
168     }
169 }
170 
171 impl<'a> ToGlibPtr<'a, *const gst_sys::GstCapsFeatures> for CapsFeatures {
172     type Storage = &'a Self;
173 
to_glib_none(&'a self) -> Stash<'a, *const gst_sys::GstCapsFeatures, Self>174     fn to_glib_none(&'a self) -> Stash<'a, *const gst_sys::GstCapsFeatures, Self> {
175         unsafe { Stash(&self.0.as_ref().0, self) }
176     }
177 
to_glib_full(&self) -> *const gst_sys::GstCapsFeatures178     fn to_glib_full(&self) -> *const gst_sys::GstCapsFeatures {
179         unsafe { gst_sys::gst_caps_features_copy(&self.0.as_ref().0) }
180     }
181 }
182 
183 impl<'a> ToGlibPtr<'a, *mut gst_sys::GstCapsFeatures> for CapsFeatures {
184     type Storage = &'a Self;
185 
to_glib_none(&'a self) -> Stash<'a, *mut gst_sys::GstCapsFeatures, Self>186     fn to_glib_none(&'a self) -> Stash<'a, *mut gst_sys::GstCapsFeatures, Self> {
187         unsafe { Stash(&self.0.as_ref().0 as *const _ as *mut _, self) }
188     }
189 
to_glib_full(&self) -> *mut gst_sys::GstCapsFeatures190     fn to_glib_full(&self) -> *mut gst_sys::GstCapsFeatures {
191         unsafe { gst_sys::gst_caps_features_copy(&self.0.as_ref().0) }
192     }
193 }
194 
195 impl<'a> ToGlibPtrMut<'a, *mut gst_sys::GstCapsFeatures> for CapsFeatures {
196     type Storage = &'a mut Self;
197 
to_glib_none_mut(&'a mut self) -> StashMut<*mut gst_sys::GstCapsFeatures, Self>198     fn to_glib_none_mut(&'a mut self) -> StashMut<*mut gst_sys::GstCapsFeatures, Self> {
199         unsafe { StashMut(&mut self.0.as_mut().0, self) }
200     }
201 }
202 
203 impl FromGlibPtrNone<*const gst_sys::GstCapsFeatures> for CapsFeatures {
from_glib_none(ptr: *const gst_sys::GstCapsFeatures) -> Self204     unsafe fn from_glib_none(ptr: *const gst_sys::GstCapsFeatures) -> Self {
205         assert!(!ptr.is_null());
206         let ptr = gst_sys::gst_caps_features_copy(ptr);
207         assert!(!ptr.is_null());
208         CapsFeatures(
209             ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
210             PhantomData,
211         )
212     }
213 }
214 
215 impl FromGlibPtrNone<*mut gst_sys::GstCapsFeatures> for CapsFeatures {
from_glib_none(ptr: *mut gst_sys::GstCapsFeatures) -> Self216     unsafe fn from_glib_none(ptr: *mut gst_sys::GstCapsFeatures) -> Self {
217         assert!(!ptr.is_null());
218         let ptr = gst_sys::gst_caps_features_copy(ptr);
219         assert!(!ptr.is_null());
220         CapsFeatures(
221             ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
222             PhantomData,
223         )
224     }
225 }
226 
227 impl FromGlibPtrFull<*const gst_sys::GstCapsFeatures> for CapsFeatures {
from_glib_full(ptr: *const gst_sys::GstCapsFeatures) -> Self228     unsafe fn from_glib_full(ptr: *const gst_sys::GstCapsFeatures) -> Self {
229         assert!(!ptr.is_null());
230         CapsFeatures(
231             ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
232             PhantomData,
233         )
234     }
235 }
236 
237 impl FromGlibPtrFull<*mut gst_sys::GstCapsFeatures> for CapsFeatures {
from_glib_full(ptr: *mut gst_sys::GstCapsFeatures) -> Self238     unsafe fn from_glib_full(ptr: *mut gst_sys::GstCapsFeatures) -> Self {
239         assert!(!ptr.is_null());
240         CapsFeatures(
241             ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
242             PhantomData,
243         )
244     }
245 }
246 
247 impl<'a> glib::value::FromValueOptional<'a> for CapsFeatures {
from_value_optional(v: &'a glib::Value) -> Option<Self>248     unsafe fn from_value_optional(v: &'a glib::Value) -> Option<Self> {
249         <&'a CapsFeaturesRef as glib::value::FromValueOptional<'a>>::from_value_optional(v)
250             .map(ToOwned::to_owned)
251     }
252 }
253 
254 impl glib::value::SetValue for CapsFeatures {
set_value(v: &mut glib::Value, s: &Self)255     unsafe fn set_value(v: &mut glib::Value, s: &Self) {
256         <CapsFeaturesRef as glib::value::SetValue>::set_value(v, s.as_ref())
257     }
258 }
259 
260 impl glib::value::SetValueOptional for CapsFeatures {
set_value_optional(v: &mut glib::Value, s: Option<&Self>)261     unsafe fn set_value_optional(v: &mut glib::Value, s: Option<&Self>) {
262         <CapsFeaturesRef as glib::value::SetValueOptional>::set_value_optional(
263             v,
264             s.map(|s| s.as_ref()),
265         )
266     }
267 }
268 
269 impl GlibPtrDefault for CapsFeatures {
270     type GlibType = *mut gst_sys::GstCapsFeatures;
271 }
272 
273 #[repr(C)]
274 pub struct CapsFeaturesRef(gst_sys::GstCapsFeatures);
275 
276 impl CapsFeaturesRef {
from_glib_borrow<'a>( ptr: *const gst_sys::GstCapsFeatures, ) -> &'a CapsFeaturesRef277     pub unsafe fn from_glib_borrow<'a>(
278         ptr: *const gst_sys::GstCapsFeatures,
279     ) -> &'a CapsFeaturesRef {
280         assert!(!ptr.is_null());
281 
282         &*(ptr as *mut CapsFeaturesRef)
283     }
284 
from_glib_borrow_mut<'a>( ptr: *mut gst_sys::GstCapsFeatures, ) -> &'a mut CapsFeaturesRef285     pub unsafe fn from_glib_borrow_mut<'a>(
286         ptr: *mut gst_sys::GstCapsFeatures,
287     ) -> &'a mut CapsFeaturesRef {
288         assert!(!ptr.is_null());
289 
290         &mut *(ptr as *mut CapsFeaturesRef)
291     }
292 
as_ptr(&self) -> *const gst_sys::GstCapsFeatures293     pub unsafe fn as_ptr(&self) -> *const gst_sys::GstCapsFeatures {
294         self as *const Self as *const gst_sys::GstCapsFeatures
295     }
296 
as_mut_ptr(&self) -> *mut gst_sys::GstCapsFeatures297     pub unsafe fn as_mut_ptr(&self) -> *mut gst_sys::GstCapsFeatures {
298         self as *const Self as *mut gst_sys::GstCapsFeatures
299     }
300 
is_empty(&self) -> bool301     pub fn is_empty(&self) -> bool {
302         self.get_size() == 0 && !self.is_any()
303     }
304 
is_any(&self) -> bool305     pub fn is_any(&self) -> bool {
306         unsafe { from_glib(gst_sys::gst_caps_features_is_any(self.as_ptr())) }
307     }
308 
contains(&self, feature: &str) -> bool309     pub fn contains(&self, feature: &str) -> bool {
310         unsafe {
311             from_glib(gst_sys::gst_caps_features_contains(
312                 self.as_ptr(),
313                 feature.to_glib_none().0,
314             ))
315         }
316     }
317 
get_size(&self) -> u32318     pub fn get_size(&self) -> u32 {
319         unsafe { gst_sys::gst_caps_features_get_size(self.as_ptr()) }
320     }
321 
get_nth(&self, idx: u32) -> Option<&str>322     pub fn get_nth(&self, idx: u32) -> Option<&str> {
323         if idx >= self.get_size() {
324             return None;
325         }
326 
327         unsafe {
328             let feature = gst_sys::gst_caps_features_get_nth(self.as_ptr(), idx);
329             if feature.is_null() {
330                 return None;
331             }
332 
333             Some(CStr::from_ptr(feature).to_str().unwrap())
334         }
335     }
336 
add(&mut self, feature: &str)337     pub fn add(&mut self, feature: &str) {
338         unsafe { gst_sys::gst_caps_features_add(self.as_mut_ptr(), feature.to_glib_none().0) }
339     }
340 
remove(&mut self, feature: &str)341     pub fn remove(&mut self, feature: &str) {
342         unsafe { gst_sys::gst_caps_features_remove(self.as_mut_ptr(), feature.to_glib_none().0) }
343     }
344 
iter(&self) -> Iter345     pub fn iter(&self) -> Iter {
346         Iter::new(self)
347     }
348 
349     // This is not an equivalence relation with regards to ANY. Everything is equal to ANY
is_equal(&self, other: &CapsFeaturesRef) -> bool350     pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool {
351         unsafe {
352             from_glib(gst_sys::gst_caps_features_is_equal(
353                 self.as_ptr(),
354                 other.as_ptr(),
355             ))
356         }
357     }
358 }
359 
360 impl glib::types::StaticType for CapsFeaturesRef {
static_type() -> glib::types::Type361     fn static_type() -> glib::types::Type {
362         unsafe { from_glib(gst_sys::gst_structure_get_type()) }
363     }
364 }
365 
366 impl<'a> glib::value::FromValueOptional<'a> for &'a CapsFeaturesRef {
from_value_optional(v: &'a glib::Value) -> Option<Self>367     unsafe fn from_value_optional(v: &'a glib::Value) -> Option<Self> {
368         let ptr = gobject_sys::g_value_get_boxed(v.to_glib_none().0);
369         if ptr.is_null() {
370             None
371         } else {
372             Some(CapsFeaturesRef::from_glib_borrow(
373                 ptr as *const gst_sys::GstCapsFeatures,
374             ))
375         }
376     }
377 }
378 
379 impl glib::value::SetValue for CapsFeaturesRef {
set_value(v: &mut glib::Value, s: &Self)380     unsafe fn set_value(v: &mut glib::Value, s: &Self) {
381         gobject_sys::g_value_set_boxed(v.to_glib_none_mut().0, s.as_ptr() as gpointer);
382     }
383 }
384 
385 impl glib::value::SetValueOptional for CapsFeaturesRef {
set_value_optional(v: &mut glib::Value, s: Option<&Self>)386     unsafe fn set_value_optional(v: &mut glib::Value, s: Option<&Self>) {
387         if let Some(s) = s {
388             gobject_sys::g_value_set_boxed(v.to_glib_none_mut().0, s.as_ptr() as gpointer);
389         } else {
390             gobject_sys::g_value_set_boxed(v.to_glib_none_mut().0, ptr::null_mut());
391         }
392     }
393 }
394 
395 #[derive(Debug)]
396 pub struct Iter<'a> {
397     caps_features: &'a CapsFeaturesRef,
398     idx: u32,
399     n_features: u32,
400 }
401 
402 impl<'a> Iter<'a> {
new(caps_features: &'a CapsFeaturesRef) -> Iter<'a>403     fn new(caps_features: &'a CapsFeaturesRef) -> Iter<'a> {
404         skip_assert_initialized!();
405         let n_features = caps_features.get_size();
406 
407         Iter {
408             caps_features,
409             idx: 0,
410             n_features,
411         }
412     }
413 }
414 
415 impl<'a> Iterator for Iter<'a> {
416     type Item = &'a str;
417 
next(&mut self) -> Option<Self::Item>418     fn next(&mut self) -> Option<Self::Item> {
419         if self.idx >= self.n_features {
420             return None;
421         }
422 
423         unsafe {
424             let feature = gst_sys::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.idx);
425             if feature.is_null() {
426                 return None;
427             }
428 
429             self.idx += 1;
430 
431             Some(CStr::from_ptr(feature).to_str().unwrap())
432         }
433     }
434 
size_hint(&self) -> (usize, Option<usize>)435     fn size_hint(&self) -> (usize, Option<usize>) {
436         if self.idx == self.n_features {
437             return (0, Some(0));
438         }
439 
440         let remaining = (self.n_features - self.idx) as usize;
441 
442         (remaining, Some(remaining))
443     }
444 }
445 
446 impl<'a> DoubleEndedIterator for Iter<'a> {
next_back(&mut self) -> Option<Self::Item>447     fn next_back(&mut self) -> Option<Self::Item> {
448         if self.idx == self.n_features {
449             return None;
450         }
451 
452         self.n_features -= 1;
453 
454         unsafe {
455             let feature =
456                 gst_sys::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.n_features);
457             if feature.is_null() {
458                 return None;
459             }
460 
461             Some(CStr::from_ptr(feature).to_str().unwrap())
462         }
463     }
464 }
465 
466 impl<'a> ExactSizeIterator for Iter<'a> {}
467 
468 impl fmt::Debug for CapsFeaturesRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result469     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
470         f.debug_tuple("CapsFeatures")
471             .field(&self.to_string())
472             .finish()
473     }
474 }
475 
476 impl fmt::Display for CapsFeaturesRef {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result477     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
478         let s = unsafe {
479             glib::GString::from_glib_full(gst_sys::gst_caps_features_to_string(self.as_ptr()))
480         };
481         f.write_str(&s)
482     }
483 }
484 
485 impl ToOwned for CapsFeaturesRef {
486     type Owned = CapsFeatures;
487 
to_owned(&self) -> CapsFeatures488     fn to_owned(&self) -> CapsFeatures {
489         unsafe {
490             from_glib_full(gst_sys::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _)
491         }
492     }
493 }
494 
495 unsafe impl Sync for CapsFeaturesRef {}
496 unsafe impl Send for CapsFeaturesRef {}
497 
498 lazy_static! {
499     pub static ref CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: &'static str = unsafe {
500         CStr::from_ptr(gst_sys::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)
501             .to_str()
502             .unwrap()
503     };
504     pub static ref CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: CapsFeatures =
505         CapsFeatures::new(&[*CAPS_FEATURE_MEMORY_SYSTEM_MEMORY]);
506 }
507 
508 #[cfg(test)]
509 mod tests {
510     use super::*;
511 
512     #[test]
test_from_value_optional()513     fn test_from_value_optional() {
514         ::init().unwrap();
515 
516         let a = glib::value::Value::from(None::<&CapsFeatures>);
517         assert!(a.get::<CapsFeatures>().unwrap().is_none());
518         let b = glib::value::Value::from(&CapsFeatures::new_empty());
519         assert!(b.get::<CapsFeatures>().unwrap().is_some());
520     }
521 }
522