rename extra to other

this is a breaking change
This commit is contained in:
nora 2022-04-06 20:04:49 +02:00
parent 299e1613ff
commit bde74a68ba
4 changed files with 167 additions and 160 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "stuff" name = "stuff"
version = "0.1.4" version = "0.2.0"
edition = "2018" edition = "2018"
description = "Stuffing things into pointers." description = "Stuffing things into pointers."
readme = "./README.md" readme = "./README.md"

View file

@ -20,10 +20,10 @@ the user, allowing the user to do their bit stuffing only on integers (pointer a
`StuffedPtr` is the main type of this crate. It's a type whose size depends on the `StuffedPtr` is the main type of this crate. It's a type whose size depends on the
choice of `Backend` (defaults to `usize`, `u64` and `u128` are also possible). It can store a choice of `Backend` (defaults to `usize`, `u64` and `u128` are also possible). It can store a
pointer or some extra data. pointer or some `other` data.
You can choose any arbitrary bitstuffing depending on the `StuffingStrategy`, an unsafe trait that governs You can choose any arbitrary bitstuffing depending on the `StuffingStrategy`, an unsafe trait that governs
how the extra data (or the pointer itself) will be packed into the backend. While this trait is still unsafe, how the `other` data (or the pointer itself) will be packed into the backend. While this trait is still unsafe,
it's a lot safer than doing everything by hand. it's a lot safer than doing everything by hand.
# Example: NaN-Boxing # Example: NaN-Boxing
@ -36,27 +36,29 @@ for more details.
```rust ```rust
use std::collections::HashMap; use std::collections::HashMap;
use stuff::{StuffedPtr, StuffingStrategy}; use stuff::{StuffedPtr, StuffingStrategy};
// Create a unit struct for our strategy // Create a unit struct for our strategy
struct NanBoxStrategy; struct NanBoxStrategy;
const QNAN: u64 = 0x7ffc000000000000; // implementation detail of NaN boxing, a quiet NaN mask // implementation detail of NaN boxing, a quiet NaN mask
const QNAN: u64 = 0x7ffc000000000000;
const SIGN_BIT: u64 = 0x8000000000000000; // implementation detail of NaN boxing, the sign bit of an f64 // implementation detail of NaN boxing, the sign bit of an f64
const SIGN_BIT: u64 = 0x8000000000000000;
unsafe impl StuffingStrategy<u64> for NanBoxStrategy { unsafe impl StuffingStrategy<u64> for NanBoxStrategy {
type Extra = f64; type Other = f64;
fn is_extra(data: u64) -> bool { fn is_other(data: u64) -> bool {
(data & QNAN) != QNAN (data & QNAN) != QNAN
} }
fn stuff_extra(inner: Self::Extra) -> u64 { fn stuff_other(inner: Self::Other) -> u64 {
unsafe { std::mem::transmute(inner) } // both are 64 bit POD's unsafe { std::mem::transmute(inner) } // both are 64 bit POD's
} }
unsafe fn extract_extra(data: u64) -> Self::Extra { unsafe fn extract_other(data: u64) -> Self::Other {
std::mem::transmute(data) // both are 64 bit POD's std::mem::transmute(data) // both are 64 bit POD's
} }
@ -71,16 +73,17 @@ unsafe impl StuffingStrategy<u64> for NanBoxStrategy {
} }
} }
type Object = HashMap<String, u32>; // a very, very crude representation of an object // a very, very crude representation of an object
type Object = HashMap<String, u32>;
type Value = StuffedPtr<Object, NanBoxStrategy, u64>; // our value type // our value type
type Value = StuffedPtr<Object, NanBoxStrategy, u64>;
fn main() { fn main() {
let float: Value = StuffedPtr::new_extra(123.5); let float: Value = StuffedPtr::new_other(123.5);
assert_eq!(float.copy_extra(), Some(123.5)); assert_eq!(float.copy_other(), Some(123.5));
let object: Object = HashMap::from([("a".to_owned(), 457)]); let object: Object = HashMap::from([("a".to_owned(), 457)]);
let boxed = Box::new(object); let boxed = Box::new(object);
let ptr: Value = StuffedPtr::new_ptr(Box::into_raw(boxed)); let ptr: Value = StuffedPtr::new_ptr(Box::into_raw(boxed));
@ -88,7 +91,7 @@ fn main() {
assert_eq!(object.get("a"), Some(&457)); assert_eq!(object.get("a"), Some(&457));
drop(unsafe { Box::from_raw(ptr.get_ptr().unwrap()) }); drop(unsafe { Box::from_raw(ptr.get_ptr().unwrap()) });
// `ptr` is a dangling pointer now! // be careful, `ptr` is a dangling pointer now!
} }
``` ```

View file

@ -13,10 +13,10 @@
//! //!
//! [`StuffedPtr`] is the main type of this crate. You it's a type whose size depends on the //! [`StuffedPtr`] is the main type of this crate. You it's a type whose size depends on the
//! choice of [`Backend`] (defaults to `usize`, `u64` and `u128` are also possible). It can store a //! choice of [`Backend`] (defaults to `usize`, `u64` and `u128` are also possible). It can store a
//! pointer or some extra data. //! pointer or some `other` data.
//! //!
//! You can choose any arbitrary bitstuffing depending on the [`StuffingStrategy`], an unsafe trait that governs //! You can choose any arbitrary bitstuffing depending on the [`StuffingStrategy`], an unsafe trait that governs
//! how the extra data (or the pointer itself) will be packed into the backend. While this trait is still unsafe, //! how the `other` data (or the pointer itself) will be packed into the backend. While this trait is still unsafe,
//! it's a lot safer than doing everything by hand. //! it's a lot safer than doing everything by hand.
//! //!
//! # Example: NaN-Boxing //! # Example: NaN-Boxing
@ -35,21 +35,23 @@
//! // Create a unit struct for our strategy //! // Create a unit struct for our strategy
//! struct NanBoxStrategy; //! struct NanBoxStrategy;
//! //!
//! const QNAN: u64 = 0x7ffc000000000000; // implementation detail of NaN boxing, a quiet NaN mask //! // implementation detail of NaN boxing, a quiet NaN mask
//! const SIGN_BIT: u64 = 0x8000000000000000; // implementation detail of NaN boxing, the sign bit of an f64 //! const QNAN: u64 = 0x7ffc000000000000;
//! // implementation detail of NaN boxing, the sign bit of an f64
//! const SIGN_BIT: u64 = 0x8000000000000000;
//! //!
//! unsafe impl StuffingStrategy<u64> for NanBoxStrategy { //! unsafe impl StuffingStrategy<u64> for NanBoxStrategy {
//! type Extra = f64; //! type Other = f64;
//! //!
//! fn is_extra(data: u64) -> bool { //! fn is_other(data: u64) -> bool {
//! (data & QNAN) != QNAN //! (data & QNAN) != QNAN
//! } //! }
//! //!
//! fn stuff_extra(inner: Self::Extra) -> u64 { //! fn stuff_other(inner: Self::Other) -> u64 {
//! unsafe { std::mem::transmute(inner) } // both are 64 bit POD's //! unsafe { std::mem::transmute(inner) } // both are 64 bit POD's
//! } //! }
//! //!
//! unsafe fn extract_extra(data: u64) -> Self::Extra { //! unsafe fn extract_other(data: u64) -> Self::Other {
//! std::mem::transmute(data) // both are 64 bit POD's //! std::mem::transmute(data) // both are 64 bit POD's
//! } //! }
//! //!
@ -64,12 +66,14 @@
//! } //! }
//! } //! }
//! //!
//! type Object = HashMap<String, u32>; // a very, very crude representation of an object //! // a very, very crude representation of an object
//! type Object = HashMap<String, u32>;
//! //!
//! type Value = StuffedPtr<Object, NanBoxStrategy, u64>; // our value type //! // our value type
//! type Value = StuffedPtr<Object, NanBoxStrategy, u64>;
//! //!
//! let float: Value = StuffedPtr::new_extra(123.5); //! let float: Value = StuffedPtr::new_other(123.5);
//! assert_eq!(float.copy_extra(), Some(123.5)); //! assert_eq!(float.copy_other(), Some(123.5));
//! //!
//! let object: Object = HashMap::from([("a".to_owned(), 457)]); //! let object: Object = HashMap::from([("a".to_owned(), 457)]);
//! let boxed = Box::new(object); //! let boxed = Box::new(object);
@ -80,7 +84,7 @@
//! //!
//! drop(unsafe { Box::from_raw(ptr.get_ptr().unwrap()) }); //! drop(unsafe { Box::from_raw(ptr.get_ptr().unwrap()) });
//! //!
//! // `ptr` is a dangling pointer now! //! // be careful, `ptr` is a dangling pointer now!
//! ``` //! ```
#[cfg(test)] #[cfg(test)]
@ -101,7 +105,7 @@ use sptr::Strict;
pub use crate::{backend::Backend, strategy::StuffingStrategy}; pub use crate::{backend::Backend, strategy::StuffingStrategy};
/// A union of a pointer or some extra data, bitpacked into a value with the size depending on /// A union of a pointer or some `other` data, bitpacked into a value with the size depending on
/// `B`. It defaults to `usize`, meaning pointer sized, but `u64` and `u128` are also provided /// `B`. It defaults to `usize`, meaning pointer sized, but `u64` and `u128` are also provided
/// by this crate. You can also provide your own [`Backend`] implementation /// by this crate. You can also provide your own [`Backend`] implementation
/// ///
@ -111,9 +115,9 @@ pub use crate::{backend::Backend, strategy::StuffingStrategy};
/// ///
/// For a usage example, view the crate level documentation. /// For a usage example, view the crate level documentation.
/// ///
/// This pointer does *not* drop extra data, [`StuffedPtr::into_extra`] can be used if that is required. /// This pointer does *not* drop `other` data, [`StuffedPtr::into_other`] can be used if that is required.
/// ///
/// `StuffedPtr` implements most traits like `Clone`, `PartialEq` or `Copy` if the extra type does. /// `StuffedPtr` implements most traits like `Clone`, `PartialEq` or `Copy` if the `other` type does.
/// ///
/// This type is guaranteed to be `#[repr(transparent)]` to a `B::Stored`. /// This type is guaranteed to be `#[repr(transparent)]` to a `B::Stored`.
#[repr(transparent)] #[repr(transparent)]
@ -134,20 +138,20 @@ where
StuffedPtr(B::set_ptr(ptr, stuffed), PhantomData) StuffedPtr(B::set_ptr(ptr, stuffed), PhantomData)
} }
/// Create a new `StuffPtr` from extra data /// Create a new `StuffPtr` from `other` data
pub fn new_extra(extra: S::Extra) -> Self { pub fn new_other(other: S::Other) -> Self {
// this doesn't have any provenance, which is ok, since it's never a pointer anyways. // this doesn't have any provenance, which is ok, since it's never a pointer anyways.
// if the user calls `set_ptr` it will use the new provenance from that ptr // if the user calls `set_ptr` it will use the new provenance from that ptr
let ptr = core::ptr::null_mut(); let ptr = core::ptr::null_mut();
let extra = S::stuff_extra(extra); let other = S::stuff_other(other);
StuffedPtr(B::set_ptr(ptr, extra), PhantomData) StuffedPtr(B::set_ptr(ptr, other), PhantomData)
} }
/// Get the pointer data, or `None` if it contains extra data /// Get the pointer data, or `None` if it contains `other` data
pub fn get_ptr(&self) -> Option<*mut T> { pub fn get_ptr(&self) -> Option<*mut T> {
match self.is_extra().not() { match self.is_other().not() {
true => { true => {
// SAFETY: We have done a check that it's not extra // SAFETY: We have done a check that it's not other
unsafe { Some(self.get_ptr_unchecked()) } unsafe { Some(self.get_ptr_unchecked()) }
} }
false => None, false => None,
@ -158,103 +162,103 @@ where
/// contains pointer data. /// contains pointer data.
/// ///
/// # Safety /// # Safety
/// `StuffedPtr` must contain pointer data and not extra data /// `StuffedPtr` must contain pointer data and not `other` data
pub unsafe fn get_ptr_unchecked(&self) -> *mut T { pub unsafe fn get_ptr_unchecked(&self) -> *mut T {
let (provenance, addr) = B::get_ptr(self.0); let (provenance, addr) = B::get_ptr(self.0);
let addr = S::extract_ptr(addr); let addr = S::extract_ptr(addr);
Strict::with_addr(provenance, addr) Strict::with_addr(provenance, addr)
} }
/// Get owned extra data from this, or `None` if it contains pointer data /// Get owned `other` data from this, or `None` if it contains pointer data
pub fn into_extra(self) -> Option<S::Extra> { pub fn into_other(self) -> Option<S::Other> {
match self.is_extra() { match self.is_other() {
true => { true => {
// SAFETY: We checked that it contains an extra above // SAFETY: We checked that it contains an other above
unsafe { Some(self.into_extra_unchecked()) } unsafe { Some(self.into_other_unchecked()) }
} }
false => None, false => None,
} }
} }
/// Turn this pointer into extra data. /// Turn this pointer into `other` data.
/// # Safety /// # Safety
/// `StuffedPtr` must contain extra data and not pointer /// `StuffedPtr` must contain `other` data and not pointer
pub unsafe fn into_extra_unchecked(self) -> S::Extra { pub unsafe fn into_other_unchecked(self) -> S::Other {
// SAFETY: `self` is consumed and forgotten after this call // SAFETY: `self` is consumed and forgotten after this call
let extra = self.get_extra_unchecked(); let other = self.get_other_unchecked();
mem::forget(self); mem::forget(self);
extra other
} }
/// Get extra data from this, or `None` if it contains pointer data /// Get `other` data from this, or `None` if it contains pointer data
/// # Safety /// # Safety
/// The caller must guarantee that only ever on `Extra` exists if `Extra: !Copy` /// The caller must guarantee that only ever on `Other` exists if `Other: !Copy`
pub unsafe fn get_extra(&self) -> Option<S::Extra> { pub unsafe fn get_other(&self) -> Option<S::Other> {
match self.is_extra() { match self.is_other() {
true => { true => {
// SAFETY: We checked that it contains extra above, the caller guarantees the rest // SAFETY: We checked that it contains other above, the caller guarantees the rest
Some(self.get_extra_unchecked()) Some(self.get_other_unchecked())
} }
false => None, false => None,
} }
} }
/// Get extra data from this /// Get `other` data from this
/// # Safety /// # Safety
/// Must contain extra data and not pointer data, /// Must contain `other` data and not pointer data,
/// and the caller must guarantee that only ever on `Extra` exists if `Extra: !Copy` /// and the caller must guarantee that only ever on `Other` exists if `Other: !Copy`
pub unsafe fn get_extra_unchecked(&self) -> S::Extra { pub unsafe fn get_other_unchecked(&self) -> S::Other {
let data = self.addr(); let data = self.addr();
S::extract_extra(data) S::extract_other(data)
} }
fn addr(&self) -> B { fn addr(&self) -> B {
B::get_int(self.0) B::get_int(self.0)
} }
fn is_extra(&self) -> bool { fn is_other(&self) -> bool {
S::is_extra(self.addr()) S::is_other(self.addr())
} }
} }
/// Extra implementations if the extra type is `Copy` /// Extra implementations if the `other` type is `Copy`
impl<T, S, B> StuffedPtr<T, S, B> impl<T, S, B> StuffedPtr<T, S, B>
where where
S: StuffingStrategy<B>, S: StuffingStrategy<B>,
S::Extra: Copy, S::Other: Copy,
B: Backend<T>, B: Backend<T>,
{ {
/// Get extra data from this, or `None` if it's pointer data /// Get `other` data from this, or `None` if it's pointer data
pub fn copy_extra(&self) -> Option<S::Extra> { pub fn copy_other(&self) -> Option<S::Other> {
// SAFETY: `S::Extra: Copy` // SAFETY: `S::Other: Copy`
unsafe { self.get_extra() } unsafe { self.get_other() }
} }
/// Get extra data from this /// Get `other` data from this
/// # Safety /// # Safety
/// Must contain extra data and not pointer data, /// Must contain `other` data and not pointer data,
pub unsafe fn copy_extra_unchecked(&self) -> S::Extra { pub unsafe fn copy_other_unchecked(&self) -> S::Other {
// SAFETY: `S::Extra: Copy`, and the caller guarantees that it's extra // SAFETY: `S::Other: Copy`, and the caller guarantees that it's other
self.get_extra_unchecked() self.get_other_unchecked()
} }
} }
impl<T, S, B> Debug for StuffedPtr<T, S, B> impl<T, S, B> Debug for StuffedPtr<T, S, B>
where where
S: StuffingStrategy<B>, S: StuffingStrategy<B>,
S::Extra: Debug, S::Other: Debug,
B: Backend<T>, B: Backend<T>,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
// SAFETY: // SAFETY:
// If S::Extra: !Copy, we can't just copy it out and call it a day // If S::Other: !Copy, we can't just copy it out and call it a day
// For example, if it's a Box, not forgetting it here would lead to a double free // For example, if it's a Box, not forgetting it here would lead to a double free
// So we just format it and forget it afterwards // So we just format it and forget it afterwards
if let Some(extra) = unsafe { self.get_extra() } { if let Some(other) = unsafe { self.get_other() } {
f.debug_struct("StuffedPtr::Extra") f.debug_struct("StuffedPtr::Other")
.field("extra", &extra) .field("other", &other)
.finish()?; .finish()?;
mem::forget(extra); mem::forget(other);
Ok(()) Ok(())
} else { } else {
// SAFETY: Checked above // SAFETY: Checked above
@ -269,15 +273,15 @@ where
impl<T, S, B> Clone for StuffedPtr<T, S, B> impl<T, S, B> Clone for StuffedPtr<T, S, B>
where where
S: StuffingStrategy<B>, S: StuffingStrategy<B>,
S::Extra: Clone, S::Other: Clone,
B: Backend<T>, B: Backend<T>,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
// SAFETY: We forget that `extra` ever existed after taking the reference and cloning it // SAFETY: We forget that `other` ever existed after taking the reference and cloning it
if let Some(extra) = unsafe { self.get_extra() } { if let Some(other) = unsafe { self.get_other() } {
let cloned_extra = extra.clone(); let cloned_other = other.clone();
mem::forget(extra); mem::forget(other);
Self::new_extra(cloned_extra) Self::new_other(cloned_other)
} else { } else {
// just copy the pointer // just copy the pointer
StuffedPtr(self.0, PhantomData) StuffedPtr(self.0, PhantomData)
@ -288,7 +292,7 @@ where
impl<T, S, B> Copy for StuffedPtr<T, S, B> impl<T, S, B> Copy for StuffedPtr<T, S, B>
where where
S: StuffingStrategy<B>, S: StuffingStrategy<B>,
S::Extra: Copy, S::Other: Copy,
B: Backend<T>, B: Backend<T>,
{ {
} }
@ -296,17 +300,17 @@ where
impl<T, S, B> PartialEq for StuffedPtr<T, S, B> impl<T, S, B> PartialEq for StuffedPtr<T, S, B>
where where
S: StuffingStrategy<B>, S: StuffingStrategy<B>,
S::Extra: PartialEq, S::Other: PartialEq,
B: Backend<T>, B: Backend<T>,
{ {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
// SAFETY: We forget them after // SAFETY: We forget them after
let extras = unsafe { (self.get_extra(), other.get_extra()) }; let others = unsafe { (self.get_other(), other.get_other()) };
let eq = match &extras { let eq = match &others {
(Some(extra1), Some(extra2)) => extra1.eq(extra2), (Some(other1), Some(other2)) => other1.eq(other2),
(None, None) => { (None, None) => {
// SAFETY: `get_extra` returned `None`, so it must be a ptr // SAFETY: `get_other` returned `None`, so it must be a ptr
unsafe { unsafe {
let ptr1 = self.get_ptr_unchecked(); let ptr1 = self.get_ptr_unchecked();
let ptr2 = self.get_ptr_unchecked(); let ptr2 = self.get_ptr_unchecked();
@ -316,7 +320,7 @@ where
_ => false, _ => false,
}; };
mem::forget(extras); mem::forget(others);
eq eq
} }
@ -325,7 +329,7 @@ where
impl<T, S, B> Eq for StuffedPtr<T, S, B> impl<T, S, B> Eq for StuffedPtr<T, S, B>
where where
S: StuffingStrategy<B>, S: StuffingStrategy<B>,
S::Extra: PartialEq + Eq, S::Other: PartialEq + Eq,
B: Backend<T>, B: Backend<T>,
{ {
} }
@ -333,14 +337,14 @@ where
impl<T, S, B> Hash for StuffedPtr<T, S, B> impl<T, S, B> Hash for StuffedPtr<T, S, B>
where where
S: StuffingStrategy<B>, S: StuffingStrategy<B>,
S::Extra: Hash, S::Other: Hash,
B: Backend<T>, B: Backend<T>,
{ {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
// SAFETY: We forget that `extra` ever existed after taking the reference and cloning it // SAFETY: We forget that `other` ever existed after taking the reference and cloning it
if let Some(extra) = unsafe { self.get_extra() } { if let Some(other) = unsafe { self.get_other() } {
extra.hash(state); other.hash(state);
mem::forget(extra); mem::forget(other);
} else { } else {
// SAFETY: Checked above // SAFETY: Checked above
let ptr = unsafe { self.get_ptr_unchecked() }; let ptr = unsafe { self.get_ptr_unchecked() };
@ -364,7 +368,7 @@ mod tests {
}; };
// note: the tests mostly use the `PanicsInDrop` type and strategy, to make sure that no // note: the tests mostly use the `PanicsInDrop` type and strategy, to make sure that no
// extra is ever dropped accidentally. // `other` is ever dropped accidentally.
fn from_box<T, S, B>(boxed: Box<T>) -> StuffedPtr<T, S, B> fn from_box<T, S, B>(boxed: Box<T>) -> StuffedPtr<T, S, B>
where where
@ -378,7 +382,7 @@ mod tests {
($backend:ident) => { ($backend:ident) => {
paste! { paste! {
#[test] #[test]
fn [<set_get_ptr_no_extra__ $backend>]() { fn [<set_get_ptr_no_other__ $backend>]() {
unsafe { unsafe {
let boxed = Box::new(1); let boxed = Box::new(1);
let stuffed_ptr: StuffedPtr<i32, (), $backend> = from_box(boxed); let stuffed_ptr: StuffedPtr<i32, (), $backend> = from_box(boxed);
@ -390,10 +394,10 @@ mod tests {
#[test] #[test]
fn [<get_extra__ $backend>]() { fn [<get_other__ $backend>]() {
let stuffed_ptr: StuffedPtr<(), EmptyInMax, $backend> = StuffedPtr::new_extra(EmptyInMax); let stuffed_ptr: StuffedPtr<(), EmptyInMax, $backend> = StuffedPtr::new_other(EmptyInMax);
assert!(stuffed_ptr.is_extra()); assert!(stuffed_ptr.is_other());
assert!(matches!(stuffed_ptr.copy_extra(), Some(EmptyInMax))); assert!(matches!(stuffed_ptr.copy_other(), Some(EmptyInMax)));
} }
#[test] #[test]
@ -404,11 +408,11 @@ mod tests {
drop(unsafe { Box::from_raw(stuffed_ptr.get_ptr().unwrap()) }); drop(unsafe { Box::from_raw(stuffed_ptr.get_ptr().unwrap()) });
let extra = HasDebug; let other = HasDebug;
let stuffed_ptr: StuffedPtr<i32, HasDebug, $backend> = StuffedPtr::new_extra(extra); let stuffed_ptr: StuffedPtr<i32, HasDebug, $backend> = StuffedPtr::new_other(other);
assert_eq!( assert_eq!(
format!("{stuffed_ptr:?}"), format!("{stuffed_ptr:?}"),
"StuffedPtr::Extra { extra: hello! }" "StuffedPtr::Other { other: hello! }"
); );
} }
@ -419,7 +423,7 @@ mod tests {
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit); let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit);
let _ = stuffed_ptr1.clone(); let _ = stuffed_ptr1.clone();
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop); let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_other(PanicsInDrop);
let stuffed_ptr2 = stuffed_ptr1.clone(); let stuffed_ptr2 = stuffed_ptr1.clone();
mem::forget((stuffed_ptr1, stuffed_ptr2)); mem::forget((stuffed_ptr1, stuffed_ptr2));
@ -436,7 +440,7 @@ mod tests {
assert_eq!(stuffed_ptr1, stuffed_ptr2); assert_eq!(stuffed_ptr1, stuffed_ptr2);
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit); let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit);
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop); let stuffed_ptr2: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_other(PanicsInDrop);
assert_ne!(stuffed_ptr1, stuffed_ptr2); assert_ne!(stuffed_ptr1, stuffed_ptr2);
mem::forget(stuffed_ptr2); mem::forget(stuffed_ptr2);
@ -444,7 +448,7 @@ mod tests {
#[test] #[test]
fn [<dont_drop_extra_when_pointer__ $backend>]() { fn [<dont_drop_other_when_pointer__ $backend>]() {
let mut unit = (); let mut unit = ();
let stuffed_ptr: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit); let stuffed_ptr: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit);
// the panicking drop needs not to be called here! // the panicking drop needs not to be called here!
@ -454,10 +458,10 @@ mod tests {
#[test] #[test]
fn [<some_traits_dont_drop__ $backend>]() { fn [<some_traits_dont_drop__ $backend>]() {
// make sure that extra is never dropped twice // make sure that other is never dropped twice
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop); let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_other(PanicsInDrop);
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop); let stuffed_ptr2: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_other(PanicsInDrop);
// PartialEq // PartialEq
assert_eq!(stuffed_ptr1, stuffed_ptr2); assert_eq!(stuffed_ptr1, stuffed_ptr2);

View file

@ -1,38 +1,38 @@
/// A trait that describes how to stuff extras and pointers into the pointer sized object. /// A trait that describes how to stuff others and pointers into the pointer sized object.
/// ///
/// This trait is what a user of this crate is expected to implement to use the crate for their own /// This trait is what a user of this crate is expected to implement to use the crate for their own
/// pointer stuffing. It's usually implemented on ZSTs that only serve as stuffing strategies, but /// pointer stuffing. It's usually implemented on ZSTs that only serve as stuffing strategies, but
/// it's also completely possible to implement it on the type in [`StuffingStrategy::Extra`] directly /// it's also completely possible to implement it on the type in [`StuffingStrategy::Other`] directly
/// if possible. /// if possible.
/// ///
/// The generic parameter `B` stands for the [`Backend`](`crate::Backend`) used by the strategy. /// The generic parameter `B` stands for the [`Backend`](`crate::Backend`) used by the strategy.
/// ///
/// # Safety /// # Safety
/// ///
/// If [`StuffingStrategy::is_extra`] returns true for a value, then /// If [`StuffingStrategy::is_other`] returns true for a value, then
/// [`StuffingStrategy::extract_extra`] *must* return a valid `Extra` for that same value. /// [`StuffingStrategy::extract_other`] *must* return a valid `Other` for that same value.
/// ///
/// [`StuffingStrategy::stuff_extra`] *must* consume `inner` and make sure that it's not dropped /// [`StuffingStrategy::stuff_other`] *must* consume `inner` and make sure that it's not dropped
/// if it isn't `Copy`. /// if it isn't `Copy`.
/// ///
/// For [`StuffingStrategy::stuff_ptr`] and [`StuffingStrategy::extract_ptr`], /// For [`StuffingStrategy::stuff_ptr`] and [`StuffingStrategy::extract_ptr`],
/// `ptr == extract_ptr(stuff_ptr(ptr))` *must* hold true. /// `ptr == extract_ptr(stuff_ptr(ptr))` *must* hold true.
pub unsafe trait StuffingStrategy<B> { pub unsafe trait StuffingStrategy<B> {
/// The type of the extra. /// The type of the other.
type Extra; type Other;
/// Checks whether the `StufferPtr` data value contains an extra value. The result of this /// Checks whether the `StufferPtr` data value contains an other value. The result of this
/// function can be trusted. /// function can be trusted.
fn is_extra(data: B) -> bool; fn is_other(data: B) -> bool;
/// Stuff extra data into a usize that is then put into the pointer. This operation /// Stuff other data into a usize that is then put into the pointer. This operation
/// must be infallible. /// must be infallible.
fn stuff_extra(inner: Self::Extra) -> B; fn stuff_other(inner: Self::Other) -> B;
/// Extract extra data from the data. /// Extract other data from the data.
/// # Safety /// # Safety
/// `data` must contain data created by [`StuffingStrategy::stuff_extra`]. /// `data` must contain data created by [`StuffingStrategy::stuff_other`].
unsafe fn extract_extra(data: B) -> Self::Extra; unsafe fn extract_other(data: B) -> Self::Other;
/// Stuff a pointer address into the pointer sized integer. /// Stuff a pointer address into the pointer sized integer.
/// ///
@ -49,17 +49,17 @@ pub unsafe trait StuffingStrategy<B> {
} }
unsafe impl StuffingStrategy<usize> for () { unsafe impl StuffingStrategy<usize> for () {
type Extra = (); type Other = ();
fn is_extra(_data: usize) -> bool { fn is_other(_data: usize) -> bool {
false false
} }
fn stuff_extra(_inner: Self::Extra) -> usize { fn stuff_other(_inner: Self::Other) -> usize {
0 0
} }
unsafe fn extract_extra(_data: usize) -> Self::Extra {} unsafe fn extract_other(_data: usize) -> Self::Other {}
fn stuff_ptr(addr: usize) -> usize { fn stuff_ptr(addr: usize) -> usize {
addr addr
@ -71,17 +71,17 @@ unsafe impl StuffingStrategy<usize> for () {
} }
unsafe impl StuffingStrategy<u64> for () { unsafe impl StuffingStrategy<u64> for () {
type Extra = (); type Other = ();
fn is_extra(_data: u64) -> bool { fn is_other(_data: u64) -> bool {
false false
} }
fn stuff_extra(_inner: Self::Extra) -> u64 { fn stuff_other(_inner: Self::Other) -> u64 {
0 0
} }
unsafe fn extract_extra(_data: u64) -> Self::Extra {} unsafe fn extract_other(_data: u64) -> Self::Other {}
fn stuff_ptr(addr: usize) -> u64 { fn stuff_ptr(addr: usize) -> u64 {
addr as u64 addr as u64
@ -93,17 +93,17 @@ unsafe impl StuffingStrategy<u64> for () {
} }
unsafe impl StuffingStrategy<u128> for () { unsafe impl StuffingStrategy<u128> for () {
type Extra = (); type Other = ();
fn is_extra(_data: u128) -> bool { fn is_other(_data: u128) -> bool {
false false
} }
fn stuff_extra(_inner: Self::Extra) -> u128 { fn stuff_other(_inner: Self::Other) -> u128 {
0 0
} }
unsafe fn extract_extra(_data: u128) -> Self::Extra {} unsafe fn extract_other(_data: u128) -> Self::Other {}
fn stuff_ptr(addr: usize) -> u128 { fn stuff_ptr(addr: usize) -> u128 {
addr as u128 addr as u128
@ -124,19 +124,19 @@ pub(crate) mod test_strategies {
($ty:ident) => { ($ty:ident) => {
// this one lives in usize::MAX // this one lives in usize::MAX
unsafe impl StuffingStrategy<usize> for $ty { unsafe impl StuffingStrategy<usize> for $ty {
type Extra = Self; type Other = Self;
fn is_extra(data: usize) -> bool { fn is_other(data: usize) -> bool {
data == usize::MAX data == usize::MAX
} }
#[allow(clippy::forget_copy)] #[allow(clippy::forget_copy)]
fn stuff_extra(inner: Self::Extra) -> usize { fn stuff_other(inner: Self::Other) -> usize {
core::mem::forget(inner); core::mem::forget(inner);
usize::MAX usize::MAX
} }
unsafe fn extract_extra(_data: usize) -> Self::Extra { unsafe fn extract_other(_data: usize) -> Self::Other {
$ty $ty
} }
@ -149,19 +149,19 @@ pub(crate) mod test_strategies {
} }
} }
unsafe impl StuffingStrategy<u64> for $ty { unsafe impl StuffingStrategy<u64> for $ty {
type Extra = Self; type Other = Self;
fn is_extra(data: u64) -> bool { fn is_other(data: u64) -> bool {
data == u64::MAX data == u64::MAX
} }
#[allow(clippy::forget_copy)] #[allow(clippy::forget_copy)]
fn stuff_extra(inner: Self::Extra) -> u64 { fn stuff_other(inner: Self::Other) -> u64 {
core::mem::forget(inner); core::mem::forget(inner);
u64::MAX u64::MAX
} }
unsafe fn extract_extra(_data: u64) -> Self::Extra { unsafe fn extract_other(_data: u64) -> Self::Other {
$ty $ty
} }
@ -175,19 +175,19 @@ pub(crate) mod test_strategies {
} }
unsafe impl StuffingStrategy<u128> for $ty { unsafe impl StuffingStrategy<u128> for $ty {
type Extra = Self; type Other = Self;
fn is_extra(data: u128) -> bool { fn is_other(data: u128) -> bool {
data == u128::MAX data == u128::MAX
} }
#[allow(clippy::forget_copy)] #[allow(clippy::forget_copy)]
fn stuff_extra(inner: Self::Extra) -> u128 { fn stuff_other(inner: Self::Other) -> u128 {
core::mem::forget(inner); core::mem::forget(inner);
u128::MAX u128::MAX
} }
unsafe fn extract_extra(_data: u128) -> Self::Extra { unsafe fn extract_other(_data: u128) -> Self::Other {
$ty $ty
} }