baryl 0.0.4

Public SDK for Baryl, a full-system emulation and introspection engine
Documentation
//! What may be stored in pool memory, and the macro that says so for a list of
//! types.

use core::cell::UnsafeCell;
use core::sync::atomic::{AtomicU32, AtomicUsize};

/// A type that may live in the run's pool, and so in a checkpoint.
///
/// You need this on any type you hand to `AllocRef::leak_and_initialize_sbx` or
/// `..._anon`, or store in a `BVec` or `BMap`. The integers, `()`, `AtomicU32`,
/// `AtomicUsize`, `UnsafeCell<T>` and `[T; N]` already have it; write
/// [`impl_sandbox_safe!`](crate::impl_sandbox_safe) for your own.
///
/// # Safety
///
/// A checkpoint stores the pool's bytes and restores them into a run that has
/// nothing else in common with the one that wrote them. So: no `Box`, `Vec`,
/// `String` or any other host-heap owner inside, and every pointer the type
/// holds must address pool memory, which keeps its address across a restore. A
/// host pointer written before a save is a dangling pointer after the restore,
/// and nothing will tell you.
pub unsafe trait SandboxSafe: Sized {
    /// Write a valid starting value at `addr`.
    ///
    /// The default does nothing, which is right for any type whose all-zeroes
    /// bit pattern is valid — freshly claimed pool bytes read as zero. Override
    /// it for a layout that needs something else in place before first use.
    fn initialize(_addr: u64) {}
}

/// Declare [`SandboxSafe`] for one or more types at once.
///
/// # Safety
///
/// This writes an `unsafe impl` for every type listed, so each must meet
/// [`SandboxSafe`]'s conditions — no host-heap ownership, no pointer outside
/// the pool. Nothing is checked.
///
/// # Examples
///
/// ```ignore
/// #[repr(C)]
/// pub struct Counters { hits: u64, misses: u64 }
///
/// #[repr(C)]
/// pub struct Window { start: u64, len: u64 }
///
/// impl_sandbox_safe!(Counters, Window);
/// ```
#[macro_export]
macro_rules! impl_sandbox_safe {
    ($($t:ty),* $(,)?) => { $( unsafe impl $crate::SandboxSafe for $t {} )* };
}

// The integers: plain data, no pointers.
impl_sandbox_safe!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

// Zero-sized, so there is nothing to restore.
unsafe impl SandboxSafe for () {}

// Atomics carry no pointers; the interior mutability is part of the layout.
unsafe impl SandboxSafe for AtomicU32 {}
unsafe impl SandboxSafe for AtomicUsize {}

// The cell adds interior mutability and no pointers, so it inherits T's answer.
unsafe impl<T: SandboxSafe> SandboxSafe for UnsafeCell<T> {}

// An array is its element repeated; nothing new is reachable through it.
unsafe impl<T: SandboxSafe, const N: usize> SandboxSafe for [T; N] {}