use crate::assert::StaticAssertions;
use crate::mem::Memory;
use crate::ptr::write_addr;
use crate::raw::FatPointer;
use core::any::Any;
use core::fmt;
use core::mem::{self, ManuallyDrop, MaybeUninit};
use core::ops;
use core::ptr;
#[cfg(feature = "coerce_unsized")]
use core::marker::Unsize;
#[cfg(feature = "coerce_unsized")]
use core::ops::CoerceUnsized;
pub struct BoxS<T, M>
where
T: ?Sized,
M: Memory,
{
buf: ManuallyDrop<M>,
ptr: *mut T,
}
#[macro_export]
macro_rules! boxed_s {
($val:expr) => {{
let mut val = $val;
let ptr = &mut val as *mut _;
let boxed = unsafe { $crate::BoxS::__new(&mut val, ptr) };
::core::mem::forget(val);
boxed
}};
}
#[cfg(feature = "coerce_unsized")]
impl<T, U, M> CoerceUnsized<BoxS<U, M>> for BoxS<T, M>
where
T: ?Sized + Unsize<U>,
U: ?Sized,
M: Memory,
{
}
impl<T, M> ops::Deref for BoxS<T, M>
where
T: ?Sized,
M: Memory,
{
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.as_ptr() }
}
}
impl<T, M> ops::DerefMut for BoxS<T, M>
where
T: ?Sized,
M: Memory,
{
fn deref_mut(&mut self) -> &mut <Self as ops::Deref>::Target {
unsafe { &mut *self.as_mut_ptr() }
}
}
impl<T, M> Drop for BoxS<T, M>
where
T: ?Sized,
M: Memory,
{
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(self.as_mut_ptr());
}
}
}
impl<T, M> fmt::Debug for BoxS<T, M>
where
T: ?Sized + fmt::Debug,
M: Memory,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Debug>::fmt(self, f)
}
}
impl<T, M> fmt::Display for BoxS<T, M>
where
T: ?Sized + fmt::Display,
M: Memory,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Display>::fmt(self, f)
}
}
impl<T, M> fmt::Pointer for BoxS<T, M>
where
T: ?Sized,
M: Memory,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_ptr().fmt(f)
}
}
impl<T, M> BoxS<T, M>
where
M: Memory,
{
pub fn new(x: T) -> Self {
boxed_s!(x)
}
}
impl<M> BoxS<dyn Any + 'static, M>
where
M: Memory,
{
pub fn downcast<T>(self) -> Result<BoxS<T, M>, Self>
where
T: Any,
{
if self.is::<T>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
}
impl<M> BoxS<dyn Any + Send + 'static, M>
where
M: Memory,
{
pub fn downcast<T>(self) -> Result<BoxS<T, M>, Self>
where
T: Any,
{
if self.is::<T>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
}
impl<T, M> BoxS<T, M>
where
T: ?Sized,
M: Memory,
{
#[doc(hidden)]
pub unsafe fn __new<U>(val: &mut U, ptr: *mut T) -> Self {
let _ = StaticAssertions::<T, U, M>::new();
BoxS::<T, M>::from_ptr(val, FatPointer::from_raw(ptr).map(|fat| fat.meta))
}
}
impl<T, M> BoxS<T, M>
where
T: ?Sized,
M: Memory,
{
unsafe fn from_ptr<U>(ptr_u: &U, extra: Option<usize>) -> Self
where
U: ?Sized,
{
let mut buf: MaybeUninit<M> = MaybeUninit::uninit();
let dst: *mut u8 = buf.as_mut_ptr() as *mut _;
ptr::copy_nonoverlapping(
ptr_u as *const _ as *const u8,
dst,
mem::size_of_val::<U>(&ptr_u),
);
let mut ptr = MaybeUninit::zeroed();
let ptr_ptr: *mut usize = ptr.as_mut_ptr() as *mut _;
if let Some(addr) = extra {
ptr_ptr.add(1).write(addr);
}
Self {
buf: ManuallyDrop::new(buf.assume_init()),
ptr: ptr.assume_init(),
}
}
fn as_ptr(&self) -> *const T {
write_addr(self.ptr, &*self.buf as *const M as _)
}
fn as_mut_ptr(&mut self) -> *mut T {
write_addr(self.ptr, &mut *self.buf as *mut M as _)
}
unsafe fn downcast_unchecked<U: Any>(mut self) -> BoxS<U, M> {
let Self { ref mut buf, ptr } = self;
let buf = ManuallyDrop::new(ManuallyDrop::take(buf));
mem::forget(self);
BoxS {
buf,
ptr: ptr as *mut _,
}
}
}
unsafe impl<T, M> Send for BoxS<T, M>
where
T: ?Sized + Send,
M: Memory,
{
}
unsafe impl<T, M> Sync for BoxS<T, M>
where
T: ?Sized + Sync,
M: Memory,
{
}
#[cfg(test)]
mod tests {
use super::*;
use core::any::Any;
use core::sync::atomic::{AtomicBool, Ordering};
#[test]
fn smoke() {
let mut boxed = BoxS::<usize, [usize; 1]>::new(0);
assert_eq!(*boxed, 0);
*boxed = 1;
assert_eq!(*boxed, 1);
}
#[test]
fn boxed_s_macro() {
let _boxed: BoxS<dyn Any, [usize; 1]> = boxed_s!(0_usize);
}
#[cfg(feature = "coerce_unsized")]
#[test]
fn coerce_unsized() {
let _boxed: BoxS<dyn Any, [usize; 1]> = BoxS::new(0_usize);
}
#[test]
fn zst() {
let mut boxed = BoxS::<(), [usize; 0]>::new(());
assert_eq!(*boxed, ());
*boxed = ();
}
#[test]
fn drop() {
struct Foo<'a>(&'a AtomicBool);
impl Drop for Foo<'_> {
fn drop(&mut self) {
self.0.store(true, Ordering::Relaxed);
}
}
let dropped = AtomicBool::new(false);
let foo = Foo(&dropped);
let boxed = BoxS::<_, [usize; 1]>::new(foo);
assert!(!dropped.load(Ordering::Relaxed));
mem::drop(boxed);
assert!(dropped.load(Ordering::Relaxed));
}
#[test]
fn any() {
let boxed: BoxS<dyn Any, [usize; 1]> = boxed_s!(0_usize);
assert_eq!(*boxed.downcast::<usize>().ok().unwrap(), 0);
let boxed: BoxS<dyn Any + Send, [usize; 1]> = boxed_s!(0_usize);
assert_eq!(*boxed.downcast::<usize>().ok().unwrap(), 0);
}
#[test]
fn slice() {
let boxed: BoxS<[u8], [usize; 1]> = boxed_s!([0_u8; 4]);
assert_eq!(&*boxed, &[0_u8; 4][..]);
}
}