Trait erasable::ErasablePtr

source ·
pub unsafe trait ErasablePtr {
    fn erase(this: Self) -> ErasedPtr;
    unsafe fn unerase(this: ErasedPtr) -> Self;
Expand description

A (smart) pointer type that can be type-erased (making a thin pointer).

When implementing this trait, you should implement it for all Erasable pointee types. Implementing this trait allows use of the pointer in erased contexts, such as Thin.


A pointer type which is erasable must not include shared mutability before indirection. Equivalently, the erased pointer produced by calling erase on some P must be the same both before and after performing any set of operations on &P. &mut P methods (notably DerefMut) are still allowed to mutate the pointer value, if necessary.

Additionally, the address of the deref target must be independent of the address of the pointer. For example, Box implements ErasablePtr because it’s a pointer to a managed heap allocation. Lazy, however, Derefs into its own location, and as such, can not implement ErasablePtr.

This is similar to (but distinct from!) the guarantees required by Pin or StableDeref.

Pin requires no access to &mut P/&mut P::target, but these remain safe even when using Thin through Thin::with_mut and DerefMut for Thin. StableDeref requires the deref target to not change between invocations, but that is completely fine behavior for ErasablePtr types.


use erasable::*;

struct MyBox<T: ?Sized>(Box<T>);

unsafe impl<T: ?Sized> ErasablePtr for MyBox<T>
    T: Erasable
    fn erase(this: Self) -> ErasedPtr {

    unsafe fn unerase(this: ErasedPtr) -> Self {

let array = [0; 10];
let boxed = MyBox(Box::new(array));
let thin_box: Thin<MyBox<_>> = boxed.into();


This implementation of ErasablePtr is unsound because it features shared mutability before indirection:

struct Pls {
    inner: Cell<Box<u8>>,

unsafe impl ErasablePtr for Pls {
    fn erase(this: Self) -> ErasedPtr { ErasablePtr::erase(this.inner.into_inner()) }
    unsafe fn unerase(this: ErasedPtr) -> Self {
        Pls { inner: Cell::new(ErasablePtr::unerase(this)) }

impl Pls {
    fn mutate(&self, to: Box<u8>) { self.inner.set(to); }

let thin = Thin::from(Pls { inner: Cell::new(Box::new(0)) });
Thin::with(&thin, |pls| pls.mutate(Box::new(1))); // drops box(0), leaks box(1)
drop(thin); // `thin` is still Pls(Box(0)); use-after-free

This implementation of ErasablePtr is unsound because it dereferences to the interior of the type:

struct Why {
    inner: Box<u8>,

unsafe impl ErasablePtr for Why {
    fn erase(this: Self) -> ErasedPtr { ErasablePtr::erase(this.inner) }
    unsafe fn unerase(this: ErasedPtr) -> Self { Why { inner: ErasablePtr::unerase(this) } }

impl Deref for Why {
    type Target = Box<u8>;
    fn deref(&self) -> &Box<u8> { &self.inner }

let thin = Thin::from(Why { inner: Box::new(0) });
let _: &Box<u8> = thin.deref(); // use-after-free; cannot deref to value that does not exist

Required Methods§

Turn this erasable pointer into an erased pointer.

To retrieve the original pointer, use unerase.

Unerase this erased pointer.


The erased pointer must have been created by erase.

Implementations on Foreign Types§