Last active
May 3, 2019 18:05
-
-
Save DutchGhost/bb8baee034032ca24ea66c6ab3be9e52 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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