use core::ptr::NonNull;
use crate::Reference;
#[repr(transparent)] pub struct Deferred<T>
where
T: Reference,
{
ptr: NonNull<T::Target>,
}
impl<'a, T: ?Sized> Deferred<&'a T> {
pub fn new(reference: &'a T) -> Self {
unsafe {
Self::from_raw(reference)
}
}
pub unsafe fn from_raw(ptr: *const T) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr as *mut T),
}
}
}
impl<'a, T: ?Sized> Deferred<&'a mut T> {
pub fn new_mut(reference: &'a mut T) -> Self {
unsafe {
Self::from_raw_mut(reference)
}
}
pub unsafe fn from_raw_mut(ptr: *mut T) -> Deferred<&'a mut T> {
Self {
ptr: NonNull::new_unchecked(ptr as *mut T),
}
}
}
impl<T> Deferred<T>
where
T: Reference,
{
pub fn as_ptr(&self) -> *const T::Target {
self.ptr.as_ptr() as *const _
}
#[cfg(feature = "coerce_unsized")]
pub fn unsize<U>(self) -> Deferred<U>
where
U: Reference,
NonNull<T::Target>: core::ops::CoerceUnsized<NonNull<U::Target>>, {
Deferred {
ptr: self.ptr,
}
}
}
impl<'a, T: ?Sized> Deferred<&'a mut T> {
pub fn as_mut_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
pub unsafe fn clone_unchecked(&self) -> Self {
Deferred::from_raw_mut(self.as_mut_ptr())
}
pub fn into_ref(self) -> Deferred<&'a T> {
self.into()
}
}
#[cfg(test)]
mod tests {
use core::cell::UnsafeCell;
use crate::{Defer, DeferMut, Deferred};
#[test]
fn new() {
let mut buffer = [0u8; 1024];
let mut deferred = Deferred::from(&mut buffer);
assert_eq!(0, deferred[0]);
assert_eq!(&mut 0, &mut deferred[0]);
let mut deferred2 = unsafe { deferred.clone_unchecked() };
let tmp1: &mut [u8] = &mut deferred[10..20];
tmp1[0] = 42; deferred2[0] = 42;
assert_eq!(42, deferred[0]);
assert_eq!(42, buffer[0]);
}
#[test]
fn mut_ref_invalidation() {
let buffer = UnsafeCell::new([0u8; 1024]);
let mut deferred = unsafe { buffer.defer_mut() };
let mut deferred2 = unsafe { deferred.clone_unchecked() };
deferred[10] = 1; deferred2[30] = 1; let _tmp1 = &mut deferred[10..20];
let tmp2 = &mut deferred2[30..40];
tmp2[0] = 42;
}
#[test]
fn cast_to_ptr() {
let mut buffer = UnsafeCell::new([0u8; 1024]);
buffer.get_mut()[0] = 1;
{
let deferred = buffer.defer();
let ptr = unsafe { *(core::ptr::addr_of!(deferred) as *const *const [u8; 1024]) };
assert_eq!(*deferred, unsafe { *ptr });
}
{
let deferred = unsafe { buffer.defer_mut() };
let ptr = unsafe { *(core::ptr::addr_of!(deferred) as *const *mut [u8; 1024]) };
assert_eq!(*deferred, unsafe { *ptr });
}
{
let mut deferred = unsafe { buffer.defer_mut() };
let ptr = unsafe { *(core::ptr::addr_of_mut!(deferred) as *mut *mut [u8; 1024]) };
assert_eq!(*deferred, unsafe { *ptr });
}
}
#[test]
fn size_of() {
assert_eq!(core::mem::size_of::<Deferred<&[u8]>>(), core::mem::size_of::<Option<Deferred<&[u8]>>>())
}
#[test]
fn as_ptr() {
let buffer = UnsafeCell::new([0u8; 1024]);
let deferred = buffer.defer();
assert_eq!(deferred.as_ptr() as usize, buffer.get() as usize);
}
#[test]
fn as_mut_ptr() {
let buffer = UnsafeCell::new([0u8; 1024]);
let deferred = unsafe { buffer.defer_mut() };
assert_eq!(deferred.as_mut_ptr() as usize, buffer.get() as usize);
}
}