diff --git a/.vscode/settings.json b/.vscode/settings.json index 6c494892..553eb564 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust.clippy_preference": "on" + "C_Cpp.clang_format_style": "Chromium" } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 0f5a55dc..5915f6db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" authors = ["Bert Belder "] edition = "2018" -[dependencies] +[build-dependencies] cc = "1.0.45" + diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..0e45db48 --- /dev/null +++ b/build.rs @@ -0,0 +1,10 @@ +use cc; + +fn main() { + cc::Build::new() + .cpp(true) + .flag("-std:c++17") + .debug(true) + .file("src/lib.cpp") + .compile("v8-bindings"); +} diff --git a/src/lib.cpp b/src/lib.cpp new file mode 100644 index 00000000..0c33298b --- /dev/null +++ b/src/lib.cpp @@ -0,0 +1,64 @@ + +#include +#include +#include +#include +#include + +namespace v8 { +class Channel { + public: + Channel() {} + virtual ~Channel() {} + + virtual void method1(int32_t arg) { + std::cout << "default v8::Channel::method1(" << arg << ") called" + << std::endl; + } + + virtual int32_t method2() const = 0; +}; +} // namespace v8 + +extern "C" { +void v8__Channel__EXTENDER__method1(v8::Channel& self, int32_t arg); +int32_t v8__Channel__EXTENDER__method2(const v8::Channel& self); +} + +namespace extender { +template +using uninit_t = typename std::aligned_storage::type; + +namespace v8 { +struct Channel : public ::v8::Channel { + using ::v8::Channel::Channel; + + void method1(int32_t arg) override { + v8__Channel__EXTENDER__method1(*this, arg); + } + + int32_t method2() const override { + return v8__Channel__EXTENDER__method2(*this); + } +}; +} // namespace v8 +} // namespace extender + +extern "C" { +void v8__Channel__DTOR(v8::Channel& self) { + self.~Channel(); +} +void v8__Channel__method1(v8::Channel& self, int32_t arg) { + self.method1(arg); +} +void v8__Channel__Channel__method1(v8::Channel& self, int32_t arg) { + self.::v8::Channel::method1(arg); +} +int32_t v8__Channel__method2(const v8::Channel& self) { + return self.method2(); +} +void v8__Channel__EXTENDER__CTOR( + extender::uninit_t& buf) { + new (std::launder(&buf)) extender::v8::Channel(); +} +} // extern "C" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 03d80a46..3148d743 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,38 +3,56 @@ mod channel { extern "C" { // Call a method/destructor; virtual methods use C++ dynamic dispatch. - fn Channel__DTOR(this: &mut Channel) -> (); - fn Channel__method1(this: &mut Channel) -> (); - fn Channel__method2(this: &Channel) -> i32; + fn v8__Channel__DTOR(this: &mut Channel) -> (); + fn v8__Channel__method1(this: &mut Channel, arg: i32) -> (); + fn v8__Channel__method2(this: &Channel) -> i32; // Call a method of a specific class implementation, bypassing dynamic // dispatch. C++ equivalent: `my_channel.Channel::a()`. - fn Channel__Channel__method1(this: &mut Channel) -> (); + fn v8__Channel__Channel__method1(this: &mut Channel, arg: i32) -> (); // 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__EXTENDER__CTOR(this: &mut std::mem::MaybeUninit) - -> (); + fn v8__Channel__EXTENDER__CTOR( + buf: &mut std::mem::MaybeUninit, + ) -> (); } + #[allow(non_snake_case)] + #[no_mangle] + pub unsafe extern "C" fn v8__Channel__EXTENDER__method1( + this: &mut Channel, + arg: i32, + ) { + ChannelExtender::dispatch_mut(this).method1(arg) + } + + #[allow(non_snake_case)] + #[no_mangle] + pub unsafe extern "C" fn v8__Channel__EXTENDER__method2( + this: &Channel, + ) -> i32 { + ChannelExtender::dispatch(this).method2() + } + #[repr(C)] pub struct Channel { _cxx_vtable: *const util::Opaque, } impl Channel { - pub fn method1(&mut self) { - unsafe { Channel__method1(self) } + pub fn method1(&mut self, arg: i32) { + unsafe { v8__Channel__method1(self, arg) } } pub fn method2(&self) -> i32 { - unsafe { Channel__method2(self) } + unsafe { v8__Channel__method2(self) } } } impl Drop for Channel { fn drop(&mut self) { - unsafe { Channel__DTOR(self) } + unsafe { v8__Channel__DTOR(self) } } } @@ -52,15 +70,6 @@ mod channel { } } - //impl AsChannel for ChannelExtender { - // fn as_channel(&self) -> &Channel { - // &self.cxx_channel - // } - // fn as_channel_mut(&mut self) -> &mut Channel { - // &mut self.cxx_channel - // } - //} - impl AsChannel for T where T: ChannelOverrides, @@ -75,8 +84,8 @@ mod channel { pub struct ChannelDefaults; impl ChannelDefaults { - pub fn method1(channel: &mut Channel) { - unsafe { Channel__Channel__method1(channel) } + pub fn method1(channel: &mut Channel, arg: i32) { + unsafe { v8__Channel__Channel__method1(channel, arg) } } } @@ -84,8 +93,8 @@ mod channel { fn extender(&self) -> &ChannelExtender; fn extender_mut(&mut self) -> &mut ChannelExtender; - fn method1(&mut self) { - ChannelDefaults::method1(self.as_channel_mut()) + fn method1(&mut self, arg: i32) { + ChannelDefaults::method1(self.as_channel_mut(), arg) } fn method2(&self) -> i32; } @@ -97,26 +106,10 @@ mod channel { } impl ChannelExtender { - #[allow(non_snake_case)] - #[no_mangle] - unsafe extern "C" fn Channel__EXTENDER__method1__DISPATCH( - this: &mut Channel, - ) { - ChannelExtender::dispatch_mut(this).method1() - } - - #[allow(non_snake_case)] - #[no_mangle] - unsafe extern "C" fn Channel__EXTENDER__method2__DISPATCH( - this: &Channel, - ) -> i32 { - ChannelExtender::dispatch(this).method2() - } - fn construct_cxx_channel() -> Channel { unsafe { let mut buf = std::mem::MaybeUninit::::uninit(); - Channel__EXTENDER__CTOR(&mut buf); + v8__Channel__EXTENDER__CTOR(&mut buf); buf.assume_init() } } @@ -162,13 +155,13 @@ mod channel { }) } - unsafe fn dispatch(channel: &Channel) -> &dyn ChannelOverrides { + pub unsafe fn dispatch(channel: &Channel) -> &dyn ChannelOverrides { let this = Self::get_channel_offset().to_embedder::(channel); let embedder = this.extender_offset.to_embedder::(this); std::mem::transmute((embedder, this.rust_vtable)) } - unsafe fn dispatch_mut(channel: &mut Channel) -> &mut dyn ChannelOverrides { + pub unsafe fn dispatch_mut(channel: &mut Channel) -> &mut dyn ChannelOverrides { let this = Self::get_channel_offset().to_embedder_mut::(channel); let vtable = this.rust_vtable; let embedder = this.extender_offset.to_embedder_mut::(this); @@ -242,12 +235,14 @@ mod example { fn extender_mut(&mut self) -> &mut ChannelExtender { &mut self.channel_extender } - fn method1(&mut self) { - println!("overriden a() called"); - self.a += self.b; + fn method1(&mut self, arg: i32) { + println!("overriden method1({}) called", arg); + self.a += self.b * arg; + let arg = self.a; + ChannelDefaults::method1(self.as_channel_mut(), arg); } fn method2(&self) -> i32 { - println!("overriden b() called"); + println!("overriden method2() called"); self.a * self.b } } @@ -268,6 +263,6 @@ fn main() { use example::*; let mut ex = Example::new(); let chan = ex.as_channel_mut(); - chan.method1(); + chan.method1(3); println!("{}", chan.method2()); }