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