mirror of
https://github.com/Noratrieb/stuff.git
synced 2026-01-15 17:05:08 +01:00
make backend generic
This commit is contained in:
parent
3e11ae0f17
commit
d144819eb0
3 changed files with 68 additions and 45 deletions
3
rust-toolchain.toml
Normal file
3
rust-toolchain.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "nightly-2022-04-03"
|
||||||
|
components = ["miri"]
|
||||||
90
src/lib.rs
90
src/lib.rs
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! A crate for stuffing things into a pointer.
|
//! A crate for stuffing things into a pointer.
|
||||||
|
|
||||||
|
mod backend;
|
||||||
pub mod strategies;
|
pub mod strategies;
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
@ -11,20 +12,25 @@ use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
|
||||||
|
use crate::backend::Backend;
|
||||||
use sptr::Strict;
|
use sptr::Strict;
|
||||||
|
|
||||||
/// A union of a pointer and some extra data.
|
/// A union of a pointer and some extra data.
|
||||||
pub struct StuffedPtr<T, S>(*mut T, PhantomData<S>)
|
pub struct StuffedPtr<T, S, I = usize>(I::Stored, PhantomData<S>)
|
||||||
where
|
where
|
||||||
S: StuffingStrategy;
|
S: StuffingStrategy<I>,
|
||||||
|
I: Backend<T>;
|
||||||
|
|
||||||
impl<T, S> StuffedPtr<T, S>
|
impl<T, S, I> StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
|
I: Backend<T>,
|
||||||
{
|
{
|
||||||
/// Create a new `StuffedPtr` from a pointer
|
/// Create a new `StuffedPtr` from a pointer
|
||||||
pub fn new_ptr(ptr: *mut T) -> Self {
|
pub fn new_ptr(ptr: *mut T) -> Self {
|
||||||
Self(map_ptr(ptr, S::stuff_ptr), PhantomData)
|
let addr = Strict::addr(ptr);
|
||||||
|
let stuffed = S::stuff_ptr(addr);
|
||||||
|
Self(I::set_ptr(ptr, stuffed), PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `StuffPtr` from extra
|
/// Create a new `StuffPtr` from extra
|
||||||
|
|
@ -32,8 +38,8 @@ where
|
||||||
// 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 = std::ptr::null_mut();
|
let ptr = std::ptr::null_mut();
|
||||||
let ptr = Strict::with_addr(ptr, S::stuff_extra(extra));
|
let extra = S::stuff_extra(extra);
|
||||||
Self(ptr, PhantomData)
|
Self(I::set_ptr(ptr, extra), PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the pointer data, or `None` if it contains extra
|
/// Get the pointer data, or `None` if it contains extra
|
||||||
|
|
@ -48,7 +54,9 @@ where
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Must contain pointer data and not extra
|
/// Must contain pointer data and not extra
|
||||||
pub unsafe fn get_ptr_unchecked(&self) -> *mut T {
|
pub unsafe fn get_ptr_unchecked(&self) -> *mut T {
|
||||||
map_ptr(self.0, S::extract_ptr)
|
let (provenance, addr) = I::get_ptr(self.0);
|
||||||
|
let addr = S::extract_ptr(addr);
|
||||||
|
Strict::with_addr(provenance, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get owned extra data from this, or `None` if it contains pointer data
|
/// Get owned extra data from this, or `None` if it contains pointer data
|
||||||
|
|
@ -88,8 +96,8 @@ where
|
||||||
unsafe { S::extract_extra(data) }
|
unsafe { S::extract_extra(data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addr(&self) -> usize {
|
fn addr(&self) -> I {
|
||||||
Strict::addr(self.0)
|
I::get_int(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_extra(&self) -> bool {
|
fn is_extra(&self) -> bool {
|
||||||
|
|
@ -97,10 +105,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> StuffedPtr<T, S>
|
impl<T, S, I> StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
S::Extra: Copy,
|
S::Extra: Copy,
|
||||||
|
I: Backend<T>,
|
||||||
{
|
{
|
||||||
/// Get extra data from this, or `None` if it's pointer data
|
/// Get extra data from this, or `None` if it's pointer data
|
||||||
pub fn copy_extra(&self) -> Option<S::Extra> {
|
pub fn copy_extra(&self) -> Option<S::Extra> {
|
||||||
|
|
@ -117,10 +126,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Debug for StuffedPtr<T, S>
|
impl<T, S, I> Debug for StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
S::Extra: Debug,
|
S::Extra: Debug,
|
||||||
|
I: Backend<T>,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
|
|
@ -134,7 +144,8 @@ where
|
||||||
mem::forget(extra);
|
mem::forget(extra);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let ptr = map_ptr(self.0, S::extract_ptr);
|
// SAFETY: Checked above
|
||||||
|
let ptr = unsafe { self.get_ptr_unchecked() };
|
||||||
f.debug_struct("StuffedPtr::Ptr")
|
f.debug_struct("StuffedPtr::Ptr")
|
||||||
.field("ptr", &ptr)
|
.field("ptr", &ptr)
|
||||||
.finish()
|
.finish()
|
||||||
|
|
@ -142,9 +153,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Drop for StuffedPtr<T, S>
|
impl<T, S, I> Drop for StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
|
I: Backend<T>,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.is_extra() {
|
if self.is_extra() {
|
||||||
|
|
@ -157,10 +169,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Clone for StuffedPtr<T, S>
|
impl<T, S, I> Clone for StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
S::Extra: Clone,
|
S::Extra: Clone,
|
||||||
|
I: 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 `extra` ever existed after taking the reference and cloning it
|
||||||
|
|
@ -175,10 +188,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> PartialEq for StuffedPtr<T, S>
|
impl<T, S, I> PartialEq for StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
S::Extra: PartialEq,
|
S::Extra: PartialEq,
|
||||||
|
I: Backend<T>,
|
||||||
{
|
{
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// SAFETY: We forget them after
|
// SAFETY: We forget them after
|
||||||
|
|
@ -203,16 +217,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Eq for StuffedPtr<T, S>
|
impl<T, S, I> Eq for StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
S::Extra: PartialEq + Eq,
|
S::Extra: PartialEq + Eq,
|
||||||
|
I: Backend<T>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> From<Box<T>> for StuffedPtr<T, S>
|
impl<T, S, I> From<Box<T>> for StuffedPtr<T, S, I>
|
||||||
where
|
where
|
||||||
S: StuffingStrategy,
|
S: StuffingStrategy<I>,
|
||||||
|
I: Backend<T>,
|
||||||
{
|
{
|
||||||
fn from(boxed: Box<T>) -> Self {
|
fn from(boxed: Box<T>) -> Self {
|
||||||
Self::new_ptr(Box::into_raw(boxed))
|
Self::new_ptr(Box::into_raw(boxed))
|
||||||
|
|
@ -230,22 +246,22 @@ where
|
||||||
///
|
///
|
||||||
/// 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 {
|
pub unsafe trait StuffingStrategy<I> {
|
||||||
/// The type of the extra.
|
/// The type of the extra.
|
||||||
type Extra;
|
type Extra;
|
||||||
|
|
||||||
/// Checks whether the `StufferPtr` data value contains an extra value. The result of this
|
/// Checks whether the `StufferPtr` data value contains an extra value. The result of this
|
||||||
/// function can be trusted.
|
/// function can be trusted.
|
||||||
fn is_extra(data: usize) -> bool;
|
fn is_extra(data: I) -> bool;
|
||||||
|
|
||||||
/// Stuff extra data into a usize that is then put into the pointer. This operation
|
/// Stuff extra 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) -> usize;
|
fn stuff_extra(inner: Self::Extra) -> I;
|
||||||
|
|
||||||
/// Extract extra data from the data.
|
/// Extract extra data from the data.
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// `data` must contain data created by [`StuffingStrategy::stuff_extra`].
|
/// `data` must contain data created by [`StuffingStrategy::stuff_extra`].
|
||||||
unsafe fn extract_extra(data: usize) -> Self::Extra;
|
unsafe fn extract_extra(data: I) -> Self::Extra;
|
||||||
|
|
||||||
/// Stuff a pointer address into the pointer sized integer.
|
/// Stuff a pointer address into the pointer sized integer.
|
||||||
///
|
///
|
||||||
|
|
@ -253,24 +269,12 @@ pub unsafe trait StuffingStrategy {
|
||||||
/// cursed things with it.
|
/// cursed things with it.
|
||||||
///
|
///
|
||||||
/// The default implementation just returns the address directly.
|
/// The default implementation just returns the address directly.
|
||||||
fn stuff_ptr(inner: usize) -> usize {
|
fn stuff_ptr(addr: usize) -> I;
|
||||||
inner
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract the pointer address from the data.
|
/// Extract the pointer address from the data.
|
||||||
///
|
///
|
||||||
/// This function expects `inner` to come directly from [`StuffingStrategy::stuff_ptr`].
|
/// This function expects `inner` to come directly from [`StuffingStrategy::stuff_ptr`].
|
||||||
///
|
fn extract_ptr(inner: I) -> usize;
|
||||||
/// The default implementation just returns the value directly.
|
|
||||||
fn extract_ptr(inner: usize) -> usize {
|
|
||||||
inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map_ptr<T>(ptr: *mut T, map: impl FnOnce(usize) -> usize) -> *mut T {
|
|
||||||
let int = Strict::addr(ptr);
|
|
||||||
let result = map(int);
|
|
||||||
Strict::with_addr(ptr, result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use crate::StuffingStrategy;
|
use crate::StuffingStrategy;
|
||||||
|
|
||||||
unsafe impl StuffingStrategy for () {
|
unsafe impl StuffingStrategy<usize> for () {
|
||||||
type Extra = ();
|
type Extra = ();
|
||||||
|
|
||||||
fn is_extra(_data: usize) -> bool {
|
fn is_extra(_data: usize) -> bool {
|
||||||
|
|
@ -16,6 +16,14 @@ unsafe impl StuffingStrategy for () {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn extract_extra(_data: usize) -> Self::Extra {}
|
unsafe fn extract_extra(_data: usize) -> Self::Extra {}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> usize {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: usize) -> usize {
|
||||||
|
inner
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -26,7 +34,7 @@ pub(crate) mod test_strategies {
|
||||||
macro_rules! impl_usize_max_zst {
|
macro_rules! impl_usize_max_zst {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
// this one lives in usize::MAX
|
// this one lives in usize::MAX
|
||||||
unsafe impl StuffingStrategy for $ty {
|
unsafe impl StuffingStrategy<usize> for $ty {
|
||||||
type Extra = Self;
|
type Extra = Self;
|
||||||
|
|
||||||
fn is_extra(data: usize) -> bool {
|
fn is_extra(data: usize) -> bool {
|
||||||
|
|
@ -42,6 +50,14 @@ pub(crate) mod test_strategies {
|
||||||
unsafe fn extract_extra(_data: usize) -> Self::Extra {
|
unsafe fn extract_extra(_data: usize) -> Self::Extra {
|
||||||
$ty
|
$ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn stuff_ptr(addr: usize) -> usize {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_ptr(inner: usize) -> usize {
|
||||||
|
inner
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue