// Take a look at the license at the top of the repository in the LICENSE file. use std::{ borrow::{Borrow, BorrowMut, ToOwned}, fmt, marker::PhantomData, mem, ops::{Deref, DerefMut}, ptr, str, }; use glib::{prelude::*, translate::*}; use once_cell::sync::Lazy; #[doc(alias = "GstCapsFeatures")] #[repr(transparent)] pub struct CapsFeatures(ptr::NonNull); unsafe impl Send for CapsFeatures {} unsafe impl Sync for CapsFeatures {} impl CapsFeatures { #[doc(alias = "gst_caps_features_new")] pub fn new(features: impl IntoIterator) -> Self { skip_assert_initialized!(); let mut f = Self::new_empty(); for feature in features { f.add(feature); } f } #[doc(alias = "gst_caps_features_new_id")] pub fn from_quarks(features: impl IntoIterator) -> Self { skip_assert_initialized!(); let mut f = Self::new_empty(); for feature in features.into_iter() { f.add_from_quark(feature); } f } #[doc(alias = "gst_caps_features_new_empty")] pub fn new_empty() -> Self { assert_initialized_main_thread!(); unsafe { CapsFeatures(ptr::NonNull::new_unchecked( ffi::gst_caps_features_new_empty(), )) } } #[doc(alias = "gst_caps_features_new_any")] pub fn new_any() -> Self { assert_initialized_main_thread!(); unsafe { CapsFeatures(ptr::NonNull::new_unchecked(ffi::gst_caps_features_new_any())) } } } impl IntoGlibPtr<*mut ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::GstCapsFeatures { let s = mem::ManuallyDrop::new(self); s.0.as_ptr() } } impl Deref for CapsFeatures { type Target = CapsFeaturesRef; #[inline] fn deref(&self) -> &CapsFeaturesRef { unsafe { &*(self.0.as_ref() as *const ffi::GstCapsFeatures as *const CapsFeaturesRef) } } } impl DerefMut for CapsFeatures { #[inline] fn deref_mut(&mut self) -> &mut CapsFeaturesRef { unsafe { &mut *(self.0.as_mut() as *mut ffi::GstCapsFeatures as *mut CapsFeaturesRef) } } } impl AsRef for CapsFeatures { #[inline] fn as_ref(&self) -> &CapsFeaturesRef { self.deref() } } impl AsMut for CapsFeatures { #[inline] fn as_mut(&mut self) -> &mut CapsFeaturesRef { self.deref_mut() } } impl Clone for CapsFeatures { #[inline] fn clone(&self) -> Self { unsafe { let ptr = ffi::gst_caps_features_copy(self.0.as_ref()); debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } } impl Drop for CapsFeatures { #[inline] fn drop(&mut self) { unsafe { ffi::gst_caps_features_free(self.0.as_mut()) } } } impl fmt::Debug for CapsFeatures { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("CapsFeatures") .field(&self.to_string()) .finish() } } impl fmt::Display for CapsFeatures { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Need to make sure to not call ToString::to_string() here, which // we have because of the Display impl. We need CapsFeaturesRef::to_string() f.write_str(&CapsFeaturesRef::to_string(self.as_ref())) } } impl str::FromStr for CapsFeatures { type Err = glib::BoolError; #[doc(alias = "gst_caps_features_from_string")] fn from_str(s: &str) -> Result { assert_initialized_main_thread!(); unsafe { let ptr = s.run_with_gstr(|s| ffi::gst_caps_features_from_string(s.as_ptr())); if ptr.is_null() { return Err(glib::bool_error!( "Failed to parse caps features from string" )); } Ok(Self(ptr::NonNull::new_unchecked(ptr))) } } } impl Borrow for CapsFeatures { #[inline] fn borrow(&self) -> &CapsFeaturesRef { self.as_ref() } } impl BorrowMut for CapsFeatures { #[inline] fn borrow_mut(&mut self) -> &mut CapsFeaturesRef { self.as_mut() } } impl glib::types::StaticType for CapsFeatures { #[inline] fn static_type() -> glib::types::Type { unsafe { from_glib(ffi::gst_caps_features_get_type()) } } } impl<'a> ToGlibPtr<'a, *const ffi::GstCapsFeatures> for CapsFeatures { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self> { unsafe { Stash(self.0.as_ref(), PhantomData) } } #[inline] fn to_glib_full(&self) -> *const ffi::GstCapsFeatures { unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) } } } impl<'a> ToGlibPtr<'a, *mut ffi::GstCapsFeatures> for CapsFeatures { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self> { unsafe { Stash( self.0.as_ref() as *const ffi::GstCapsFeatures as *mut ffi::GstCapsFeatures, PhantomData, ) } } #[inline] fn to_glib_full(&self) -> *mut ffi::GstCapsFeatures { unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) } } } impl<'a> ToGlibPtrMut<'a, *mut ffi::GstCapsFeatures> for CapsFeatures { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<*mut ffi::GstCapsFeatures, Self> { unsafe { StashMut(self.0.as_mut(), PhantomData) } } } impl FromGlibPtrNone<*const ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); let ptr = ffi::gst_caps_features_copy(ptr); debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } impl FromGlibPtrNone<*mut ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); let ptr = ffi::gst_caps_features_copy(ptr); debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } impl FromGlibPtrFull<*const ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked( ptr as *mut ffi::GstCapsFeatures, )) } } impl FromGlibPtrFull<*mut ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } impl glib::value::ValueType for CapsFeatures { type Type = Self; } impl glib::value::ValueTypeOptional for CapsFeatures {} unsafe impl<'a> glib::value::FromValue<'a> for CapsFeatures { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstCapsFeatures) } } impl glib::value::ToValue for CapsFeatures { fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(self).0 as *mut _, ) } value } fn value_type(&self) -> glib::Type { Self::static_type() } } impl glib::value::ToValueOptional for CapsFeatures { fn to_value_optional(s: Option<&Self>) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(&s).0 as *mut _, ) } value } } impl From for glib::Value { fn from(v: CapsFeatures) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, IntoGlibPtr::<*mut ffi::GstCapsFeatures>::into_glib_ptr(v) as *mut _, ) } value } } impl GlibPtrDefault for CapsFeatures { type GlibType = *mut ffi::GstCapsFeatures; } unsafe impl TransparentPtrType for CapsFeatures {} #[repr(transparent)] #[doc(alias = "GstCapsFeatures")] pub struct CapsFeaturesRef(ffi::GstCapsFeatures); impl CapsFeaturesRef { #[inline] pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef { debug_assert!(!ptr.is_null()); &*(ptr as *mut CapsFeaturesRef) } #[inline] pub unsafe fn from_glib_borrow_mut<'a>( ptr: *mut ffi::GstCapsFeatures, ) -> &'a mut CapsFeaturesRef { debug_assert!(!ptr.is_null()); &mut *(ptr as *mut CapsFeaturesRef) } #[inline] pub fn as_ptr(&self) -> *const ffi::GstCapsFeatures { self as *const Self as *const ffi::GstCapsFeatures } #[inline] pub fn as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures { self as *const Self as *mut ffi::GstCapsFeatures } pub fn is_empty(&self) -> bool { self.size() == 0 && !self.is_any() } #[doc(alias = "gst_caps_features_is_any")] pub fn is_any(&self) -> bool { unsafe { from_glib(ffi::gst_caps_features_is_any(self.as_ptr())) } } #[doc(alias = "gst_caps_features_contains")] pub fn contains(&self, feature: impl IntoGStr) -> bool { unsafe { feature.run_with_gstr(|feature| { from_glib(ffi::gst_caps_features_contains( self.as_ptr(), feature.as_ptr(), )) }) } } #[doc(alias = "gst_caps_features_contains_id")] pub fn contains_quark(&self, feature: glib::Quark) -> bool { unsafe { from_glib(ffi::gst_caps_features_contains_id( self.as_ptr(), feature.into_glib(), )) } } #[doc(alias = "get_size")] #[doc(alias = "gst_caps_features_get_size")] pub fn size(&self) -> u32 { unsafe { ffi::gst_caps_features_get_size(self.as_ptr()) } } #[doc(alias = "get_nth")] #[doc(alias = "gst_caps_features_get_nth")] pub fn nth(&self, idx: u32) -> Option<&glib::GStr> { if idx >= self.size() { return None; } unsafe { let feature = ffi::gst_caps_features_get_nth(self.as_ptr(), idx); if feature.is_null() { return None; } Some(glib::GStr::from_ptr(feature)) } } #[doc(alias = "gst_caps_features_get_nth_id")] pub fn nth_quark(&self, idx: u32) -> Option { if idx >= self.size() { return None; } unsafe { let feature = ffi::gst_caps_features_get_nth_id(self.as_ptr(), idx); Some(from_glib(feature)) } } #[doc(alias = "gst_caps_features_add")] pub fn add(&mut self, feature: impl IntoGStr) { unsafe { feature.run_with_gstr(|feature| { ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ptr()) }) } } #[doc(alias = "gst_caps_features_remove")] pub fn remove(&mut self, feature: impl IntoGStr) { unsafe { feature.run_with_gstr(|feature| { ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.as_ptr()) }) } } #[doc(alias = "gst_caps_features_add_id")] pub fn add_from_quark(&mut self, feature: glib::Quark) { unsafe { ffi::gst_caps_features_add_id(self.as_mut_ptr(), feature.into_glib()) } } #[doc(alias = "gst_caps_features_remove_id")] pub fn remove_by_quark(&mut self, feature: glib::Quark) { unsafe { ffi::gst_caps_features_remove_id(self.as_mut_ptr(), feature.into_glib()) } } pub fn iter(&self) -> Iter { Iter::new(self) } // This is not an equivalence relation with regards to ANY. Everything is equal to ANY #[doc(alias = "gst_caps_features_is_equal")] pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool { unsafe { from_glib(ffi::gst_caps_features_is_equal( self.as_ptr(), other.as_ptr(), )) } } } impl glib::types::StaticType for CapsFeaturesRef { #[inline] fn static_type() -> glib::types::Type { unsafe { from_glib(ffi::gst_structure_get_type()) } } } impl<'a> std::iter::Extend<&'a str> for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(f)); } } impl<'a> std::iter::Extend<&'a glib::GStr> for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(f)); } } impl std::iter::Extend for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(&f)); } } impl std::iter::Extend for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(&f)); } } impl std::iter::Extend for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add_from_quark(f)); } } unsafe impl<'a> glib::value::FromValue<'a> for &'a CapsFeaturesRef { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const CapsFeaturesRef) } } impl glib::value::ToValue for CapsFeaturesRef { fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.as_mut_ptr() as *mut _, ) } value } fn value_type(&self) -> glib::Type { Self::static_type() } } impl glib::value::ToValueOptional for CapsFeaturesRef { fn to_value_optional(s: Option<&Self>) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.map(|s| s.as_mut_ptr()).unwrap_or(ptr::null_mut()) as *mut _, ) } value } } #[derive(Debug)] pub struct Iter<'a> { caps_features: &'a CapsFeaturesRef, idx: usize, n_features: usize, } impl<'a> Iter<'a> { fn new(caps_features: &'a CapsFeaturesRef) -> Iter<'a> { skip_assert_initialized!(); let n_features = caps_features.size(); Iter { caps_features, idx: 0, n_features: n_features as usize, } } } impl<'a> Iterator for Iter<'a> { type Item = &'a glib::GStr; fn next(&mut self) -> Option { if self.idx >= self.n_features { return None; } unsafe { let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.idx as u32); debug_assert!(!feature.is_null()); self.idx += 1; Some(glib::GStr::from_ptr(feature)) } } fn size_hint(&self) -> (usize, Option) { let remaining = self.n_features - self.idx; (remaining, Some(remaining)) } fn count(self) -> usize { self.n_features - self.idx } // checker-ignore-item fn nth(&mut self, n: usize) -> Option { let (end, overflow) = self.idx.overflowing_add(n); if end >= self.n_features || overflow { self.idx = self.n_features; None } else { unsafe { self.idx = end + 1; let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), end as u32); debug_assert!(!feature.is_null()); Some(glib::GStr::from_ptr(feature)) } } } fn last(self) -> Option { if self.idx == self.n_features { None } else { unsafe { let feature = ffi::gst_caps_features_get_nth( self.caps_features.as_ptr(), self.n_features as u32 - 1, ); debug_assert!(!feature.is_null()); Some(glib::GStr::from_ptr(feature)) } } } } impl<'a> DoubleEndedIterator for Iter<'a> { fn next_back(&mut self) -> Option { if self.idx == self.n_features { return None; } self.n_features -= 1; unsafe { let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.n_features as u32); debug_assert!(!feature.is_null()); Some(glib::GStr::from_ptr(feature)) } } fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.n_features.overflowing_sub(n); if end <= self.idx || overflow { self.idx = self.n_features; None } else { unsafe { self.n_features = end - 1; let feature = ffi::gst_caps_features_get_nth( self.caps_features.as_ptr(), self.n_features as u32, ); debug_assert!(!feature.is_null()); Some(glib::GStr::from_ptr(feature)) } } } } impl<'a> ExactSizeIterator for Iter<'a> {} impl<'a> std::iter::FusedIterator for Iter<'a> {} impl<'a> IntoIterator for &'a CapsFeaturesRef { type IntoIter = Iter<'a>; type Item = &'a glib::GStr; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a> From<&'a str> for CapsFeatures { fn from(value: &'a str) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); features.add(value); features } } impl<'a> From<&'a glib::GStr> for CapsFeatures { fn from(value: &'a glib::GStr) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); features.add(value); features } } impl From for CapsFeatures { fn from(value: glib::Quark) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); features.add_from_quark(value); features } } impl<'a, const N: usize> From<[&'a str; N]> for CapsFeatures { fn from(value: [&'a str; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(f)); features } } impl<'a, const N: usize> From<[&'a glib::GStr; N]> for CapsFeatures { fn from(value: [&'a glib::GStr; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(f)); features } } impl From<[String; N]> for CapsFeatures { fn from(value: [String; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(&f)); features } } impl From<[glib::GString; N]> for CapsFeatures { fn from(value: [glib::GString; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(&f)); features } } impl From<[glib::Quark; N]> for CapsFeatures { fn from(value: [glib::Quark; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add_from_quark(f)); features } } impl<'a> std::iter::FromIterator<&'a str> for CapsFeatures { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(f)); features } } impl<'a> std::iter::FromIterator<&'a glib::GStr> for CapsFeatures { fn from_iter>(iter: T) -> Self { assert_initialized_main_thread!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(f)); features } } impl std::iter::FromIterator for CapsFeatures { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(&f)); features } } impl std::iter::FromIterator for CapsFeatures { fn from_iter>(iter: T) -> Self { assert_initialized_main_thread!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(&f)); features } } impl std::iter::FromIterator for CapsFeatures { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add_from_quark(f)); features } } impl fmt::Debug for CapsFeaturesRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("CapsFeatures") .field(&self.to_string()) .finish() } } impl fmt::Display for CapsFeaturesRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = unsafe { glib::GString::from_glib_full(ffi::gst_caps_features_to_string(self.as_ptr())) }; f.write_str(&s) } } impl ToOwned for CapsFeaturesRef { type Owned = CapsFeatures; #[inline] fn to_owned(&self) -> CapsFeatures { unsafe { from_glib_full(ffi::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) } } } unsafe impl Sync for CapsFeaturesRef {} unsafe impl Send for CapsFeaturesRef {} pub static CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) }; pub static CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: Lazy = Lazy::new(|| CapsFeatures::new([CAPS_FEATURE_MEMORY_SYSTEM_MEMORY])); #[cfg(test)] mod tests { use super::*; #[test] fn test_from_value_optional() { use glib::value::ToValue; crate::init().unwrap(); let a = None::.to_value(); assert!(a.get::>().unwrap().is_none()); let b = glib::value::Value::from(&CapsFeatures::new_empty()); assert!(b.get::>().unwrap().is_some()); } }