diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 3f5bf7910..5af345353 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -335,6 +335,8 @@ pub mod prelude { SpecificFormattedValueIntrinsic, }; pub use crate::utils::Displayable; + + pub use crate::memory::MemoryType; } #[macro_use] diff --git a/gstreamer/src/memory.rs b/gstreamer/src/memory.rs index 838e02388..25fd9d1b1 100644 --- a/gstreamer/src/memory.rs +++ b/gstreamer/src/memory.rs @@ -3,7 +3,7 @@ use std::fmt; use std::marker::PhantomData; use std::mem; -use std::ops; +use std::ops::{Deref, DerefMut}; use std::ptr; use std::slice; @@ -359,7 +359,7 @@ impl<'a> AsMut<[u8]> for MemoryMap<'a, Writable> { } } -impl<'a, T> ops::Deref for MemoryMap<'a, T> { +impl<'a, T> Deref for MemoryMap<'a, T> { type Target = [u8]; fn deref(&self) -> &[u8] { @@ -367,7 +367,7 @@ impl<'a, T> ops::Deref for MemoryMap<'a, T> { } } -impl<'a> ops::DerefMut for MemoryMap<'a, Writable> { +impl<'a> DerefMut for MemoryMap<'a, Writable> { fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } @@ -447,7 +447,7 @@ impl AsMut<[u8]> for MappedMemory { } } -impl ops::Deref for MappedMemory { +impl Deref for MappedMemory { type Target = [u8]; fn deref(&self) -> &[u8] { @@ -455,7 +455,7 @@ impl ops::Deref for MappedMemory { } } -impl ops::DerefMut for MappedMemory { +impl DerefMut for MappedMemory { fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } @@ -522,6 +522,342 @@ impl<'a> fmt::Debug for Dump<'a> { } } +pub unsafe trait MemoryType: crate::prelude::IsMiniObject + AsRef +where + ::RefType: AsRef + AsMut, +{ + fn check_memory_type(mem: &MemoryRef) -> bool; +} + +#[derive(Debug, thiserror::Error)] +pub enum MemoryTypeMismatchError { + #[error(transparent)] + ValueTypeMismatch(#[from] glib::value::ValueTypeMismatchError), + #[error("the memory is not of the requested type {requested}")] + MemoryTypeMismatch { requested: &'static str }, +} + +pub struct MemoryTypeValueTypeChecker(PhantomData); + +unsafe impl glib::value::ValueTypeChecker for MemoryTypeValueTypeChecker +where + M: MemoryType + glib::StaticType, + ::RefType: AsRef + AsMut, +{ + type Error = glib::value::ValueTypeMismatchOrNoneError; + + fn check(value: &glib::Value) -> Result<(), Self::Error> { + skip_assert_initialized!(); + let mem = value.get::<&Memory>().map_err(|err| match err { + glib::value::ValueTypeMismatchOrNoneError::UnexpectedNone => { + glib::value::ValueTypeMismatchOrNoneError::UnexpectedNone + } + glib::value::ValueTypeMismatchOrNoneError::WrongValueType(err) => { + glib::value::ValueTypeMismatchOrNoneError::WrongValueType( + MemoryTypeMismatchError::ValueTypeMismatch(err), + ) + } + })?; + + if mem.is_memory_type::() { + Ok(()) + } else { + Err(glib::value::ValueTypeMismatchOrNoneError::WrongValueType( + MemoryTypeMismatchError::MemoryTypeMismatch { + requested: std::any::type_name::(), + }, + )) + } + } +} + +impl AsRef for MemoryRef { + fn as_ref(&self) -> &MemoryRef { + self + } +} + +impl AsMut for MemoryRef { + fn as_mut(&mut self) -> &mut MemoryRef { + self + } +} + +impl AsRef for Memory { + fn as_ref(&self) -> &Memory { + self + } +} + +unsafe impl MemoryType for Memory { + fn check_memory_type(_mem: &MemoryRef) -> bool { + skip_assert_initialized!(); + true + } +} + +impl Memory { + pub fn downcast_memory(self) -> Result + where + ::RefType: AsRef + AsMut, + { + if M::check_memory_type(&self) { + unsafe { Ok(from_glib_full(self.into_ptr() as *mut M::FfiType)) } + } else { + Err(self) + } + } +} + +impl MemoryRef { + pub fn is_memory_type(&self) -> bool + where + ::RefType: AsRef + AsMut, + { + M::check_memory_type(self) + } + + pub fn downcast_memory_ref(&self) -> Option<&M::RefType> + where + ::RefType: AsRef + AsMut, + { + if M::check_memory_type(self) { + unsafe { Some(&*(self as *const Self as *const M::RefType)) } + } else { + None + } + } + + pub fn downcast_memory_mut(&mut self) -> Option<&mut M::RefType> + where + ::RefType: AsRef + AsMut, + { + if M::check_memory_type(self) { + unsafe { Some(&mut *(self as *mut Self as *mut M::RefType)) } + } else { + None + } + } +} + +#[macro_export] +macro_rules! memory_object_wrapper { + ($name:ident, $ref_name:ident, $ffi_name:path, $mem_type_check:expr, $parent_memory_type:path, $parent_memory_ref_type:path) => { + $crate::mini_object_wrapper!($name, $ref_name, $ffi_name); + + unsafe impl $crate::memory::MemoryType for $name { + fn check_memory_type(mem: &$crate::MemoryRef) -> bool { + skip_assert_initialized!(); + $mem_type_check(mem) + } + } + + impl $name { + pub fn downcast_memory(self) -> Result + where + ::RefType: AsRef<$crate::MemoryRef> + + AsMut<$crate::MemoryRef> + + AsRef<$ref_name> + + AsMut<$ref_name>, + { + if M::check_memory_type(&self) { + unsafe { + Ok($crate::glib::translate::from_glib_full( + self.into_ptr() as *mut M::FfiType + )) + } + } else { + Err(self) + } + } + + pub fn upcast_memory(self) -> M + where + M: $crate::memory::MemoryType + + $crate::glib::translate::FromGlibPtrFull< + *const ::FfiType, + >, + ::RefType: + AsRef<$crate::MemoryRef> + AsMut<$crate::MemoryRef>, + Self: AsRef, + { + unsafe { + $crate::glib::translate::from_glib_full( + self.into_ptr() as *const ::FfiType + ) + } + } + } + + impl $ref_name { + pub fn upcast_memory_ref(&self) -> &M::RefType + where + M: $crate::memory::MemoryType, + ::RefType: + AsRef<$crate::MemoryRef> + AsMut<$crate::MemoryRef>, + Self: AsRef + AsMut + { + self.as_ref() + } + + pub fn upcast_memory_mut(&mut self) -> &mut M::RefType + where + M: $crate::memory::MemoryType, + ::RefType: + AsRef<$crate::MemoryRef> + AsMut<$crate::MemoryRef>, + Self: AsRef + AsMut + { + self.as_mut() + } + } + + impl std::ops::Deref for $ref_name { + type Target = $parent_memory_ref_type; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const _ as *const Self::Target) } + } + } + + impl std::ops::DerefMut for $ref_name { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut _ as *mut Self::Target) } + } + } + + impl AsRef<$parent_memory_type> for $name { + fn as_ref(&self) -> &$parent_memory_type { + unsafe { &*(self as *const _ as *const $parent_memory_type) } + } + } + + impl AsRef<$parent_memory_ref_type> for $ref_name { + fn as_ref(&self) -> &$parent_memory_ref_type { + self + } + } + + impl AsMut<$parent_memory_ref_type> for $ref_name { + fn as_mut(&mut self) -> &mut $parent_memory_ref_type { + &mut *self + } + } + + impl $crate::glib::types::StaticType for $name { + fn static_type() -> glib::types::Type { + $ref_name::static_type() + } + } + + impl $crate::glib::types::StaticType for $ref_name { + fn static_type() -> $crate::glib::types::Type { + unsafe { $crate::glib::translate::from_glib($crate::ffi::gst_memory_get_type()) } + } + } + + impl $crate::glib::value::ValueType for $name { + type Type = Self; + } + + unsafe impl<'a> $crate::glib::value::FromValue<'a> for $name { + type Checker = $crate::memory::MemoryTypeValueTypeChecker; + + unsafe fn from_value(value: &'a $crate::glib::Value) -> Self { + skip_assert_initialized!(); + $crate::glib::translate::from_glib_none($crate::glib::gobject_ffi::g_value_get_boxed( + $crate::glib::translate::ToGlibPtr::to_glib_none(value).0, + ) as *mut $ffi_name) + } + } + + unsafe impl<'a> $crate::glib::value::FromValue<'a> for &'a $name { + type Checker = $crate::memory::MemoryTypeValueTypeChecker<$name>; + + unsafe fn from_value(value: &'a $crate::glib::Value) -> Self { + skip_assert_initialized!(); + assert_eq!( + std::mem::size_of::<$name>(), + std::mem::size_of::<$crate::glib::ffi::gpointer>() + ); + let value = &*(value as *const $crate::glib::Value as *const $crate::glib::gobject_ffi::GValue); + let ptr = &value.data[0].v_pointer as *const $crate::glib::ffi::gpointer + as *const *const $ffi_name; + assert!(!(*ptr).is_null()); + &*(ptr as *const $name) + } + } + + impl $crate::glib::value::ToValue for $name { + fn to_value(&self) -> $crate::glib::Value { + let mut value = $crate::glib::Value::for_value_type::(); + unsafe { + $crate::glib::gobject_ffi::g_value_set_boxed( + $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, + $crate::glib::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(self).0 + as *mut _, + ) + } + value + } + + fn value_type(&self) -> glib::Type { + ::static_type() + } + } + + impl $crate::glib::value::ToValueOptional for $name { + fn to_value_optional(s: Option<&Self>) -> $crate::glib::Value { + skip_assert_initialized!(); + let mut value = $crate::glib::Value::for_value_type::(); + unsafe { + $crate::glib::gobject_ffi::g_value_set_boxed( + $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, + $crate::glib::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&s).0 + as *mut _, + ) + } + value + } + } + + unsafe impl<'a> $crate::glib::value::FromValue<'a> for &'a $ref_name { + type Checker = $crate::memory::MemoryTypeValueTypeChecker<$name>; + + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + &*($crate::glib::gobject_ffi::g_value_get_boxed($crate::glib::translate::ToGlibPtr::to_glib_none(value).0) + as *const $ref_name) + } + } + + // Can't have SetValue/SetValueOptional impls as otherwise one could use it to get + // immutable references from a mutable reference without borrowing via the value + }; + ($name:ident, $ref_name:ident, $ffi_name:path, $mem_type_check:expr, $parent_memory_type:path, $parent_memory_ref_type:path, $($parent_parent_memory_type:path, $parent_parent_memory_ref_type:path),*) => { + $crate::memory_object_wrapper!($name, $ref_name, $ffi_name, $mem_type_check, $parent_memory_type, $parent_memory_ref_type); + + $( + impl AsRef<$parent_parent_memory_type> for $name { + fn as_ref(&self) -> &$parent_parent_memory_type { + unsafe { &*(self as *const _ as *const $parent_parent_memory_type) } + } + } + + impl AsRef<$parent_parent_memory_ref_type> for $ref_name { + fn as_ref(&self) -> &$parent_parent_memory_ref_type { + self + } + } + + impl AsMut<$parent_parent_memory_ref_type> for $ref_name { + fn as_mut(&mut self) -> &mut $parent_parent_memory_ref_type { + &mut *self + } + } + )* + }; +} + #[cfg(test)] mod tests { #[test] @@ -537,4 +873,19 @@ mod tests { let mem = crate::Memory::from_slice(vec![0; 64]); dbg!(mem.dump(None)); } + + #[test] + fn test_value() { + use glib::prelude::*; + + crate::init().unwrap(); + + let v = None::<&crate::Memory>.to_value(); + assert!(matches!(v.get::>(), Ok(None))); + + let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); + let v = mem.to_value(); + assert!(matches!(v.get::>(), Ok(Some(_)))); + assert!(matches!(v.get::(), Ok(_))); + } }