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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Byte fiddling utilities
//!
//! Define [FromBytes](trait.FromBytes.html) and [AsBytes](trait.AsBytes.html)
//! traits, which allow for safe data conversion assuming the data meets certain
//! layout-specific restrictions.
//! See documentation for [AsBytes](trait.AsBytes.html) for more details.
//!
//! These traits are implemented automatically for sized data structures if they
//! implement [Pod](trait.Pod.html) trait.

use core::alloc::Layout;
use core::{mem, ptr, slice};

/// Checks if a pointer can be a valid Rust reference.
pub(crate) fn ptr_ref_cast<T, U>(ptr: *const U) -> *const T {
    assert_ne!(ptr, ptr::null());
    assert_eq!(ptr as usize % mem::align_of::<T>(), 0);
    ptr as *const _
}

/// Attempts to cast the pointer to byte slice to a pointer of a generic slice.
/// Adjusts the length metadata as required.
/// Panics if the pointer is null.
///
/// # Safety
///
pub unsafe fn ptr_slice_cast<T>(ptr: *const [u8]) -> *const [T] {
    assert_ne!(ptr as *const (), ptr::null());
    // SAFETY: [u8] is 1-byte aligned so no need to check that before deref
    let len = (*ptr).len();

    let new_len = len * mem::size_of::<u8>() / mem::size_of::<T>();

    let slice = slice::from_raw_parts(ptr as *const T, new_len);
    slice as *const _ as *const [T]
}

/// Marker trait for types that can be safely converted to bytes.
///
/// # Safety
/// Implementee MUST be `#[repr(C)]` and:
/// - not contain any pointer types that are dereferenced,
/// - itself or any of its members MUST NOT implement a custom destructor,
/// - be inhabited,
/// - allow any bit pattern
///
/// ## Layout
/// Implementee also needs to be layout-compatible with [u8].
pub unsafe trait AsBytes {
    fn as_bytes(&self) -> &[u8] {
        let len = mem::size_of_val(self);
        // SAFETY: Guaranteed by documented unsafe impl invariants.
        unsafe { slice::from_raw_parts(self as *const _ as *const u8, len) }
    }

    fn into_bytes(self: Box<Self>) -> Box<[u8]> {
        let len = mem::size_of_val(self.as_ref());
        // SAFETY: Guaranteed by documented unsafe impl invariants of `AsBytes`.
        let ptr = Box::into_raw(self);
        unsafe {
            let slice = slice::from_raw_parts_mut(ptr as *mut _ as *mut u8, len);

            Box::from_raw(slice)
        }
    }
}

/// Marker trait for types that can be safely converted to bytes.
pub unsafe trait FromBytes {
    /// Specified the minimum layout requirements for the allocation:
    /// - is at least as big as `MIN_LAYOUT.size()`
    /// - referenced/pointed data is at least as aligned as `MIN_LAYOUT.align()`
    ///
    /// For DSTs, final size should be exactly the same as the allocation's.
    ///
    /// # Safety
    /// In Rust, it is considered [UB] for pointers/references/`Box<T>`es to
    /// be dangling, unaligned or pointing to invalid value.
    ///
    /// The alignment check is done using `MIN_LAYOUT` and thus can cause UB if
    /// implemented incorrectly.
    ///
    /// [UB]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
    const MIN_LAYOUT: Layout;

    fn from_bytes(bytes: &[u8]) -> &Self {
        let min_layout = Self::MIN_LAYOUT;
        // Make sure the allocation meets the expected layout requirements
        assert!(bytes.len() >= min_layout.size());
        assert_eq!(bytes.as_ptr() as usize % min_layout.align(), 0);

        let old_size = mem::size_of_val(bytes);
        // SAFETY: It's up to the implementer to provide a sound
        // `Self::ptr_cast` implementation.
        let new = unsafe { &*Self::ptr_cast(bytes) };

        let new_size = mem::size_of_val(new);
        // Make sure we don't leak data/forget any information when adjusting
        // the (possibly wide) pointer
        assert_eq!(old_size, new_size);

        new
    }

    fn from_boxed(boxed: Box<[u8]>) -> Box<Self> {
        let min_layout = Self::MIN_LAYOUT;
        // Make sure the allocation meets the expected layout requirements
        assert!(boxed.len() >= min_layout.size());
        assert_eq!(boxed.as_ptr() as usize % min_layout.align(), 0);

        let old_size = mem::size_of_val(boxed.as_ref());

        let ptr = Box::into_raw(boxed);
        // SAFETY: It's up to the implementer to provide a sound
        // `Self::ptr_cast` implementation.
        let new = unsafe { Box::from_raw(Self::ptr_cast(ptr) as *mut Self) };

        let new_size = mem::size_of_val(new.as_ref());
        // Make sure we don't leak data/forget any information when adjusting
        // the (possibly wide) pointer
        assert_eq!(old_size, new_size);

        new
    }

    #[doc(hidden)]
    unsafe fn ptr_cast(source: *const [u8]) -> *const Self;
}

unsafe impl FromBytes for [u16] {
    // Allow for empty slices but require correct alignment
    const MIN_LAYOUT: Layout =
        unsafe { Layout::from_size_align_unchecked(0, mem::align_of::<u16>()) };
    unsafe fn ptr_cast(source: *const [u8]) -> *const Self {
        ptr_slice_cast(source)
    }
}

unsafe impl FromBytes for [u8] {
    // Allow for empty slices but require correct alignment
    const MIN_LAYOUT: Layout =
        unsafe { Layout::from_size_align_unchecked(0, mem::align_of::<u8>()) };
    unsafe fn ptr_cast(source: *const [u8]) -> *const [u8] {
        source
    }

    fn from_bytes(bytes: &[u8]) -> &Self {
        bytes
    }
    fn from_boxed(boxed: Box<[u8]>) -> Box<Self> {
        boxed
    }
}

/// Marker trait that can be safely converted from and into bytes.
///
/// Automatically implements [AsBytes] and [FromBytes].
/// # Safety
/// See documentation for [AsBytes] for safety invariants that need to be upheld.
pub unsafe trait Pod: Sized {}

unsafe impl<T> AsBytes for T where T: Pod {}
unsafe impl<T> FromBytes for T
where
    T: Pod,
{
    const MIN_LAYOUT: Layout = Layout::new::<Self>();

    unsafe fn ptr_cast(ptr: *const [u8]) -> *const Self {
        ptr_ref_cast(ptr as *const ())
    }
}

unsafe impl Pod for u32 {} // Ignores endianness