1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
use crate::error::Error;
/// Basic functionality for flat types.
pub trait FlatBase {
/// Align of the type.
const ALIGN: usize;
/// Minimal size of of an instance of the type.
const MIN_SIZE: usize;
/// Size of an instance of the type.
fn size(&self) -> usize;
/// Check that memory size and alignment are suitable for `Self`.
fn check_size_and_align(mem: &[u8]) -> Result<(), Error> {
if mem.len() < Self::MIN_SIZE {
Err(Error::InsufficientSize)
} else if mem.as_ptr().align_offset(Self::ALIGN) != 0 {
Err(Error::BadAlign)
} else {
Ok(())
}
}
}
/// Construction of flat types.
pub trait FlatInit: FlatBase {
/// Representation of flat type that uses dynamic memory if needed.
/// Therefore it is always sized.
///
/// May be cloned onto flat memory by using [`FlatInit::placement_new`].
type Dyn: Sized;
/// Size of corresponding flat type.
fn size_of(value: &Self::Dyn) -> usize;
/// Create a new instance of `Self` onto raw memory from dynamic representation of the type.
fn placement_new<'a, 'b>(
mem: &'a mut [u8],
init: &'b Self::Dyn,
) -> Result<&'a mut Self, Error> {
Self::check_size_and_align(mem)?;
Ok(unsafe { Self::placement_new_unchecked(mem, init) })
}
/// Create a new default instance of `Self` onto raw memory.
fn placement_default(mem: &mut [u8]) -> Result<&mut Self, Error>
where
Self::Dyn: Default,
{
Self::placement_new(mem, &Self::Dyn::default())
}
/// Initialize without checks.
///
/// # Safety
///
/// Size, alignment and specific type requirements must be ok.
unsafe fn placement_new_unchecked<'a, 'b>(
mem: &'a mut [u8],
init: &'b Self::Dyn,
) -> &'a mut Self;
/// Validate memory before interpretation.
fn pre_validate(mem: &[u8]) -> Result<(), Error>;
/// Validate memory after interpretation.
fn post_validate(&self) -> Result<(), Error>;
/// Interpret a previously iniailized memory as an instance of `Self`.
fn reinterpret(mem: &[u8]) -> Result<&Self, Error> {
Self::check_size_and_align(mem)?;
Self::pre_validate(mem)?;
let self_ = unsafe { Self::reinterpret_unchecked(mem) };
self_.post_validate()?;
Ok(self_)
}
/// The same as [`reinterpret`](`Self::reinterpret`) but provides a mutable reference.
fn reinterpret_mut(mem: &mut [u8]) -> Result<&mut Self, Error> {
Self::check_size_and_align(mem)?;
Self::pre_validate(mem)?;
let self_ = unsafe { Self::reinterpret_mut_unchecked(mem) };
self_.post_validate()?;
Ok(self_)
}
/// Interpret without checks.
///
/// # Safety
///
/// Memory must have suitable size and align for `Self` and its contents must be valid.
unsafe fn reinterpret_unchecked(mem: &[u8]) -> &Self;
/// Interpret without checks providing mutable reference.
///
/// # Safety
///
/// Memory must have suitable size and align for `Self` and its contents must be valid.
unsafe fn reinterpret_mut_unchecked(mem: &mut [u8]) -> &mut Self;
}
/// Dynamically-sized flat type.
///
/// *For now it must be implemented for all flat types until negative trait bounds supported.*
pub trait FlatUnsized: FlatBase {
/// Sized type that has the same alignment as [`Self`].
type AlignAs: Sized;
/// Metadata to store in wide pointer.
fn ptr_metadata(mem: &[u8]) -> usize;
}
/// Marker trait for flat types.
///
/// *If you want to implement this type for your custom type it's recommended to use safe `make_flat` macro instead.*
///
/// # Safety
///
/// The type must have portable binary representation.
pub unsafe trait Flat: FlatBase + FlatInit + FlatUnsized {}