diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 00000000..faa3d5a3 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,3 @@ +# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +max_width = 80 +tab_spaces = 2 diff --git a/src/main.rs b/src/main.rs index a363b483..9f29639f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,246 +1,249 @@ mod channel { - use super::util; + use super::util; - extern "C" { - // Call a method/destructor; virtual methods use C++ dynamic dispatch. - fn Channel__DTOR(this: &mut Channel) -> (); - fn Channel__a(this: &mut Channel) -> (); - fn Channel__b(this: &Channel) -> i32; + extern "C" { + // Call a method/destructor; virtual methods use C++ dynamic dispatch. + fn Channel__DTOR(this: &mut Channel) -> (); + fn Channel__a(this: &mut Channel) -> (); + fn Channel__b(this: &Channel) -> i32; - // Call a method of a specific class implementation, bypassing dynamic - // dispatch. C++ equivalent: `my_channel.Channel::a()`. - fn Channel__Channel__a(this: &mut Channel) -> (); + // Call a method of a specific class implementation, bypassing dynamic + // dispatch. C++ equivalent: `my_channel.Channel::a()`. + fn Channel__Channel__a(this: &mut Channel) -> (); - // Constructs a special class derived from Channel that forwards all - // virtual method invocations to rust. It is assumed that this subclass - // has the same size and memory layout as the class it's deriving from. - fn Channel__OVERRIDE__CTOR(this: &mut std::mem::MaybeUninit) -> (); + // Constructs a special class derived from Channel that forwards all + // virtual method invocations to rust. It is assumed that this subclass + // has the same size and memory layout as the class it's deriving from. + fn Channel__OVERRIDE__CTOR(this: &mut std::mem::MaybeUninit) + -> (); + } + + #[repr(C)] + pub struct Channel { + _cxx_vtable: *const [usize; 0], + } + + #[allow(dead_code)] + impl Channel { + pub fn a(&mut self) { + unsafe { Channel__a(self) } + } + pub fn b(&self) -> i32 { + unsafe { Channel__b(self) } + } + } + + impl Drop for Channel { + fn drop(&mut self) { + unsafe { Channel__DTOR(self) } + } + } + + pub struct ChannelDefaults; + impl ChannelDefaults { + pub fn a(this: &mut Channel) { + unsafe { Channel__Channel__a(this) } + } + } + + pub trait ChannelOverrides { + fn extender(&self) -> &ChannelExtender; + fn extender_mut(&mut self) -> &mut ChannelExtender; + + fn a(&mut self) { + ChannelDefaults::a(self.extender_mut()) + } + fn b(&self) -> i32; + } + + pub struct ChannelExtender { + cxx_channel: Channel, + extender_offset: usize, + rust_vtable: util::RustVTable<&'static dyn ChannelOverrides>, + } + + #[no_mangle] + unsafe extern "C" fn Channel__OVERRIDE__a__DISPATCH(this: &mut Channel) { + ChannelExtender::dispatch_mut(this).a() + } + #[no_mangle] + unsafe extern "C" fn Channel__OVERRIDE__b__DISPATCH(this: &Channel) -> i32 { + ChannelExtender::dispatch(this).b() + } + + impl ChannelExtender { + fn construct_cxx_channel() -> Channel { + unsafe { + let mut buf = std::mem::MaybeUninit::::uninit(); + Channel__OVERRIDE__CTOR(&mut buf); + buf.assume_init() + } } - #[repr(C)] - pub struct Channel { - _cxx_vtable: *const [usize; 0], + fn get_extender_offset() -> usize + where + T: ChannelOverrides, + { + let buf = std::mem::MaybeUninit::::uninit(); + let embedder_ptr: *const T = buf.as_ptr(); + let self_ptr: *const Self = unsafe { (*embedder_ptr).extender() }; + util::FieldOffset::from_ptrs(embedder_ptr, self_ptr).offset() } - #[allow(dead_code)] - impl Channel { - pub fn a(&mut self) { - unsafe { Channel__a(self) } - } - pub fn b(&self) -> i32 { - unsafe { Channel__b(self) } - } + fn get_rust_vtable() -> util::RustVTable<&'static dyn ChannelOverrides> + where + T: ChannelOverrides, + { + let buf = std::mem::MaybeUninit::::uninit(); + let embedder_ptr = buf.as_ptr(); + let trait_object: *const dyn ChannelOverrides = embedder_ptr; + let (data_ptr, vtable): (*const T, util::RustVTable<_>) = + unsafe { std::mem::transmute(trait_object) }; + assert_eq!(data_ptr, embedder_ptr); + vtable } - pub struct ChannelDefaults; - impl ChannelDefaults { - pub fn a(this: &mut Channel) { - unsafe { Channel__Channel__a(this) } - } + pub fn new() -> Self + where + T: ChannelOverrides, + { + Self { + cxx_channel: Self::construct_cxx_channel(), + extender_offset: Self::get_extender_offset::(), + rust_vtable: Self::get_rust_vtable::(), + } } - pub trait ChannelOverrides { - fn base(&self) -> &Override; - fn base_mut(&mut self) -> &mut Override; - - fn a(&mut self) { - ChannelDefaults::a(self.base_mut()) - } - fn b(&self) -> i32; + fn channel_offset() -> util::FieldOffset { + let buf = std::mem::MaybeUninit::::uninit(); + util::FieldOffset::from_ptrs(buf.as_ptr(), unsafe { + &(*buf.as_ptr()).cxx_channel + }) } - pub struct Override { - cxx_channel: Channel, - base_offset: usize, - rust_vtable: util::RustVTable<&'static dyn ChannelOverrides>, + fn embedder_offset(&self) -> util::FieldOffset { + util::FieldOffset::::from_offset(self.extender_offset) } - #[no_mangle] - unsafe extern "C" fn Channel__OVERRIDE__a__DISPATCH(this: &mut Channel) { - Override::dispatch_mut(this).a() - } - #[no_mangle] - unsafe extern "C" fn Channel__OVERRIDE__b__DISPATCH(this: &Channel) -> i32 { - Override::dispatch(this).b() + unsafe fn dispatch(channel: &Channel) -> &dyn ChannelOverrides { + let this = Self::channel_offset().to_outer(channel); + let embedder = this.embedder_offset().to_outer(this); + std::mem::transmute((embedder, this.rust_vtable)) } - impl Drop for Channel { - fn drop(&mut self) { - unsafe { Channel__DTOR(self) } - } + unsafe fn dispatch_mut(channel: &mut Channel) -> &mut dyn ChannelOverrides { + let this = Self::channel_offset().to_outer_mut(channel); + let vtable = this.rust_vtable; + let embedder = this.embedder_offset().to_outer_mut(this); + std::mem::transmute((embedder, vtable)) } + } - impl Override { - fn construct_cxx_channel() -> Channel { - unsafe { - let mut buf = std::mem::MaybeUninit::::uninit(); - Channel__OVERRIDE__CTOR(&mut buf); - buf.assume_init() - } - } - - fn get_base_offset() -> usize - where - T: ChannelOverrides, - { - let buf = std::mem::MaybeUninit::::uninit(); - let top_ptr: *const T = buf.as_ptr(); - let self_ptr: *const Self = unsafe { (*top_ptr).base() }; - util::FieldOffset::from_ptrs(top_ptr, self_ptr).offset() - } - - fn get_rust_vtable() -> util::RustVTable<&'static dyn ChannelOverrides> - where - T: ChannelOverrides, - { - let buf = std::mem::MaybeUninit::::uninit(); - let embedder_ptr = buf.as_ptr(); - let trait_object: *const dyn ChannelOverrides = embedder_ptr; - let (data_ptr, vtable): (*const T, util::RustVTable<_>) = - unsafe { std::mem::transmute(trait_object) }; - assert_eq!(data_ptr, embedder_ptr); - vtable - } - - pub fn new() -> Self - where - T: ChannelOverrides, - { - Self { - cxx_channel: Self::construct_cxx_channel(), - base_offset: Self::get_base_offset::(), - rust_vtable: Self::get_rust_vtable::(), - } - } - - fn channel_offset() -> util::FieldOffset { - let buf = std::mem::MaybeUninit::::uninit(); - util::FieldOffset::from_ptrs(buf.as_ptr(), unsafe { &(*buf.as_ptr()).cxx_channel }) - } - - fn embedder_offset(&self) -> util::FieldOffset { - util::FieldOffset::::from_offset(self.base_offset) - } - - unsafe fn dispatch(channel: &Channel) -> &dyn ChannelOverrides { - let this = Self::channel_offset().to_outer(channel); - let embedder = this.embedder_offset().to_outer(this); - std::mem::transmute((embedder, this.rust_vtable)) - } - - unsafe fn dispatch_mut(channel: &mut Channel) -> &mut dyn ChannelOverrides { - let this = Self::channel_offset().to_outer_mut(channel); - let vtable = this.rust_vtable; - let embedder = this.embedder_offset().to_outer_mut(this); - std::mem::transmute((embedder, vtable)) - } + impl std::ops::Deref for ChannelExtender { + type Target = Channel; + fn deref(&self) -> &Channel { + &self.cxx_channel } + } - impl std::ops::Deref for Override { - type Target = Channel; - fn deref(&self) -> &Channel { - &self.cxx_channel - } - } - - impl std::ops::DerefMut for Override { - fn deref_mut(&mut self) -> &mut Channel { - &mut self.cxx_channel - } + impl std::ops::DerefMut for ChannelExtender { + fn deref_mut(&mut self) -> &mut Channel { + &mut self.cxx_channel } + } } mod trying { - use super::channel::*; + use super::channel::*; - #[allow(dead_code)] - pub struct Session { - a: i32, - b: String, - c: Override, - } + #[allow(dead_code)] + pub struct Session { + a: i32, + b: String, + c: ChannelExtender, + } - impl ChannelOverrides for Session { - fn base(&self) -> &Override { - &self.c - } - fn base_mut(&mut self) -> &mut Override { - &mut self.c - } - fn a(&mut self) { - println!("Override a!"); - } - fn b(&self) -> i32 { - println!("Override b!"); - 42 - } + impl ChannelOverrides for Session { + fn extender(&self) -> &ChannelExtender { + &self.c } + fn extender_mut(&mut self) -> &mut ChannelExtender { + &mut self.c + } + fn a(&mut self) { + println!("ChannelExtender a!"); + } + fn b(&self) -> i32 { + println!("ChannelExtender b!"); + 42 + } + } - impl Session { - pub fn new() -> Self { - Self { - a: 1, - b: "abc".to_owned(), - c: Override::new::(), - } - } + impl Session { + pub fn new() -> Self { + Self { + a: 1, + b: "abc".to_owned(), + c: ChannelExtender::new::(), + } } + } } mod util { - use std::marker::PhantomData; - use std::mem::size_of; + use std::marker::PhantomData; + use std::mem::size_of; - pub type Opaque = [usize; 0]; + pub type Opaque = [usize; 0]; - #[repr(transparent)] - #[derive(Copy, Clone, Debug)] - pub struct RustVTable(pub *const Opaque, pub PhantomData); + #[repr(transparent)] + #[derive(Copy, Clone, Debug)] + pub struct RustVTable(pub *const Opaque, pub PhantomData); - #[derive(Copy, Clone, Debug)] - #[repr(transparent)] - pub struct FieldOffset(isize, PhantomData<(O, I)>); + #[derive(Copy, Clone, Debug)] + #[repr(transparent)] + pub struct FieldOffset(isize, PhantomData<(O, I)>); - impl FieldOffset { - pub fn from_ptrs(o_ptr: *const O, i_ptr: *const I) -> Self { - let o_addr = o_ptr as usize; - let i_addr = i_ptr as usize; - assert!(i_addr >= o_addr); - assert!((i_addr + size_of::()) <= (o_addr + size_of::())); - let offset = (o_addr - i_addr) as isize; - assert!(offset > 0); - Self(offset, PhantomData) - } - - pub fn from_offset(offset: usize) -> Self { - assert!((offset as isize) > 0); - Self(offset as isize, PhantomData) - } - - pub fn offset(self) -> usize { - self.0 as usize - } - - fn shift(ptr: *const PI, delta: isize) -> *mut PO { - (ptr as isize + delta) as *mut PO - } - pub unsafe fn to_outer<'a>(&self, inner: &'a I) -> &'a O { - Self::shift::(inner, -self.0).as_ref().unwrap() - } - #[allow(dead_code)] - pub unsafe fn to_outer_mut<'a>(&self, inner: &'a mut I) -> &'a mut O { - Self::shift::(inner, -self.0).as_mut().unwrap() - } + impl FieldOffset { + pub fn from_ptrs(o_ptr: *const O, i_ptr: *const I) -> Self { + let o_addr = o_ptr as usize; + let i_addr = i_ptr as usize; + assert!(i_addr >= o_addr); + assert!((i_addr + size_of::()) <= (o_addr + size_of::())); + let offset = (o_addr - i_addr) as isize; + assert!(offset > 0); + Self(offset, PhantomData) } - impl std::ops::Add> for FieldOffset { - type Output = FieldOffset; - fn add(self, that: FieldOffset) -> Self::Output { - FieldOffset::::from_offset(self.offset() + that.offset()) - } + pub fn from_offset(offset: usize) -> Self { + assert!((offset as isize) > 0); + Self(offset as isize, PhantomData) } + + pub fn offset(self) -> usize { + self.0 as usize + } + + fn shift(ptr: *const PI, delta: isize) -> *mut PO { + (ptr as isize + delta) as *mut PO + } + pub unsafe fn to_outer<'a>(&self, inner: &'a I) -> &'a O { + Self::shift::(inner, -self.0).as_ref().unwrap() + } + #[allow(dead_code)] + pub unsafe fn to_outer_mut<'a>(&self, inner: &'a mut I) -> &'a mut O { + Self::shift::(inner, -self.0).as_mut().unwrap() + } + } + + impl std::ops::Add> for FieldOffset { + type Output = FieldOffset; + fn add(self, that: FieldOffset) -> Self::Output { + FieldOffset::::from_offset(self.offset() + that.offset()) + } + } } fn main() { - trying::Session::new(); + trying::Session::new(); }