mirror of
https://github.com/Noratrieb/stuff.git
synced 2026-01-14 16:35:08 +01:00
test all backends!
This commit is contained in:
parent
5164f70545
commit
14e7443532
6 changed files with 374 additions and 234 deletions
3
.rustfmt.toml
Normal file
3
.rustfmt.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
newline_style = "Unix"
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
|
@ -7,3 +7,6 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sptr = "0.2.3"
|
sptr = "0.2.3"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
paste = "1.0.7"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,29 @@
|
||||||
use sptr::Strict;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use sptr::Strict;
|
||||||
|
|
||||||
|
/// A backend where the stuffed pointer is stored. Must be bigger or equal to the pointer size.
|
||||||
pub trait Backend<T> {
|
pub trait Backend<T> {
|
||||||
|
/// The underlying type where the data is stored. Often a tuple of a pointer (for the provenance)
|
||||||
|
/// and some integers to fill up the bytes.
|
||||||
type Stored: Copy;
|
type Stored: Copy;
|
||||||
|
|
||||||
|
/// Get the pointer from the backed. Since the [`crate::StuffingStrategy`] is able to use the full
|
||||||
|
/// bytes to pack in the pointer address, the full address is returned in the second tuple field,
|
||||||
|
/// as the integer. The provenance of the pointer is returned as the first tuple field, but its
|
||||||
|
/// address should be ignored and may be invalid.
|
||||||
fn get_ptr(s: Self::Stored) -> (*mut T, Self);
|
fn get_ptr(s: Self::Stored) -> (*mut T, Self);
|
||||||
|
|
||||||
|
/// Set a new pointer address. The provenance of the new pointer is transferred in the first argument,
|
||||||
|
/// and the address in the second. See [`Backend::get_ptr`] for more details on the separation.
|
||||||
fn set_ptr(provenance: *mut T, addr: Self) -> Self::Stored;
|
fn set_ptr(provenance: *mut T, addr: Self) -> Self::Stored;
|
||||||
|
|
||||||
|
/// Get the integer value from the backend. Note that this *must not* be used to create a pointer,
|
||||||
|
/// for that use [`Backend::get_ptr`] to keep the provenance.
|
||||||
fn get_int(s: Self::Stored) -> Self;
|
fn get_int(s: Self::Stored) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::should_assert_eq, dead_code)] // :/
|
#[allow(dead_code)] // :/
|
||||||
const fn assert_size<B>()
|
const fn assert_size<B>()
|
||||||
where
|
where
|
||||||
B: Backend<()>,
|
B: Backend<()>,
|
||||||
|
|
|
||||||
136
src/lib.rs
136
src/lib.rs
|
|
@ -3,18 +3,28 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
//! A crate for stuffing things into a pointer.
|
//! A crate for stuffing things into a pointer.
|
||||||
|
//!
|
||||||
|
//! This crate consists of three parts:
|
||||||
|
//! * The type [`StuffedPtr`]
|
||||||
|
//! * The trait [`StuffingStrategy`]
|
||||||
|
//! * The trait [`Backend`]
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
pub mod strategies;
|
mod strategy;
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::{
|
||||||
use std::marker::PhantomData;
|
fmt::{Debug, Formatter},
|
||||||
use std::mem;
|
marker::PhantomData,
|
||||||
use std::ops::Not;
|
mem,
|
||||||
|
ops::Not,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::backend::Backend;
|
|
||||||
use sptr::Strict;
|
use sptr::Strict;
|
||||||
|
|
||||||
|
pub use crate::{backend::Backend, strategy::StuffingStrategy};
|
||||||
|
|
||||||
/// A union of a pointer and some extra data.
|
/// A union of a pointer and some extra data.
|
||||||
pub struct StuffedPtr<T, S, I = usize>(I::Stored, PhantomData<S>)
|
pub struct StuffedPtr<T, S, I = usize>(I::Stored, PhantomData<S>)
|
||||||
where
|
where
|
||||||
|
|
@ -235,142 +245,115 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait that describes how to stuff extras and pointers into the pointer sized object.
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// If [`StuffingStrategy::is_extra`] returns true for a value, then
|
|
||||||
/// [`StuffingStrategy::extract_extra`] *must* return a valid `Extra` for that same value.
|
|
||||||
///
|
|
||||||
/// [`StuffingStrategy::stuff_extra`] *must* consume `inner` and make sure that it's not dropped
|
|
||||||
/// if it isn't `Copy`.
|
|
||||||
///
|
|
||||||
/// For [`StuffingStrategy::stuff_ptr`] and [`StuffingStrategy::extract_ptr`],
|
|
||||||
/// `ptr == extract_ptr(stuff_ptr(ptr))` *must* hold true.
|
|
||||||
pub unsafe trait StuffingStrategy<I> {
|
|
||||||
/// The type of the extra.
|
|
||||||
type Extra;
|
|
||||||
|
|
||||||
/// Checks whether the `StufferPtr` data value contains an extra value. The result of this
|
|
||||||
/// function can be trusted.
|
|
||||||
fn is_extra(data: I) -> bool;
|
|
||||||
|
|
||||||
/// Stuff extra data into a usize that is then put into the pointer. This operation
|
|
||||||
/// must be infallible.
|
|
||||||
fn stuff_extra(inner: Self::Extra) -> I;
|
|
||||||
|
|
||||||
/// Extract extra data from the data.
|
|
||||||
/// # Safety
|
|
||||||
/// `data` must contain data created by [`StuffingStrategy::stuff_extra`].
|
|
||||||
unsafe fn extract_extra(data: I) -> Self::Extra;
|
|
||||||
|
|
||||||
/// Stuff a pointer address into the pointer sized integer.
|
|
||||||
///
|
|
||||||
/// This can be used to optimize away some of the unnecessary parts of the pointer or do other
|
|
||||||
/// cursed things with it.
|
|
||||||
///
|
|
||||||
/// The default implementation just returns the address directly.
|
|
||||||
fn stuff_ptr(addr: usize) -> I;
|
|
||||||
|
|
||||||
/// Extract the pointer address from the data.
|
|
||||||
///
|
|
||||||
/// This function expects `inner` to come directly from [`StuffingStrategy::stuff_ptr`].
|
|
||||||
fn extract_ptr(inner: I) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::strategies::test_strategies::{EmptyInMax, HasDebug, PanicsInDrop};
|
#![allow(non_snake_case)]
|
||||||
use crate::StuffedPtr;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
// note: the tests mostly use the `PanicsInDrop` type and strategy, to make sure that no
|
use paste::paste;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
strategy::test_strategies::{EmptyInMax, HasDebug, PanicsInDrop},
|
||||||
|
StuffedPtr,
|
||||||
|
};
|
||||||
|
|
||||||
// extra is ever dropped accidentally.
|
// extra is ever dropped accidentally.
|
||||||
|
|
||||||
|
// note: the tests mostly use the `PanicsInDrop` type and strategy, to make sure that no
|
||||||
|
macro_rules! make_tests {
|
||||||
|
($backend:ident) => {
|
||||||
|
paste! {
|
||||||
#[test]
|
#[test]
|
||||||
fn set_get_ptr_no_extra() {
|
fn [<set_get_ptr_no_extra__ $backend>]() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let boxed = Box::new(1);
|
let boxed = Box::new(1);
|
||||||
let stuffed_ptr: StuffedPtr<i32, ()> = boxed.into();
|
let stuffed_ptr: StuffedPtr<i32, (), $backend> = boxed.into();
|
||||||
let ptr = stuffed_ptr.get_ptr_unchecked();
|
let ptr = stuffed_ptr.get_ptr_unchecked();
|
||||||
let boxed = Box::from_raw(ptr);
|
let boxed = Box::from_raw(ptr);
|
||||||
assert_eq!(*boxed, 1);
|
assert_eq!(*boxed, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_extra() {
|
fn [<get_extra__ $backend>]() {
|
||||||
let stuffed_ptr: StuffedPtr<(), EmptyInMax> = StuffedPtr::new_extra(EmptyInMax);
|
let stuffed_ptr: StuffedPtr<(), EmptyInMax, $backend> = StuffedPtr::new_extra(EmptyInMax);
|
||||||
assert!(stuffed_ptr.is_extra());
|
assert!(stuffed_ptr.is_extra());
|
||||||
assert!(matches!(stuffed_ptr.copy_extra(), Some(EmptyInMax)));
|
assert!(matches!(stuffed_ptr.copy_extra(), Some(EmptyInMax)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn debug() {
|
fn [<debug__ $backend>]() {
|
||||||
let boxed = Box::new(1);
|
let boxed = Box::new(1);
|
||||||
let stuffed_ptr: StuffedPtr<i32, HasDebug> = boxed.into();
|
let stuffed_ptr: StuffedPtr<i32, HasDebug, $backend> = boxed.into();
|
||||||
assert!(format!("{stuffed_ptr:?}").starts_with("StuffedPtr::Ptr {"));
|
assert!(format!("{stuffed_ptr:?}").starts_with("StuffedPtr::Ptr {"));
|
||||||
|
|
||||||
drop(unsafe { Box::from_raw(stuffed_ptr.get_ptr().unwrap()) });
|
drop(unsafe { Box::from_raw(stuffed_ptr.get_ptr().unwrap()) });
|
||||||
|
|
||||||
let extra = HasDebug;
|
let extra = HasDebug;
|
||||||
let stuffed_ptr: StuffedPtr<i32, HasDebug> = StuffedPtr::new_extra(extra);
|
let stuffed_ptr: StuffedPtr<i32, HasDebug, $backend> = StuffedPtr::new_extra(extra);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{stuffed_ptr:?}"),
|
format!("{stuffed_ptr:?}"),
|
||||||
"StuffedPtr::Extra { extra: hello! }"
|
"StuffedPtr::Extra { extra: hello! }"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn drop_extra_when_extra() {
|
fn [<drop_extra_when_extra__ $backend>]() {
|
||||||
let stuffed_ptr: StuffedPtr<(), PanicsInDrop> = StuffedPtr::new_extra(PanicsInDrop);
|
let stuffed_ptr: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop);
|
||||||
// the panicking drop needs to be called here!
|
// the panicking drop needs to be called here!
|
||||||
drop(stuffed_ptr);
|
drop(stuffed_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::redundant_clone)]
|
#[allow(clippy::redundant_clone)]
|
||||||
fn clone() {
|
fn [<clone__ $backend>]() {
|
||||||
let mut unit = ();
|
let mut unit = ();
|
||||||
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop> = 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> = StuffedPtr::new_extra(PanicsInDrop);
|
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn eq() {
|
fn [<eq__ $backend>]() {
|
||||||
// two pointers
|
// two pointers
|
||||||
let mut unit = ();
|
let mut unit = ();
|
||||||
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop> = StuffedPtr::new_ptr(&mut unit);
|
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit);
|
||||||
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop> = StuffedPtr::new_ptr(&mut unit);
|
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit);
|
||||||
|
|
||||||
assert_eq!(stuffed_ptr1, stuffed_ptr2);
|
assert_eq!(stuffed_ptr1, stuffed_ptr2);
|
||||||
|
|
||||||
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop> = StuffedPtr::new_ptr(&mut unit);
|
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_ptr(&mut unit);
|
||||||
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop> = StuffedPtr::new_extra(PanicsInDrop);
|
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop);
|
||||||
|
|
||||||
assert_ne!(stuffed_ptr1, stuffed_ptr2);
|
assert_ne!(stuffed_ptr1, stuffed_ptr2);
|
||||||
mem::forget(stuffed_ptr2);
|
mem::forget(stuffed_ptr2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dont_drop_extra_when_pointer() {
|
fn [<dont_drop_extra_when_pointer__ $backend>]() {
|
||||||
let mut unit = ();
|
let mut unit = ();
|
||||||
let stuffed_ptr: StuffedPtr<(), PanicsInDrop> = 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!
|
||||||
drop(stuffed_ptr);
|
drop(stuffed_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn some_traits_dont_drop() {
|
fn [<some_traits_dont_drop__ $backend>]() {
|
||||||
// make sure that extra is never dropped twice
|
// make sure that extra is never dropped twice
|
||||||
|
|
||||||
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop> = StuffedPtr::new_extra(PanicsInDrop);
|
let stuffed_ptr1: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop);
|
||||||
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop> = StuffedPtr::new_extra(PanicsInDrop);
|
let stuffed_ptr2: StuffedPtr<(), PanicsInDrop, $backend> = StuffedPtr::new_extra(PanicsInDrop);
|
||||||
|
|
||||||
// PartialEq
|
// PartialEq
|
||||||
assert_eq!(stuffed_ptr1, stuffed_ptr2);
|
assert_eq!(stuffed_ptr1, stuffed_ptr2);
|
||||||
|
|
@ -380,3 +363,10 @@ mod tests {
|
||||||
mem::forget((stuffed_ptr1, stuffed_ptr2));
|
mem::forget((stuffed_ptr1, stuffed_ptr2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
make_tests!(u128);
|
||||||
|
make_tests!(u64);
|
||||||
|
make_tests!(usize);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
//! Several pre-defined strategies to use with `StuffedPtr`.
|
|
||||||
//!
|
|
||||||
//! * `()`: An empty strategy, is always the pointer
|
|
||||||
|
|
||||||
use crate::StuffingStrategy;
|
|
||||||
|
|
||||||
unsafe impl StuffingStrategy<usize> for () {
|
|
||||||
type Extra = ();
|
|
||||||
|
|
||||||
fn is_extra(_data: usize) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stuff_extra(_inner: Self::Extra) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn extract_extra(_data: usize) -> Self::Extra {}
|
|
||||||
|
|
||||||
fn stuff_ptr(addr: usize) -> usize {
|
|
||||||
addr
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_ptr(inner: usize) -> usize {
|
|
||||||
inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) mod test_strategies {
|
|
||||||
use crate::StuffingStrategy;
|
|
||||||
use std::fmt::{Debug, Formatter};
|
|
||||||
|
|
||||||
macro_rules! impl_usize_max_zst {
|
|
||||||
($ty:ident) => {
|
|
||||||
// this one lives in usize::MAX
|
|
||||||
unsafe impl StuffingStrategy<usize> for $ty {
|
|
||||||
type Extra = Self;
|
|
||||||
|
|
||||||
fn is_extra(data: usize) -> bool {
|
|
||||||
data == usize::MAX
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::forget_copy)]
|
|
||||||
fn stuff_extra(inner: Self::Extra) -> usize {
|
|
||||||
std::mem::forget(inner);
|
|
||||||
usize::MAX
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn extract_extra(_data: usize) -> Self::Extra {
|
|
||||||
$ty
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stuff_ptr(addr: usize) -> usize {
|
|
||||||
addr
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_ptr(inner: usize) -> usize {
|
|
||||||
inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct EmptyInMax;
|
|
||||||
|
|
||||||
impl_usize_max_zst!(EmptyInMax);
|
|
||||||
|
|
||||||
pub struct HasDebug;
|
|
||||||
|
|
||||||
impl Debug for HasDebug {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_str("hello!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_usize_max_zst!(HasDebug);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct PanicsInDrop;
|
|
||||||
|
|
||||||
impl Drop for PanicsInDrop {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
panic!("oh no!!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_usize_max_zst!(PanicsInDrop);
|
|
||||||
}
|
|
||||||
222
src/strategy.rs
Normal file
222
src/strategy.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
/// A trait that describes how to stuff extras and pointers into the pointer sized object.
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// If [`StuffingStrategy::is_extra`] returns true for a value, then
|
||||||
|
/// [`StuffingStrategy::extract_extra`] *must* return a valid `Extra` for that same value.
|
||||||
|
///
|
||||||
|
/// [`StuffingStrategy::stuff_extra`] *must* consume `inner` and make sure that it's not dropped
|
||||||
|
/// if it isn't `Copy`.
|
||||||
|
///
|
||||||
|
/// For [`StuffingStrategy::stuff_ptr`] and [`StuffingStrategy::extract_ptr`],
|
||||||
|
/// `ptr == extract_ptr(stuff_ptr(ptr))` *must* hold true.
|
||||||
|
pub unsafe trait StuffingStrategy<I> {
|
||||||
|
/// The type of the extra.
|
||||||
|
type Extra;
|
||||||
|
|
||||||
|
/// Checks whether the `StufferPtr` data value contains an extra value. The result of this
|
||||||
|
/// function can be trusted.
|
||||||
|
fn is_extra(data: I) -> bool;
|
||||||
|
|
||||||
|
/// Stuff extra data into a usize that is then put into the pointer. This operation
|
||||||
|
/// must be infallible.
|
||||||
|
fn stuff_extra(inner: Self::Extra) -> I;
|
||||||
|
|
||||||
|
/// Extract extra data from the data.
|
||||||
|
/// # Safety
|
||||||
|
/// `data` must contain data created by [`StuffingStrategy::stuff_extra`].
|
||||||
|
unsafe fn extract_extra(data: I) -> Self::Extra;
|
||||||
|
|
||||||
|
/// Stuff a pointer address into the pointer sized integer.
|
||||||
|
///
|
||||||
|
/// This can be used to optimize away some of the unnecessary parts of the pointer or do other
|
||||||
|
/// cursed things with it.
|
||||||
|
///
|
||||||
|
/// The default implementation just returns the address directly.
|
||||||
|
fn stuff_ptr(addr: usize) -> I;
|
||||||
|
|
||||||
|
/// Extract the pointer address from the data.
|
||||||
|
///
|
||||||
|
/// This function expects `inner` to come directly from [`StuffingStrategy::stuff_ptr`].
|
||||||
|
fn extract_ptr(inner: I) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl StuffingStrategy<usize> for () {
|
||||||
|
type Extra = ();
|
||||||
|
|
||||||
|
fn is_extra(_data: usize) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stuff_extra(_inner: Self::Extra) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn extract_extra(_data: usize) -> Self::Extra {}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> usize {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: usize) -> usize {
|
||||||
|
inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl StuffingStrategy<u64> for () {
|
||||||
|
type Extra = ();
|
||||||
|
|
||||||
|
fn is_extra(_data: u64) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stuff_extra(_inner: Self::Extra) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn extract_extra(_data: u64) -> Self::Extra {}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> u64 {
|
||||||
|
addr as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: u64) -> usize {
|
||||||
|
inner as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl StuffingStrategy<u128> for () {
|
||||||
|
type Extra = ();
|
||||||
|
|
||||||
|
fn is_extra(_data: u128) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stuff_extra(_inner: Self::Extra) -> u128 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn extract_extra(_data: u128) -> Self::Extra {}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> u128 {
|
||||||
|
addr as u128
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: u128) -> usize {
|
||||||
|
inner as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) mod test_strategies {
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
|
use super::StuffingStrategy;
|
||||||
|
|
||||||
|
macro_rules! impl_usize_max_zst {
|
||||||
|
($ty:ident) => {
|
||||||
|
// this one lives in usize::MAX
|
||||||
|
unsafe impl StuffingStrategy<usize> for $ty {
|
||||||
|
type Extra = Self;
|
||||||
|
|
||||||
|
fn is_extra(data: usize) -> bool {
|
||||||
|
data == usize::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::forget_copy)]
|
||||||
|
fn stuff_extra(inner: Self::Extra) -> usize {
|
||||||
|
std::mem::forget(inner);
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn extract_extra(_data: usize) -> Self::Extra {
|
||||||
|
$ty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> usize {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: usize) -> usize {
|
||||||
|
inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl StuffingStrategy<u64> for $ty {
|
||||||
|
type Extra = Self;
|
||||||
|
|
||||||
|
fn is_extra(data: u64) -> bool {
|
||||||
|
data == u64::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::forget_copy)]
|
||||||
|
fn stuff_extra(inner: Self::Extra) -> u64 {
|
||||||
|
std::mem::forget(inner);
|
||||||
|
u64::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn extract_extra(_data: u64) -> Self::Extra {
|
||||||
|
$ty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> u64 {
|
||||||
|
addr as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: u64) -> usize {
|
||||||
|
inner as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl StuffingStrategy<u128> for $ty {
|
||||||
|
type Extra = Self;
|
||||||
|
|
||||||
|
fn is_extra(data: u128) -> bool {
|
||||||
|
data == u128::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::forget_copy)]
|
||||||
|
fn stuff_extra(inner: Self::Extra) -> u128 {
|
||||||
|
std::mem::forget(inner);
|
||||||
|
u128::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn extract_extra(_data: u128) -> Self::Extra {
|
||||||
|
$ty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> u128 {
|
||||||
|
addr as u128
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: u128) -> usize {
|
||||||
|
inner as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct EmptyInMax;
|
||||||
|
|
||||||
|
impl_usize_max_zst!(EmptyInMax);
|
||||||
|
|
||||||
|
pub struct HasDebug;
|
||||||
|
|
||||||
|
impl Debug for HasDebug {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("hello!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_usize_max_zst!(HasDebug);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct PanicsInDrop;
|
||||||
|
|
||||||
|
impl Drop for PanicsInDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
panic!("oh no!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_usize_max_zst!(PanicsInDrop);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue