// Take a look at the license at the top of the repository in the LICENSE file. use std::{ fmt, marker::PhantomData, mem, ops::{Bound, Deref, DerefMut, RangeBounds}, ptr, slice, }; use glib::translate::*; use crate::{AllocationParams, Allocator, MemoryFlags}; mini_object_wrapper!(Memory, MemoryRef, ffi::GstMemory, || { ffi::gst_memory_get_type() }); pub struct MemoryMap<'a, T> { memory: &'a MemoryRef, map_info: ffi::GstMapInfo, phantom: PhantomData, } pub struct MappedMemory { memory: Memory, map_info: ffi::GstMapInfo, phantom: PhantomData, } impl fmt::Debug for Memory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { MemoryRef::fmt(self, f) } } impl fmt::Debug for MemoryRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Memory") .field("ptr", &self.as_ptr()) .field("allocator", &self.allocator()) .field("parent", &self.parent()) .field("maxsize", &self.maxsize()) .field("align", &self.align()) .field("offset", &self.offset()) .field("size", &self.size()) .field("flags", &self.flags()) .finish() } } pub enum Readable {} pub enum Writable {} impl Memory { #[inline] pub fn with_size(size: usize) -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_allocator_alloc( ptr::null_mut(), size, ptr::null_mut(), )) } } #[inline] pub fn with_size_and_params(size: usize, params: &AllocationParams) -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_allocator_alloc( ptr::null_mut(), size, params.as_ptr() as *mut _, )) } } #[inline] pub fn into_mapped_memory_readable(self) -> Result, Self> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res: bool = from_glib(ffi::gst_memory_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READ, )); if res { Ok(MappedMemory { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(self) } } } #[inline] pub fn into_mapped_memory_writable(self) -> Result, Self> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res: bool = from_glib(ffi::gst_memory_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READWRITE, )); if res { Ok(MappedMemory { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(self) } } } } impl MemoryRef { #[doc(alias = "get_allocator")] #[inline] pub fn allocator(&self) -> Option<&Allocator> { unsafe { if self.0.allocator.is_null() { None } else { Some(&*(&self.0.allocator as *const *mut ffi::GstAllocator as *const Allocator)) } } } #[doc(alias = "get_parent")] #[inline] pub fn parent(&self) -> Option<&MemoryRef> { unsafe { if self.0.parent.is_null() { None } else { Some(MemoryRef::from_ptr(self.0.parent)) } } } #[doc(alias = "get_maxsize")] #[inline] pub fn maxsize(&self) -> usize { self.0.maxsize } #[doc(alias = "get_align")] #[inline] pub fn align(&self) -> usize { self.0.align } #[doc(alias = "get_offset")] #[inline] pub fn offset(&self) -> usize { self.0.offset } #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.0.size } #[doc(alias = "get_flags")] #[inline] pub fn flags(&self) -> MemoryFlags { unsafe { from_glib(self.0.mini_object.flags) } } fn calculate_offset_size(&self, range: impl RangeBounds) -> (isize, isize) { let size = self.size(); let start_offset = match range.start_bound() { Bound::Included(v) => *v, Bound::Excluded(v) => v.checked_add(1).expect("Invalid start offset"), Bound::Unbounded => 0, }; assert!(start_offset < size, "Start offset after valid range"); let end_offset = match range.end_bound() { Bound::Included(v) => v.checked_add(1).expect("Invalid end offset"), Bound::Excluded(v) => *v, Bound::Unbounded => size, }; assert!(end_offset <= size, "End offset after valid range"); // Cast from usize to isize because that's literally how this works in the // implementation and how the upper half of the usize range can be made use of. // // The implementation works exploiting wraparounds. let new_offset = start_offset as isize; let new_size = end_offset.saturating_sub(start_offset) as isize; (new_offset, new_size) } fn calculate_offset_size_maxsize(&self, range: impl RangeBounds) -> (isize, isize) { let maxsize = self.maxsize(); let start_offset = match range.start_bound() { Bound::Included(v) => *v, Bound::Excluded(v) => v.checked_add(1).expect("Invalid start offset"), Bound::Unbounded => 0, }; assert!(start_offset < maxsize, "Start offset after valid range"); let end_offset = match range.end_bound() { Bound::Included(v) => v.checked_add(1).expect("Invalid end offset"), Bound::Excluded(v) => *v, Bound::Unbounded => maxsize, }; assert!(end_offset <= maxsize, "End offset after valid range"); // Cast from usize to isize because that's literally how this works in the // implementation and how the upper half of the usize range can be made use of. // // The implementation works by exploiting wraparounds. let offset = self.offset(); let new_offset = start_offset.wrapping_sub(offset) as isize; let new_size = end_offset.saturating_sub(start_offset) as isize; (new_offset, new_size) } #[doc(alias = "gst_memory_copy")] pub fn copy_range(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size(range); unsafe { from_glib_full(ffi::gst_memory_copy(self.as_mut_ptr(), offset, size)) } } #[doc(alias = "gst_memory_copy")] pub fn copy_range_maxsize(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size_maxsize(range); unsafe { from_glib_full(ffi::gst_memory_copy(self.as_mut_ptr(), offset, size)) } } #[doc(alias = "gst_memory_is_span")] pub fn is_span(&self, mem2: &MemoryRef) -> Option { unsafe { let mut offset = mem::MaybeUninit::uninit(); let res = from_glib(ffi::gst_memory_is_span( self.as_mut_ptr(), mem2.as_mut_ptr(), offset.as_mut_ptr(), )); if res { Some(offset.assume_init()) } else { None } } } #[doc(alias = "gst_memory_is_type")] pub fn is_type(&self, mem_type: &str) -> bool { unsafe { from_glib(ffi::gst_memory_is_type( self.as_mut_ptr(), mem_type.to_glib_none().0, )) } } #[inline] pub fn map_readable(&self) -> Result, glib::BoolError> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_memory_map(self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READ); if res == glib::ffi::GTRUE { Ok(MemoryMap { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map memory readable")) } } } #[inline] pub fn map_writable(&mut self) -> Result, glib::BoolError> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_memory_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READWRITE, ); if res == glib::ffi::GTRUE { Ok(MemoryMap { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map memory writable")) } } } #[doc(alias = "gst_memory_share")] pub fn share(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size(range); unsafe { from_glib_full(ffi::gst_memory_share(self.as_ptr() as *mut _, offset, size)) } } #[doc(alias = "gst_memory_share")] pub fn share_maxsize(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size_maxsize(range); unsafe { from_glib_full(ffi::gst_memory_share(self.as_ptr() as *mut _, offset, size)) } } #[doc(alias = "gst_memory_resize")] pub fn resize(&mut self, range: impl RangeBounds) { let (offset, size) = self.calculate_offset_size(range); unsafe { ffi::gst_memory_resize(self.as_mut_ptr(), offset, size as usize) } } #[doc(alias = "gst_memory_resize")] pub fn resize_maxsize(&mut self, range: impl RangeBounds) { let (offset, size) = self.calculate_offset_size_maxsize(range); unsafe { ffi::gst_memory_resize(self.as_mut_ptr(), offset, size as usize) } } #[doc(alias = "gst_util_dump_mem")] pub fn dump(&self) -> Dump { Dump { memory: self, start: Bound::Unbounded, end: Bound::Unbounded, } } #[doc(alias = "gst_util_dump_mem")] pub fn dump_range(&self, range: impl RangeBounds) -> Dump { Dump { memory: self, start: range.start_bound().cloned(), end: range.end_bound().cloned(), } } } impl<'a, T> MemoryMap<'a, T> { #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.map_info.size } #[doc(alias = "get_memory")] #[inline] pub fn memory(&self) -> &MemoryRef { self.memory } #[inline] pub fn as_slice(&self) -> &[u8] { if self.map_info.size == 0 { return &[]; } unsafe { slice::from_raw_parts(self.map_info.data, self.map_info.size) } } } impl<'a> MemoryMap<'a, Writable> { #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { if self.map_info.size == 0 { return &mut []; } unsafe { slice::from_raw_parts_mut(self.map_info.data, self.map_info.size) } } } impl<'a, T> AsRef<[u8]> for MemoryMap<'a, T> { #[inline] fn as_ref(&self) -> &[u8] { self.as_slice() } } impl<'a> AsMut<[u8]> for MemoryMap<'a, Writable> { #[inline] fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl<'a, T> Deref for MemoryMap<'a, T> { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { self.as_slice() } } impl<'a> DerefMut for MemoryMap<'a, Writable> { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl<'a, T> fmt::Debug for MemoryMap<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("MemoryMap").field(&self.memory()).finish() } } impl<'a, T> PartialEq for MemoryMap<'a, T> { fn eq(&self, other: &MemoryMap<'a, T>) -> bool { self.as_slice().eq(other.as_slice()) } } impl<'a, T> Eq for MemoryMap<'a, T> {} impl<'a, T> Drop for MemoryMap<'a, T> { #[inline] fn drop(&mut self) { unsafe { ffi::gst_memory_unmap(self.memory.as_mut_ptr(), &mut self.map_info); } } } unsafe impl<'a, T> Send for MemoryMap<'a, T> {} unsafe impl<'a, T> Sync for MemoryMap<'a, T> {} impl MappedMemory { #[inline] pub fn as_slice(&self) -> &[u8] { if self.map_info.size == 0 { return &[]; } unsafe { slice::from_raw_parts(self.map_info.data, self.map_info.size) } } #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.map_info.size } #[doc(alias = "get_memory")] #[inline] pub fn memory(&self) -> &MemoryRef { self.memory.as_ref() } #[inline] pub fn into_memory(self) -> Memory { let mut s = mem::ManuallyDrop::new(self); let memory = unsafe { ptr::read(&s.memory) }; unsafe { ffi::gst_memory_unmap(memory.as_mut_ptr(), &mut s.map_info); } memory } } impl MappedMemory { #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { if self.map_info.size == 0 { return &mut []; } unsafe { slice::from_raw_parts_mut(self.map_info.data, self.map_info.size) } } } impl AsRef<[u8]> for MappedMemory { #[inline] fn as_ref(&self) -> &[u8] { self.as_slice() } } impl AsMut<[u8]> for MappedMemory { #[inline] fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl Deref for MappedMemory { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { self.as_slice() } } impl DerefMut for MappedMemory { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl Drop for MappedMemory { #[inline] fn drop(&mut self) { unsafe { ffi::gst_memory_unmap(self.memory.as_mut_ptr(), &mut self.map_info); } } } impl fmt::Debug for MappedMemory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("MappedMemory").field(&self.memory()).finish() } } impl PartialEq for MappedMemory { fn eq(&self, other: &MappedMemory) -> bool { self.as_slice().eq(other.as_slice()) } } impl Eq for MappedMemory {} unsafe impl Send for MappedMemory {} unsafe impl Sync for MappedMemory {} pub struct Dump<'a> { memory: &'a MemoryRef, start: Bound, end: Bound, } impl<'a> Dump<'a> { fn fmt(&self, f: &mut fmt::Formatter, debug: bool) -> fmt::Result { let map = self.memory.map_readable().expect("Failed to map memory"); let data = map.as_slice(); let dump = crate::slice::Dump { data, start: self.start, end: self.end, }; if debug { ::fmt(&dump, f) } else { ::fmt(&dump, f) } } } impl<'a> fmt::Display for Dump<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.fmt(f, false) } } impl<'a> fmt::Debug for Dump<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt(f, true) } } 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::prelude::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 { #[inline] fn as_ref(&self) -> &MemoryRef { self } } impl AsMut for MemoryRef { #[inline] fn as_mut(&mut self) -> &mut MemoryRef { self } } impl AsRef for Memory { #[inline] fn as_ref(&self) -> &Memory { self } } unsafe impl MemoryType for Memory { #[inline] fn check_memory_type(_mem: &MemoryRef) -> bool { skip_assert_initialized!(); true } } impl Memory { #[inline] pub fn downcast_memory(self) -> Result where ::RefType: AsRef + AsMut, { if M::check_memory_type(&self) { unsafe { Ok(from_glib_full(self.into_glib_ptr() as *mut M::FfiType)) } } else { Err(self) } } } impl MemoryRef { #[inline] pub fn is_memory_type(&self) -> bool where ::RefType: AsRef + AsMut, { M::check_memory_type(self) } #[inline] 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 } } #[inline] 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 { #[inline] fn check_memory_type(mem: &$crate::MemoryRef) -> bool { skip_assert_initialized!(); $mem_type_check(mem) } } impl $name { #[inline] 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_glib_ptr() as *mut M::FfiType )) } } else { Err(self) } } #[inline] 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_glib_ptr() as *const ::FfiType ) } } } impl $ref_name { #[inline] 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() } #[inline] 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; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self as *const _ as *const Self::Target) } } } impl std::ops::DerefMut for $ref_name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut _ as *mut Self::Target) } } } impl AsRef<$parent_memory_type> for $name { #[inline] 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 { #[inline] fn as_ref(&self) -> &$parent_memory_ref_type { self } } impl AsMut<$parent_memory_ref_type> for $ref_name { #[inline] fn as_mut(&mut self) -> &mut $parent_memory_ref_type { &mut *self } } impl $crate::glib::types::StaticType for $name { #[inline] fn static_type() -> glib::types::Type { $ref_name::static_type() } } impl $crate::glib::types::StaticType for $ref_name { #[inline] 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; debug_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 } } impl From<$name> for $crate::glib::Value { fn from(v: $name) -> $crate::glib::Value { skip_assert_initialized!(); let mut value = $crate::glib::Value::for_value_type::<$name>(); unsafe { $crate::glib::gobject_ffi::g_value_take_boxed( $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::glib::translate::IntoGlibPtr::<*mut $ffi_name>::into_glib_ptr(v) 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 { #[inline] 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 { #[inline] fn as_ref(&self) -> &$parent_parent_memory_ref_type { self } } impl AsMut<$parent_parent_memory_ref_type> for $ref_name { #[inline] fn as_mut(&mut self) -> &mut $parent_parent_memory_ref_type { &mut *self } } )* }; } #[cfg(test)] mod tests { #[test] fn test_map() { crate::init().unwrap(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); let map = mem.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); drop(map); let mem = mem.into_mapped_memory_readable().unwrap(); assert_eq!(mem.as_slice(), &[1, 2, 3, 4]); let mem = mem.into_memory(); let map = mem.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); } #[test] fn test_share() { crate::init().unwrap(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); let sub = mem.share(1..=2); // [2, 3] let sub_sub1 = sub.share(1..=1); // [3] let sub_sub2 = sub.share_maxsize(0..4); // [1, 2, 3, 4] let map = mem.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); drop(map); let map = sub.map_readable().unwrap(); assert_eq!(map.as_slice(), &[2, 3]); drop(map); let map = sub_sub1.map_readable().unwrap(); assert_eq!(map.as_slice(), &[3]); drop(map); let map = sub_sub2.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); drop(map); } #[test] fn test_dump() { use std::fmt::Write; crate::init().unwrap(); let mut s = String::new(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); write!(&mut s, "{:?}", mem.dump()).unwrap(); assert_eq!( s, "0000: 01 02 03 04 ...." ); s.clear(); write!(&mut s, "{}", mem.dump()).unwrap(); assert_eq!(s, "01 02 03 04"); s.clear(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); write!(&mut s, "{:?}", mem.dump_range(..)).unwrap(); assert_eq!( s, "0000: 01 02 03 04 ...." ); s.clear(); write!(&mut s, "{:?}", mem.dump_range(..2)).unwrap(); assert_eq!( s, "0000: 01 02 .." ); s.clear(); write!(&mut s, "{:?}", mem.dump_range(2..=3)).unwrap(); assert_eq!( s, "0002: 03 04 .." ); s.clear(); write!(&mut s, "{:?}", mem.dump_range(..100)).unwrap(); assert_eq!(s, "",); s.clear(); write!(&mut s, "{:?}", mem.dump_range(90..100)).unwrap(); assert_eq!(s, "",); s.clear(); let mem = crate::Memory::from_slice(vec![0; 19]); write!(&mut s, "{:?}", mem.dump()).unwrap(); assert_eq!( s, "0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\n\ 0010: 00 00 00 ..." ); s.clear(); } #[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!(v.get::().is_ok()); } }