use std::{
marker::PhantomData,
mem::ManuallyDrop,
ptr::{self, NonNull},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Metadata(pub u8);
impl Metadata {
pub const MASK: u8 = 0b00000011;
pub const _0: Metadata = Metadata(0b00000000);
pub const _1: Metadata = Metadata(0b00000001);
pub const _2: Metadata = Metadata(0b00000010);
pub const _3: Metadata = Metadata(0b00000011);
}
#[repr(C)]
pub struct Align4PtrCompat<T> {
pub meta: u8,
pub value: T,
}
#[derive(Clone, Copy)]
#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
struct Align4Ptr(
cfg_select! {
target_pointer_width = "64" => [u8; 8],
target_pointer_width = "32" => [u8; 4],
},
);
impl Align4Ptr {
fn from_parts(addr: usize, meta: Metadata) -> Self {
let mut bytes = addr.to_le_bytes();
assert_eq!(bytes[0] & Metadata::MASK, 0);
bytes[0] |= meta.0;
Self(bytes)
}
fn into_parts(self) -> (usize, Metadata) {
let mut bytes = self.0;
let meta = Metadata(bytes[0] & Metadata::MASK);
bytes[0] &= !Metadata::MASK;
let addr = usize::from_le_bytes(bytes);
(addr, meta)
}
}
#[repr(C, align(4))]
pub struct Align4<T: ?Sized>(pub T);
#[repr(C)]
pub struct Align4Own<T> {
ptr: Align4Ptr,
_marker: PhantomData<Align4<T>>,
}
impl<T> Align4Own<T> {
pub fn from_boxed(ptr: Box<Align4<T>>, meta: Metadata) -> Self {
let addr = Box::into_raw(ptr).expose_provenance();
Self {
ptr: Align4Ptr::from_parts(addr, meta),
_marker: PhantomData,
}
}
pub fn into_raw(self) -> *mut Align4<T> {
let this = ManuallyDrop::new(self);
ptr::with_exposed_provenance_mut(this.ptr.into_parts().0)
}
pub unsafe fn into_boxed(self) -> Box<Align4<T>> {
unsafe { Box::from_raw(self.into_raw()) }
}
pub unsafe fn cast<U>(self) -> Align4Own<U> {
let (_, meta) = self.ptr.into_parts();
Align4Own::from_boxed(
unsafe { Box::from_raw(self.into_raw().cast::<Align4<U>>()) },
meta,
)
}
pub fn borrow(&self) -> Ref<'_, T> {
let (addr, _) = self.ptr.into_parts();
let ptr: *mut Align4<T> = ptr::with_exposed_provenance_mut(addr);
let ptr = ptr.cast::<T>();
Ref {
ptr: unsafe { NonNull::new_unchecked(ptr) },
_marker: PhantomData,
}
}
pub fn borrow_mut(&self) -> Mut<'_, T> {
let (addr, _) = self.ptr.into_parts();
let ptr: *mut Align4<T> = ptr::with_exposed_provenance_mut(addr);
let ptr = ptr.cast::<T>();
Mut {
ptr: unsafe { NonNull::new_unchecked(ptr) },
_marker: PhantomData,
}
}
}
impl<T> Drop for Align4Own<T> {
fn drop(&mut self) {
unsafe {
let _ = Box::from_raw(Self::into_raw(Self {
ptr: self.ptr,
_marker: PhantomData,
}));
}
}
}
#[derive(Clone, Copy)]
#[repr(C, align(4))]
pub struct Align4Ref<'a, T> {
ptr: Align4Ptr,
_marker: PhantomData<&'a Align4<T>>,
}
impl<'a, T> Align4Ref<'a, T> {
pub fn new(static_ref: &'a Align4<T>, meta: Metadata) -> Align4Ref<'a, T> {
Self {
ptr: Align4Ptr::from_parts((&raw const *static_ref).expose_provenance(), meta),
_marker: PhantomData,
}
}
pub fn borrow(&self) -> Ref<'_, T> {
let (addr, _) = self.ptr.into_parts();
let ptr: *const Align4<T> = ptr::with_exposed_provenance(addr);
let ptr = ptr.cast::<T>();
Ref {
ptr: unsafe { NonNull::new_unchecked(ptr.cast_mut()) },
_marker: PhantomData,
}
}
}
#[derive(Clone, Copy)]
pub struct Ref<'a, T> {
ptr: NonNull<T>,
_marker: PhantomData<&'a Align4<T>>,
}
impl<'a, T> Ref<'a, T> {
pub unsafe fn cast<U>(self) -> Ref<'a, U> {
Ref {
ptr: self.ptr.cast::<U>(),
_marker: PhantomData,
}
}
pub unsafe fn project<F>(self, f: fn(*const T) -> *const F) -> Ref<'a, F> {
Ref {
ptr: unsafe { NonNull::new_unchecked(f(self.ptr.as_ptr()).cast_mut()) },
_marker: PhantomData,
}
}
pub fn deref(&self) -> &'a T {
unsafe { self.ptr.as_ref() }
}
}
impl<'a, T> Ref<'a, T>
where
T: Copy,
{
pub fn copied(&self) -> T {
unsafe { self.ptr.read() }
}
}
pub struct Mut<'a, T> {
ptr: NonNull<T>,
_marker: PhantomData<&'a mut Align4<T>>,
}
impl<'a, T> Mut<'a, T> {
pub unsafe fn cast<U>(self) -> Mut<'a, U> {
Mut {
ptr: self.ptr.cast::<U>(),
_marker: PhantomData,
}
}
pub unsafe fn project<F>(self, f: fn(*mut T) -> *mut F) -> Mut<'a, F> {
Mut {
ptr: unsafe { NonNull::new_unchecked(f(self.ptr.as_ptr())) },
_marker: PhantomData,
}
}
pub fn deref_mut(&mut self) -> &'a mut T {
unsafe { self.ptr.as_mut() }
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
#[test]
fn align4_ptr_round_trip() {
let addr = 0xDEAD_BEE0usize; for meta in [Metadata::_0, Metadata::_1, Metadata::_2, Metadata::_3] {
let ptr = Align4Ptr::from_parts(addr, meta);
let (restored_addr, restored_meta) = ptr.into_parts();
assert_eq!(restored_addr, addr);
assert_eq!(restored_meta, meta);
}
}
#[test]
#[should_panic]
fn align4_ptr_panics_on_unaligned() {
let addr = 0xDEAD_BEEFusize; Align4Ptr::from_parts(addr, Metadata::_0);
}
#[test]
fn align4_own_boxed_round_trip() {
let value = Box::new(Align4(42u32));
let owned = Align4Own::from_boxed(value, Metadata::_1);
let restored = unsafe { owned.into_boxed() };
assert_eq!(restored.0, 42);
}
#[test]
fn align4_own_cast_preserves_data() {
let value = Box::new(Align4(0xABCD_EF01u32));
let owned = Align4Own::from_boxed(value, Metadata::_2);
let casted = unsafe { owned.cast::<[u8; 4]>() };
let restored = unsafe { casted.into_boxed() };
assert_eq!(restored.0, [0x01, 0xEF, 0xCD, 0xAB]); }
#[test]
fn ref_deref_valid() {
let value = Box::new(Align4(99u64));
let owned = Align4Own::from_boxed(value, Metadata::_0);
let r = owned.borrow();
assert_eq!(*r.deref(), 99);
}
#[test]
fn ref_project_field() {
#[repr(C)]
struct Pair {
x: u32,
y: u32,
}
let value = Box::new(Align4(Pair { x: 10, y: 20 }));
let owned = Align4Own::from_boxed(value, Metadata::_0);
let r = owned.borrow();
let y_ref = unsafe { r.project(|p| &raw const (*p).y) };
assert_eq!(*y_ref.deref(), 20);
}
#[test]
fn align4_guarantees_alignment() {
assert!(mem::align_of::<Align4<u8>>() >= 4);
assert!(mem::align_of::<Align4<u64>>() >= 4);
}
}