-
-
Save Kimundi/bdc59228b89345ee25af to your computer and use it in GitHub Desktop.
Shared via Rust Playground
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
#![feature(unsize)] | |
#![feature(raw)] | |
#![feature(const_fn)] | |
use std::marker::{Unsize, PhantomData}; | |
use std::fmt::Display; | |
use std::fmt::Debug; | |
use std::raw::TraitObject; | |
use std::cell::Cell; | |
use std::mem; | |
use std::ops::Deref; | |
use std::rc::Rc; | |
use std::sync::Arc; | |
trait Dst: Unsize<Self> {} | |
impl<T: ?Sized + Unsize<T>> Dst for T {} | |
type Meta = *const (); | |
#[repr(C)] | |
struct MetaField<D: ?Sized + Dst, T: ?Sized = D> { | |
meta: Cell<Meta>, | |
_marker: PhantomData<Cell<*const D>>, | |
data: T, | |
} | |
impl<D: ?Sized + Dst, T> MetaField<D, T> { | |
const fn new(t: T) -> MetaField<D, T> { | |
MetaField { | |
meta: Cell::new(0 as *const _), | |
data: t, | |
_marker: PhantomData, | |
} | |
} | |
} | |
impl<D: ?Sized + Dst, T: ?Sized> Deref for MetaField<D, T> { | |
type Target = T; | |
fn deref(&self) -> &T { | |
&self.data | |
} | |
} | |
unsafe trait MetaPrefix<D: ?Sized + Dst> {} | |
unsafe impl<D: ?Sized + Dst, T: ?Sized> MetaPrefix<D> for MetaField<D, T> {} | |
unsafe trait Unaliased {} | |
unsafe impl<T: ?Sized> Unaliased for Box<T> {} | |
unsafe impl<'a, T: ?Sized> Unaliased for &'a mut T {} | |
unsafe trait Ptr: Sized + Deref { | |
type Erased: Ptr; | |
unsafe fn erase(self) -> (Self::Erased, Meta) | |
{ | |
let this = super_transmute::<Self, TraitObject>(self); | |
let meta = super_transmute(this.vtable); | |
(super_transmute(this.data), meta) | |
} | |
unsafe fn unerase<T>(self, meta: Meta) -> T { | |
let this = TraitObject { | |
data: super_transmute(self), | |
vtable: super_transmute(meta), | |
}; | |
super_transmute(this) | |
} | |
unsafe fn as_unerased<T: ?Sized + Dst>(&self, meta: Meta) -> &T { | |
let this = TraitObject { | |
data: super_transmute(&**self), | |
vtable: super_transmute(meta), | |
}; | |
super_transmute(this) | |
} | |
} | |
unsafe impl<'a, T: ?Sized> Ptr for &'a T { type Erased = &'a (); } | |
unsafe impl<'a, T: ?Sized> Ptr for &'a mut T { type Erased = &'a mut (); } | |
unsafe impl<T: ?Sized> Ptr for Box<T> { type Erased = Box<()>; } | |
unsafe impl<T: ?Sized> Ptr for Rc<T> { type Erased = Rc<()>; } | |
unsafe impl<T: ?Sized> Ptr for Arc<T> { type Erased = Arc<()>; } | |
struct Thin<P: Ptr> | |
where P::Erased: Deref<Target = ()> | |
{ | |
data: P::Erased, | |
_marker: PhantomData<P>, | |
} | |
impl<P: Ptr> Thin<P> | |
where P::Erased: Deref<Target = ()> | |
{ | |
fn new(dst: P) -> Thin<P> | |
{ | |
unsafe { | |
let meta_ref: &Cell<Meta> = super_transmute(&*dst); | |
let (data, meta) = dst.erase(); | |
meta_ref.set(meta); | |
Thin { | |
data: data, | |
_marker: PhantomData, | |
} | |
} | |
} | |
} | |
impl<P: Ptr + Deref> Deref for Thin<P> | |
where P::Erased: Deref<Target = ()>, | |
P::Target: Dst, | |
{ | |
type Target = P::Target; | |
fn deref(&self) -> &Self::Target { | |
unsafe { | |
let meta = super_transmute::<&(), &Cell<Meta>>(&*self.data); | |
let meta = meta.get(); | |
self.data.as_unerased(meta) | |
} | |
} | |
} | |
use std::ptr; | |
unsafe fn super_transmute<T, U>(t: T) -> U { | |
let p: *const T = &t; | |
let p: *const U = p as *const _; | |
let u: U = ptr::read(&*p); | |
mem::forget(t); | |
u | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
struct DstWrap<T: ?Sized> { | |
_stuff: [u64; 3], | |
_t: T, | |
} | |
static mut X: MetaField<Display, i32> = MetaField::new(5); | |
static mut Y: MetaField<DstWrap<Display>, DstWrap<i32>> = MetaField::new(DstWrap { _stuff: [0,0,0], _t: 10 }); | |
fn main() { | |
// 'static default prevents creating these borrowed DST on the stack. | |
let x: &MetaField<_> = unsafe { &X }; | |
let y: &MetaField<_> = unsafe { &Y }; | |
println!("size_of x: {} display: {}", mem::size_of_val(&x), &**x); | |
println!("size_of y: {}", mem::size_of_val(&y)); | |
let x_thin: Thin<&MetaField<Display>> = Thin::new(x); | |
let y_thin: Thin<&MetaField<DstWrap<Display>>> = Thin::new(y); | |
println!("size_of x_thin: {} display {}", mem::size_of_val(&x_thin), &**x_thin); | |
println!("size_of y_thin: {}", mem::size_of_val(&y_thin)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment