Skip to content

Commit

Permalink
Implements non-virtual destructor
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Oct 19, 2024
1 parent 3b5342d commit 86509ad
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 4 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ This is a Rust crate to generate binding to C++ functions and methods with **zer

The goal of this crate is to allows efficient integration between Rust and C++, which mean most of the generated code will be unsafe. You need to know how the C++ code you are going to use is working otherwise you will be hit by undefined behaviors.

Only x86-64 Linux is supported at the moment. A PR to adds supports for other platforms is welcome!

## Requirements

- C++11 and its toolchain.

## Limitations

- Rust cannot access an instance variable directly. You need to create a getter/setter for each variable you want to access.
- Inline method is not supported. That mean you cannot define a method you want to use inside a class declaration.
- Inline method is not supported (including constructors and destructor that auto generated by C++ compiler). You need to create a method definition outside a class declaration.

## Usage

Expand Down
5 changes: 5 additions & 0 deletions example/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class class1 {
public:
class1();
class1(const char *v1);
~class1();
protected:
std::string v1;
};
Expand All @@ -19,3 +20,7 @@ class1::class1()
class1::class1(const char *v1) : v1(v1)
{
}

class1::~class1()
{
}
1 change: 1 addition & 0 deletions example/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use cppbind::cpp;

fn main() {
// Construct class1 directly on Rust stack.
let mut v1 = class1_memory::new();
let v1 = unsafe { class1::new1(&mut v1) };
}
Expand Down
27 changes: 24 additions & 3 deletions macros/src/cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn render_class(item: Class) -> syn::Result<TokenStream> {

for (i, ctor) in item.ctors.iter().enumerate() {
let name = format_ident!("new{}", i + 1, span = ctor.span);
let ffi = format_ident!("{}_new{}", class, i + 1, span = Span::call_site());
let ffi = format_ident!("{}_ctor{}", class, i + 1, span = Span::call_site());

impls.extend(quote! {
pub unsafe fn #name(mut this: T) -> Self {
Expand Down Expand Up @@ -98,7 +98,7 @@ fn render_class(item: Class) -> syn::Result<TokenStream> {
// Render.
let sym = Symbol::new(name, Some(Signature::new(params)));
let sym = sym.to_itanium();
let name = format_ident!("{}_new{}", class, i + 1, span = Span::call_site());
let name = format_ident!("{}_ctor{}", class, i + 1, span = Span::call_site());

externs.extend(quote! {
unsafe extern "C-unwind" {
Expand All @@ -108,6 +108,21 @@ fn render_class(item: Class) -> syn::Result<TokenStream> {
});
}

// Generate destructor FFI.
let dtor = format_ident!("{}_dtor", class, span = Span::call_site());
let sym = Symbol::new(
vec![Segment::Ident(name.as_str().into()), Segment::Dtor],
Some(Signature::new(vec![Type::Void])),
)
.to_itanium();

externs.extend(quote! {
unsafe extern "C-unwind" {
#[link_name = #sym]
fn #dtor(this: *mut (), __in_chrg: ::std::ffi::c_int);
}
});

// Compose.
let align = Literal::usize_unsuffixed(align);
let mem = if name.chars().next().unwrap().is_uppercase() {
Expand All @@ -118,7 +133,7 @@ fn render_class(item: Class) -> syn::Result<TokenStream> {

Ok(quote! {
#[allow(non_camel_case_types)]
pub struct #class<T> {
pub struct #class<T: ::cppbind::Memory<Class = Self>> {
mem: T,
phantom: ::std::marker::PhantomData<::std::rc::Rc<()>>,
}
Expand All @@ -127,6 +142,12 @@ fn render_class(item: Class) -> syn::Result<TokenStream> {
#impls
}

impl<T: ::cppbind::Memory<Class = Self>> Drop for #class<T> {
fn drop(&mut self) {
unsafe { #dtor(self.mem.as_mut_ptr(), 0) };
}
}

#[allow(non_camel_case_types)]
#[repr(C, align(#align))]
pub struct #mem([::std::mem::MaybeUninit<u8>; #size]);
Expand Down
2 changes: 2 additions & 0 deletions macros/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ impl<'a> Symbol<'a> {
Segment::Ident(v) => write!(name, "{}{}", v.len(), v).unwrap(),
Segment::TemplateArg(_) => todo!(),
Segment::Ctor => name.push_str("C1"),
Segment::Dtor => name.push_str("D1"),
}
}

Expand All @@ -68,6 +69,7 @@ pub enum Segment<'a> {
Ident(Cow<'a, str>),
TemplateArg(TemplateArg<'a>),
Ctor,
Dtor,
}

/// Argument of a template instantiation.
Expand Down

0 comments on commit 86509ad

Please sign in to comment.