This commit is contained in:
Bert Belder 2019-10-15 18:31:05 -07:00
parent f6bc61ec11
commit f9d0a6ba77
No known key found for this signature in database
GPG Key ID: 7A77887B2E2ED461
5 changed files with 119 additions and 49 deletions

View File

@ -1,3 +1,3 @@
{
"rust.clippy_preference": "on"
"C_Cpp.clang_format_style": "Chromium"
}

View File

@ -4,5 +4,6 @@ version = "0.1.0"
authors = ["Bert Belder <bertbelder@gmail.com>"]
edition = "2018"
[dependencies]
[build-dependencies]
cc = "1.0.45"

10
build.rs Normal file
View File

@ -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");
}

64
src/lib.cpp Normal file
View File

@ -0,0 +1,64 @@
#include <cstdint>
#include <iostream>
#include <new>
#include <type_traits>
#include <utility>
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 <class T>
using uninit_t = typename std::aligned_storage<sizeof(T), alignof(T)>::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<extender::v8::Channel>& buf) {
new (std::launder(&buf)) extender::v8::Channel();
}
} // extern "C"

View File

@ -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<Channel>)
-> ();
fn v8__Channel__EXTENDER__CTOR(
buf: &mut std::mem::MaybeUninit<Channel>,
) -> ();
}
#[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<T> 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::<Channel>::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::<Self>(channel);
let embedder = this.extender_offset.to_embedder::<util::Opaque>(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::<Self>(channel);
let vtable = this.rust_vtable;
let embedder = this.extender_offset.to_embedder_mut::<util::Opaque>(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());
}