use std::ops::{Deref, DerefMut}; use std::{any::type_name, fmt}; use memsafe::MemSafe; pub trait SafeCellHandle { type CellRead<'a>: Deref where Self: 'a, T: 'a; type CellWrite<'a>: Deref + DerefMut where Self: 'a, T: 'a; fn new(value: T) -> Self where Self: Sized; fn read(&mut self) -> Self::CellRead<'_>; fn write(&mut self) -> Self::CellWrite<'_>; fn new_inline(f: F) -> Self where Self: Sized, T: Default, F: for<'a> FnOnce(&'a mut T), { let mut cell = Self::new(T::default()); { let mut handle = cell.write(); f(handle.deref_mut()); } cell } #[inline(always)] fn read_inline(&mut self, f: F) -> R where F: FnOnce(&T) -> R, { f(&*self.read()) } #[inline(always)] fn write_inline(&mut self, f: F) -> R where F: FnOnce(&mut T) -> R, { f(&mut *self.write()) } } pub struct MemSafeCell(MemSafe); impl fmt::Debug for MemSafeCell { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MemSafeCell") .field("inner", &format_args!("", type_name::())) .finish() } } impl SafeCellHandle for MemSafeCell { type CellRead<'a> = memsafe::MemSafeRead<'a, T> where Self: 'a, T: 'a; type CellWrite<'a> = memsafe::MemSafeWrite<'a, T> where Self: 'a, T: 'a; fn new(value: T) -> Self { match MemSafe::new(value) { Ok(inner) => Self(inner), Err(err) => { // If protected memory cannot be allocated, process integrity is compromised. abort_memory_breach("safe cell allocation", &err) } } } #[inline(always)] fn read(&mut self) -> Self::CellRead<'_> { match self.0.read() { Ok(inner) => inner, Err(err) => abort_memory_breach("safe cell read", &err), } } #[inline(always)] fn write(&mut self) -> Self::CellWrite<'_> { match self.0.write() { Ok(inner) => inner, Err(err) => { // If protected memory becomes unwritable here, treat it as a fatal memory breach. abort_memory_breach("safe cell write", &err) } } } } fn abort_memory_breach(action: &str, err: &memsafe::error::MemoryError) -> ! { eprintln!("fatal {action}: {err}"); std::process::abort(); } pub type SafeCell = MemSafeCell;