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 {}