1use core::cell::Cell;
4use core::fmt;
5use core::marker::PhantomData;
6
7use crate::memory;
8
9#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
11pub struct RegionId(u128);
12
13impl RegionId {
14 pub const fn new(value: u128) -> Option<Self> {
16 if value == 0 { None } else { Some(Self(value)) }
17 }
18
19 pub const fn get(self) -> u128 {
21 self.0
22 }
23}
24
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub enum WriterEndpoint {
28 Coordinator,
30 Receiver,
32}
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub struct RegionSpec {
37 pub id: RegionId,
39 pub writer: WriterEndpoint,
41}
42
43#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub enum GuardPolicy {
56 BestEffort,
59 Require,
62 Disable,
64}
65
66#[derive(Clone, Copy, Debug, Eq, PartialEq)]
68pub struct GuardCapability {
69 pub requested: GuardPolicy,
71 pub installed: bool,
74}
75
76#[derive(Clone, Copy, Debug, Eq, PartialEq)]
78pub struct RegionOptions {
79 logical_len: usize,
80 maximum_len: usize,
81 guard: GuardPolicy,
82}
83
84impl RegionOptions {
85 pub const fn fixed(logical_len: usize) -> Self {
87 Self {
88 logical_len,
89 maximum_len: logical_len,
90 guard: GuardPolicy::BestEffort,
91 }
92 }
93
94 pub const fn with_max_bytes(mut self, maximum_len: usize) -> Self {
96 self.maximum_len = maximum_len;
97 self
98 }
99
100 pub const fn with_guard_policy(mut self, guard: GuardPolicy) -> Self {
102 self.guard = guard;
103 self
104 }
105}
106
107#[derive(Debug)]
109pub enum RegionError {
110 Memory(memory::MemoryError),
112 GuardUnavailable,
116}
117
118impl fmt::Display for RegionError {
119 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
120 match self {
121 Self::Memory(error) => error.fmt(formatter),
122 Self::GuardUnavailable => formatter.write_str("required guard bands are unavailable"),
123 }
124 }
125}
126
127impl std::error::Error for RegionError {}
128
129impl From<memory::MemoryError> for RegionError {
130 fn from(value: memory::MemoryError) -> Self {
131 Self::Memory(value)
132 }
133}
134
135pub struct PrivateRegion {
137 inner: memory::NativeRegion,
138 guard: GuardPolicy,
139 _not_sync: PhantomData<Cell<()>>,
140}
141
142unsafe impl Send for PrivateRegion {}
145
146impl PrivateRegion {
147 pub fn allocate(options: RegionOptions) -> Result<Self, RegionError> {
157 let native = if options.maximum_len == options.logical_len {
158 memory::RegionOptions::fixed(options.logical_len, memory::WriterOwner::Creator)
159 } else {
160 memory::RegionOptions::growable(
161 options.logical_len,
162 options.maximum_len,
163 memory::WriterOwner::Creator,
164 )
165 };
166 Ok(Self {
167 inner: memory::NativeRegion::allocate(native)?,
168 guard: options.guard,
169 _not_sync: PhantomData,
170 })
171 }
172
173 pub fn initialize<R>(&mut self, operation: impl FnOnce(&mut [u8]) -> R) -> R {
175 self.inner.initialize(operation)
176 }
177
178 pub fn prepare(self, spec: RegionSpec) -> Result<PreparedRegion, RegionError> {
180 let writer = match spec.writer {
181 WriterEndpoint::Coordinator => memory::WriterOwner::Creator,
182 WriterEndpoint::Receiver => memory::WriterOwner::Peer,
183 };
184 let request = self.inner.prepare_with_writer(writer)?;
185 Ok(PreparedRegion {
186 request,
187 spec,
188 guard: GuardCapability {
189 requested: self.guard,
190 installed: false,
191 },
192 #[cfg(test)]
193 drop_observer: PreparedDropObserver(None),
194 _not_sync: PhantomData,
195 })
196 }
197}
198
199pub struct PreparedRegion {
208 #[cfg(test)]
209 drop_observer: PreparedDropObserver,
210 #[allow(dead_code)]
211 pub(crate) request: memory::NativeShareRequest,
212 #[allow(dead_code)]
213 pub(crate) spec: RegionSpec,
214 #[allow(dead_code)]
215 pub(crate) guard: GuardCapability,
216 _not_sync: PhantomData<Cell<()>>,
217}
218
219#[cfg(test)]
220struct PreparedDropObserver(Option<std::sync::Arc<std::sync::Mutex<Vec<&'static str>>>>);
221
222#[cfg(test)]
223impl Drop for PreparedDropObserver {
224 fn drop(&mut self) {
225 if let Some(events) = &self.0 {
226 events.lock().unwrap().push("prepared-drop");
227 }
228 }
229}
230
231unsafe impl Send for PreparedRegion {}
233
234impl PreparedRegion {
235 pub const fn guard_capability(&self) -> GuardCapability {
244 self.guard
245 }
246
247 pub(crate) const fn spec(&self) -> RegionSpec {
248 self.spec
249 }
250
251 #[allow(dead_code)]
252 pub(crate) fn logical_len(&self) -> usize {
253 self.request.logical_len()
254 }
255
256 #[allow(dead_code)]
257 pub(crate) fn mapped_len(&self) -> usize {
258 self.request.mapped_len()
259 }
260
261 #[cfg(test)]
262 pub(crate) fn observe_drop(
263 mut self,
264 events: std::sync::Arc<std::sync::Mutex<Vec<&'static str>>>,
265 ) -> Self {
266 self.drop_observer.0 = Some(events);
267 self
268 }
269
270 #[cfg(target_os = "linux")]
271 pub(crate) fn into_linux_transfer_parts(
272 self,
273 ) -> (memory::NativeShareRequest, RegionSpec, GuardCapability) {
274 let Self {
275 #[cfg(test)]
276 drop_observer: _,
277 request,
278 spec,
279 guard,
280 _not_sync: _,
281 } = self;
282 (request, spec, guard)
283 }
284
285 #[cfg(target_os = "macos")]
286 pub(crate) fn into_macos_transfer_parts(
287 self,
288 ) -> (memory::NativeShareRequest, RegionSpec, GuardCapability) {
289 let Self {
290 #[cfg(test)]
291 drop_observer: _,
292 request,
293 spec,
294 guard,
295 _not_sync: _,
296 } = self;
297 (request, spec, guard)
298 }
299
300 #[cfg(target_os = "windows")]
301 pub(crate) fn into_windows_transfer_parts(
302 self,
303 ) -> (memory::NativeShareRequest, RegionSpec, GuardCapability) {
304 let Self {
305 #[cfg(test)]
306 drop_observer: _,
307 request,
308 spec,
309 guard,
310 _not_sync: _,
311 } = self;
312 (request, spec, guard)
313 }
314}
315
316#[cfg(test)]
317#[path = "region_test.rs"]
318mod tests;