diff options
Diffstat (limited to 'rendy-memory/src/mapping/range.rs')
-rw-r--r-- | rendy-memory/src/mapping/range.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/rendy-memory/src/mapping/range.rs b/rendy-memory/src/mapping/range.rs new file mode 100644 index 0000000..f4c49be --- /dev/null +++ b/rendy-memory/src/mapping/range.rs @@ -0,0 +1,85 @@ +use { + crate::util::fits_usize, + std::{ + mem::{align_of, size_of}, + ops::Range, + ptr::NonNull, + slice::{from_raw_parts, from_raw_parts_mut}, + }, +}; + +/// Get sub-range of memory mapping. +/// `range` and `fitting` are in memory object space. +/// `ptr` points to the `range.start` offset from memory origin. +/// returns pointer to `fitting.start` offset from memory origin +/// if `fitting` is contained in `range`. +pub(crate) fn mapped_sub_range( + ptr: NonNull<u8>, + range: Range<u64>, + fitting: Range<u64>, +) -> Option<NonNull<u8>> { + assert!( + range.start < range.end, + "Memory mapping region must have valid size" + ); + assert!( + fitting.start < fitting.end, + "Memory mapping region must have valid size" + ); + assert!(fits_usize(range.end - range.start)); + assert!(usize::max_value() - (range.end - range.start) as usize >= ptr.as_ptr() as usize); + + if fitting.start < range.start || fitting.end > range.end { + None + } else { + Some(unsafe { + // for x > 0 and y >= 0: x + y > 0. No overflow due to checks above. + NonNull::new_unchecked( + (ptr.as_ptr() as usize + (fitting.start - range.start) as usize) as *mut u8, + ) + }) + } +} + +/// # Safety +/// +/// User must ensure that: +/// * this function won't create aliasing slices. +/// * returned slice doesn't outlive mapping. +/// * `T` Must be plain-old-data type compatible with data in mapped region. +pub(crate) unsafe fn mapped_slice_mut<'a, T>(ptr: NonNull<u8>, size: usize) -> &'a mut [T] { + assert_eq!( + size % size_of::<T>(), + 0, + "Range length must be multiple of element size" + ); + let offset = ptr.as_ptr() as usize; + assert_eq!( + offset % align_of::<T>(), + 0, + "Range offset must be multiple of element alignment" + ); + assert!(usize::max_value() - size >= ptr.as_ptr() as usize); + from_raw_parts_mut(ptr.as_ptr() as *mut T, size) +} + +/// # Safety +/// +/// User must ensure that: +/// * returned slice doesn't outlive mapping. +/// * `T` Must be plain-old-data type compatible with data in mapped region. +pub(crate) unsafe fn mapped_slice<'a, T>(ptr: NonNull<u8>, size: usize) -> &'a [T] { + assert_eq!( + size % size_of::<T>(), + 0, + "Range length must be multiple of element size" + ); + let offset = ptr.as_ptr() as usize; + assert_eq!( + offset % align_of::<T>(), + 0, + "Range offset must be multiple of element alignment" + ); + assert!(usize::max_value() - size >= ptr.as_ptr() as usize); + from_raw_parts(ptr.as_ptr() as *const T, size) +} |