#![no_std]
mod pod;
use core::{
mem::{size_of, size_of_val, ManuallyDrop, MaybeUninit},
num::Wrapping,
slice::{from_raw_parts, from_raw_parts_mut},
};
pub use safe_bytes_derive::SafeBytes;
#[doc(hidden)]
pub use core;
#[macro_export]
macro_rules! typed_field {
($instance:expr, $type:path, $field:ident) => {{
let reference: &$type = &$instance;
let $type {
$field: field_reference,
..
} = reference;
let base_address = reference as *const _ as usize;
let field_size = $crate::core::mem::size_of_val(field_reference);
let field_address = field_reference as *const _ as usize;
let field_offset = field_address.checked_sub(base_address).unwrap();
let field_sub = $crate::PaddingBane::get_fields(field_reference);
TypedField {
raw: $crate::Field {
offset: field_offset,
size: field_size,
},
sub: field_sub,
}
}};
}
pub trait SafeBytes {
fn safe_bytes(&mut self) -> &[u8];
}
pub unsafe trait PaddingBane {
type Fields: Copy;
fn get_fields(&self) -> Self::Fields;
unsafe fn init_padding(fields: Self::Fields, bytes: &mut [MaybeUninit<u8>]);
}
impl<T> SafeBytes for T
where
T: PaddingBane,
{
#[inline]
fn safe_bytes(&mut self) -> &[u8] {
let fields = self.get_fields();
unsafe {
let bytes = maybe_init_bytes_of(self);
Self::init_padding(fields, bytes);
assume_slice_init(&*bytes)
}
}
}
impl<T> SafeBytes for [T]
where
T: PaddingBane,
{
fn safe_bytes(&mut self) -> &[u8] {
if self.is_empty() {
&[]
} else {
let fields = self[0].get_fields();
let len = self.len();
unsafe {
let bytes = maybe_init_bytes_of(self);
for i in 0..len {
let start = i * size_of::<T>();
let end = start + size_of::<T>();
T::init_padding(fields, &mut bytes[start..end]);
}
assume_slice_init(&*bytes)
}
}
}
}
macro_rules! impl_for_array {
($N:tt) => {
unsafe impl<T> PaddingBane for [T; $N]
where
T: PaddingBane,
{
type Fields = T::Fields;
#[inline(always)]
fn get_fields(&self) -> T::Fields {
self[0].get_fields()
}
#[inline(always)]
unsafe fn init_padding(fields: T::Fields, bytes: &mut [MaybeUninit<u8>]) {
for i in 0 .. $N {
let start = i * size_of::<T>();
let end = start + size_of::<T>();
T::init_padding(fields, &mut bytes[start..end]);
}
}
}
};
($($N:tt)*) => {
$(impl_for_array!($N);)*
};
}
impl_for_array! {
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
48 64 96 128 256 512 1024 2048 4096 8192 16384 32768 65536
}
unsafe impl<T> PaddingBane for ManuallyDrop<T>
where
T: PaddingBane,
{
type Fields = T::Fields;
#[inline(always)]
fn get_fields(&self) -> Self::Fields {
(&**self).get_fields()
}
#[inline(always)]
unsafe fn init_padding(fields: Self::Fields, bytes: &mut [MaybeUninit<u8>]) {
T::init_padding(fields, bytes);
}
}
unsafe impl<T> PaddingBane for Wrapping<T>
where
T: PaddingBane,
{
type Fields = T::Fields;
#[inline(always)]
fn get_fields(&self) -> Self::Fields {
self.0.get_fields()
}
#[inline(always)]
unsafe fn init_padding(fields: Self::Fields, bytes: &mut [MaybeUninit<u8>]) {
T::init_padding(fields, bytes);
}
}
#[derive(Clone, Copy)]
pub struct Field {
pub offset: usize,
pub size: usize,
}
#[derive(Clone, Copy)]
pub struct TypedField<T: PaddingBane> {
pub raw: Field,
pub sub: T::Fields,
}
unsafe fn maybe_init_bytes_of<T: ?Sized>(r: &mut T) -> &mut [MaybeUninit<u8>] {
from_raw_parts_mut(r as *mut T as *mut MaybeUninit<u8>, size_of_val(r))
}
unsafe fn assume_slice_init<T>(slice: &[MaybeUninit<T>]) -> &[T] {
from_raw_parts(slice.as_ptr() as *const T, size_of_val(slice))
}