diff --git a/src/praetor/mod.rs b/src/praetor/mod.rs index f18c35f..44a9dc4 100644 --- a/src/praetor/mod.rs +++ b/src/praetor/mod.rs @@ -170,11 +170,13 @@ mod util { mod job { use std::{ any::Any, + borrow::{Borrow, BorrowMut}, cell::UnsafeCell, - fmt::Debug, + fmt::{Debug, Display}, hint::cold_path, marker::PhantomPinned, mem::{self, ManuallyDrop, MaybeUninit}, + ops::{Deref, DerefMut}, pin::Pin, ptr::{self, NonNull}, sync::atomic::Ordering, @@ -185,23 +187,114 @@ mod job { use super::util::TaggedAtomicPtr; - pub struct Value(pub MaybeUninit>>); + #[derive(Debug)] + pub struct SmallBox(pub MaybeUninit>); - impl Value { + impl Display for SmallBox { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + (**self).fmt(f) + } + } + + impl Ord for SmallBox { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_ref().cmp(other.as_ref()) + } + } + + impl PartialOrd for SmallBox { + fn partial_cmp(&self, other: &Self) -> Option { + self.as_ref().partial_cmp(other.as_ref()) + } + } + + impl Eq for SmallBox {} + + impl PartialEq for SmallBox { + fn eq(&self, other: &Self) -> bool { + self.as_ref().eq(other.as_ref()) + } + } + + impl Default for SmallBox { + fn default() -> Self { + Self::new(Default::default()) + } + } + + impl Clone for SmallBox { + fn clone(&self) -> Self { + Self::new(self.as_ref().clone()) + } + } + + impl Deref for SmallBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } + } + + impl DerefMut for SmallBox { + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut() + } + } + + impl AsRef for SmallBox { + fn as_ref(&self) -> &T { + Self::as_ref(self) + } + } + impl AsMut for SmallBox { + fn as_mut(&mut self) -> &mut T { + Self::as_mut(self) + } + } + + impl Borrow for SmallBox { + fn borrow(&self) -> &T { + &**self + } + } + impl BorrowMut for SmallBox { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } + } + + impl SmallBox { /// must only be called once. takes a reference so this can be called in /// drop() unsafe fn get_unchecked(&self, inline: bool) -> T { if inline { - unsafe { mem::transmute_copy::>>, T>(&self.0) } + unsafe { mem::transmute_copy::>, T>(&self.0) } } else { - unsafe { - let inner = *self.0.assume_init_read(); - inner.assume_init() + unsafe { *self.0.assume_init_read() } + } + } + + pub fn as_ref(&self) -> &T { + unsafe { + if Self::is_inline() { + mem::transmute::<&MaybeUninit>, &T>(&self.0) + } else { + self.0.assume_init_ref() + } + } + } + pub fn as_mut(&mut self) -> &mut T { + unsafe { + if Self::is_inline() { + mem::transmute::<&mut MaybeUninit>, &mut T>(&mut self.0) + } else { + self.0.assume_init_mut() } } } - pub fn get(self) -> T { + pub fn into_inner(self) -> T { let this = ManuallyDrop::new(self); let inline = Self::is_inline(); @@ -228,12 +321,12 @@ mod job { this.assume_init() } } else { - Self(MaybeUninit::new(Box::new(MaybeUninit::new(value)))) + Self(MaybeUninit::new(Box::new(value))) } } } - impl Drop for Value { + impl Drop for SmallBox { fn drop(&mut self) { // drop contained value. drop(unsafe { self.get_unchecked(Self::is_inline()) }); @@ -374,7 +467,7 @@ mod job { union ValueOrThis { uninit: (), - value: ManuallyDrop>, + value: ManuallyDrop>, this: NonNull<()>, } @@ -568,7 +661,7 @@ mod job { ManuallyDrop::take(&mut (&mut *self.val_or_this.get()).value) }; - Ok(val.get()) + Ok(val.into_inner()) }; return result; @@ -647,7 +740,7 @@ mod job { match result { Ok(val) => unsafe { - (&mut *self.val_or_this.get()).value = ManuallyDrop::new(Value::new(val)); + (&mut *self.val_or_this.get()).value = ManuallyDrop::new(SmallBox::new(val)); (&mut *self.err_or_link.get()).error = ManuallyDrop::new(None); }, Err(err) => unsafe { diff --git a/src/praetor/tests.rs b/src/praetor/tests.rs index dbabd5f..2b3128a 100644 --- a/src/praetor/tests.rs +++ b/src/praetor/tests.rs @@ -201,9 +201,9 @@ fn tagged_ptr_exchange_failure() { #[test] fn value_inline() { - let val = Value::new(3usize); + let val = SmallBox::new(3usize); - let inner = val.get(); + let inner = val.into_inner(); assert_eq!(inner, 3usize); } @@ -213,15 +213,15 @@ fn value_inline_struct() { struct Small { c: f32, } - let val = Value::new(Small { c: 3.2 }); + let val = SmallBox::new(Small { c: 3.2 }); - let inner = val.get(); + let inner = val.into_inner(); assert_eq!(inner.c, 3.2); } #[test] fn value_inline_ptr_sized() { - assert!(Value::::is_inline()); + assert!(SmallBox::::is_inline()); } #[test] @@ -232,13 +232,13 @@ fn value_boxed() { b: f32, c: u32, } - let val = Value::new(Big { + let val = SmallBox::new(Big { a: 42, b: 2.25, c: 7, }); - let inner = val.get(); + let inner = val.into_inner(); assert_eq!( inner, Big { @@ -261,21 +261,21 @@ fn value_inline_drop() { *self.inner += 1; } } - assert!(Value::>::is_inline()); + assert!(SmallBox::>::is_inline()); let mut dropped = 0; { let inner = { - let val = Value::new(Small { + let val = SmallBox::new(Small { inner: &mut dropped, }); - val.get() + val.into_inner() }; assert_eq!(*inner.inner, 0); } assert_eq!(dropped, 1); { - let _val = Value::new(Small { + let _val = SmallBox::new(Small { inner: &mut dropped, }); } @@ -297,18 +297,18 @@ fn value_boxed_drop() { let mut dropped = 0; { let inner = { - let val = Value::new(Big { + let val = SmallBox::new(Big { inner: &mut dropped, pad: [0; 3], }); - val.get() + val.into_inner() }; assert_eq!(*inner.inner, 0); } assert_eq!(dropped, 1); { - let _val = Value::new(Big { + let _val = SmallBox::new(Big { inner: &mut dropped, pad: [0; 3], });