1use core::mem::{align_of, size_of};
2use core::ptr::NonNull;
3
4#[derive(Clone, Copy)]
12pub struct Region {
13 base: NonNull<u8>,
14 len: usize,
15}
16
17impl Region {
18 pub unsafe fn from_raw(base: *mut u8, len: usize) -> Self {
26 let base = NonNull::new(base).expect("region base must be non-null");
27 Self { base, len }
28 }
29
30 #[inline]
32 pub fn as_ptr(&self) -> *mut u8 {
33 self.base.as_ptr()
34 }
35
36 #[inline]
38 pub fn len(&self) -> usize {
39 self.len
40 }
41
42 #[inline]
44 pub fn is_empty(&self) -> bool {
45 self.len == 0
46 }
47
48 #[inline]
50 pub fn offset(&self, off: usize) -> *mut u8 {
51 assert!(
52 off < self.len,
53 "offset {off} out of bounds (len={})",
54 self.len
55 );
56 unsafe { self.as_ptr().add(off) }
57 }
58
59 #[inline]
65 pub unsafe fn get<T>(&self, off: usize) -> &T {
66 debug_assert!(off + size_of::<T>() <= self.len);
67 debug_assert!(off.is_multiple_of(align_of::<T>()));
68 unsafe { &*(self.offset(off) as *const T) }
69 }
70
71 #[inline]
77 #[allow(clippy::mut_from_ref)]
78 pub unsafe fn get_mut<T>(&self, off: usize) -> &mut T {
79 debug_assert!(off + size_of::<T>() <= self.len);
80 debug_assert!(off.is_multiple_of(align_of::<T>()));
81 unsafe { &mut *(self.offset(off) as *mut T) }
82 }
83}
84
85unsafe impl Send for Region {}
86unsafe impl Sync for Region {}
87
88mod heap {
89 use super::Region;
90 use core::ptr::NonNull;
91 use std::alloc::{Layout, alloc_zeroed, dealloc};
92
93 pub struct HeapRegion {
95 base: NonNull<u8>,
96 len: usize,
97 layout: Layout,
98 }
99
100 impl HeapRegion {
101 pub fn new_zeroed(size: usize) -> Self {
103 let layout =
104 Layout::from_size_align(size.max(1), 64).expect("invalid heap region layout");
105 let ptr = unsafe { alloc_zeroed(layout) };
106 let base = NonNull::new(ptr).expect("heap region allocation failed");
107 Self {
108 base,
109 len: size,
110 layout,
111 }
112 }
113
114 #[inline]
116 pub fn region(&self) -> Region {
117 unsafe { Region::from_raw(self.base.as_ptr(), self.len) }
118 }
119
120 #[inline]
122 pub fn len(&self) -> usize {
123 self.len
124 }
125
126 #[inline]
128 pub fn is_empty(&self) -> bool {
129 self.len == 0
130 }
131 }
132
133 impl Drop for HeapRegion {
134 fn drop(&mut self) {
135 unsafe { dealloc(self.base.as_ptr(), self.layout) };
136 }
137 }
138
139 unsafe impl Send for HeapRegion {}
140 unsafe impl Sync for HeapRegion {}
141}
142
143pub use heap::HeapRegion;