Skip to content

Instantly share code, notes, and snippets.

@DutchGhost
Last active May 3, 2019 18:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DutchGhost/bb8baee034032ca24ea66c6ab3be9e52 to your computer and use it in GitHub Desktop.
Save DutchGhost/bb8baee034032ca24ea66c6ab3be9e52 to your computer and use it in GitHub Desktop.
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
/// Fake stdlib's TraitObject:
/// https://doc.rust-lang.org/std/raw/struct.TraitObject.html
/// That requires nightly, but this works on stable.
#[derive(Copy, Clone)]
#[repr(C)]
struct TraitObject {
_data: *mut (),
_vtable: *mut (),
}
/// We have a Shared T (&T), allowed to call Deref, and be Cloned.
#[derive(Debug)]
enum Shared {}
/// We have a Unique T (&mut T), allowed to call DerefMut.
#[derive(Debug)]
enum Unique {}
#[derive(Debug)]
struct Ptr<
'a,
T: ?Sized + Pointee<Meta = Meta>,
Meta: 'static + Copy = <T as Pointee>::Meta,
A = Shared,
> {
/// The location of `T`
location: usize,
/// Additional Metadata of the Pointee.
meta: Meta,
/// Shared / Unique access
access: PhantomData<A>,
/// We don't own T
_mark: PhantomData<*const T>,
/// Lifetime
lifetime: PhantomData<&'a ()>,
}
/// We have a `Shared`, so we can freely copy.
impl<'a, T: ?Sized + Pointee> Copy for Ptr<'a, T, T::Meta, Shared> {}
/// We have a `Shared`, so we can freely clone.
impl<'a, T: ?Sized + Pointee> Clone for Ptr<'a, T, T::Meta, Shared> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, T: ?Sized + Pointee, A> Ptr<'a, T, T::Meta, A> {
/// Constructs a new `Ptr` from `pointer`.
pub fn new<P>(pointer: P) -> Self
where
Self: From<P>,
{
Self::from(pointer)
}
}
/// &T produces Shared
impl<'a, T: ?Sized + Pointee> From<&'a T> for Ptr<'a, T, T::Meta, Shared> {
fn from(reference: &'a T) -> Self {
Self {
location: unsafe { std::mem::transmute_copy::<&T, usize>(&reference) },
meta: reference.metadata(),
access: PhantomData,
_mark: PhantomData,
lifetime: PhantomData,
}
}
}
/// &mut *can* produce Shared
impl<'a, T: ?Sized + Pointee> From<&'a mut T> for Ptr<'a, T, T::Meta, Shared> {
fn from(reference: &'a mut T) -> Self {
Self::from(&*reference)
}
}
/// &mut produces Unique
impl<'a, T: ?Sized + Pointee> From<&'a mut T> for Ptr<'a, T, T::Meta, Unique> {
fn from(reference: &'a mut T) -> Self {
Self {
location: unsafe { std::mem::transmute_copy::<&mut T, usize>(&reference) },
meta: (&*reference).metadata(),
access: PhantomData,
_mark: PhantomData,
lifetime: PhantomData,
}
}
}
impl<'a, T: Pointee<Meta = ()>, A> Deref for Ptr<'a, T, (), A> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*(self.location as *const T) }
}
}
impl<'a, T: Pointee<Meta = ()>> DerefMut for Ptr<'a, T, (), Unique> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self.location as *mut T) }
}
}
impl<'a, T: ?Sized + Pointee<Meta = TraitObject>, A> Deref for Ptr<'a, T, TraitObject, A> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute_copy(&self.meta) }
}
}
impl<'a, T: ?Sized + Pointee<Meta = TraitObject>> DerefMut for Ptr<'a, T, TraitObject, Unique> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::mem::transmute_copy(&self.meta) }
}
}
impl<'a, T, A> Deref for Ptr<'a, [T], <[T] as Pointee>::Meta, A> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe {
let ptr: *const T = self.location as *const T;
std::slice::from_raw_parts(ptr, self.meta)
}
}
}
impl<'a, T> DerefMut for Ptr<'a, [T], <[T] as Pointee>::Meta, Unique> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
let ptr: *mut T = self.location as *mut T;
std::slice::from_raw_parts_mut(ptr, self.meta)
}
}
}
trait Pointee {
type Meta: 'static + Copy;
fn metadata(&self) -> Self::Meta;
}
impl<T> Pointee for T {
type Meta = ();
fn metadata(&self) -> Self::Meta {}
}
impl<T> Pointee for dyn FnMut() -> T {
type Meta = TraitObject;
fn metadata(&self) -> Self::Meta {
unsafe { std::mem::transmute(self) }
}
}
impl<T> Pointee for dyn Fn() -> T {
type Meta = TraitObject;
fn metadata(&self) -> Self::Meta {
unsafe { std::mem::transmute(self) }
}
}
impl<T> Pointee for [T] {
type Meta = usize;
fn metadata(&self) -> Self::Meta {
self.len()
}
}
fn main() {
let mut closure: Box<dyn Fn() -> i32> = Box::new(|| 0);
let mut ptr: Ptr<_, _, Shared> = Ptr::new(&*closure);
let second_ptr = ptr;
// drop(closure); <-- can't do this!!
println!("{:?}", ptr.deref()());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment