Skip to content

Commit

Permalink
Implements default constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Oct 19, 2024
1 parent 67f0e8d commit 3b5342d
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 7 deletions.
28 changes: 27 additions & 1 deletion macros/src/cpp.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use self::class::Class;
use crate::symbol::{Segment, Signature, Symbol, Type};
use crate::META;
use proc_macro2::{Literal, Span, TokenStream};
use quote::{format_ident, quote};
Expand Down Expand Up @@ -62,9 +63,12 @@ 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());

impls.extend(quote! {
pub unsafe fn #name(this: T) -> Self {
pub unsafe fn #name(mut this: T) -> Self {
#ffi(this.as_mut_ptr());

Self {
mem: this,
phantom: ::std::marker::PhantomData,
Expand All @@ -77,10 +81,28 @@ fn render_class(item: Class) -> syn::Result<TokenStream> {
let mut externs = TokenStream::new();

for (i, ctor) in item.ctors.iter().enumerate() {
// Build name.
let mut name = vec![Segment::Ident(name.as_str().into())];

name.push(Segment::Ctor);

// Build parameters.
let mut params = Vec::with_capacity(ctor.params.len());

if ctor.params.is_empty() {
params.push(Type::Void);
} else {
todo!("parameterized constructor");
}

// 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());

externs.extend(quote! {
unsafe extern "C-unwind" {
#[link_name = #sym]
fn #name(this: *mut ());
}
});
Expand Down Expand Up @@ -117,6 +139,10 @@ fn render_class(item: Class) -> syn::Result<TokenStream> {

impl ::cppbind::Memory for &mut #mem {
type Class = #class<Self>;

fn as_mut_ptr(&mut self) -> *mut () {
self.0.as_mut_ptr().cast()
}
}

impl Default for #mem {
Expand Down
62 changes: 58 additions & 4 deletions macros/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ mod itanium;

/// C++ symbol.
#[derive(Debug)]
pub struct Symbol {
name: Vec<Segment<'static>>,
pub struct Symbol<'a> {
name: Vec<Segment<'a>>,
sig: Option<Signature>,
}

impl Symbol {
impl Symbol<'static> {
pub fn parse(mangled: impl AsRef<[u8]>) -> Result<Self, SymbolError> {
let mangled = mangled.as_ref();

Expand All @@ -21,17 +22,52 @@ impl Symbol {
Err(SymbolError::UnknownSymbol)
}
}
}

impl<'a> Symbol<'a> {
pub fn new(name: Vec<Segment<'a>>, sig: Option<Signature>) -> Self {
Self { name, sig }
}

pub fn name(&self) -> &[Segment<'static>] {
pub fn name(&self) -> &[Segment<'a>] {
&self.name
}

pub fn to_itanium(&self) -> String {
// Build name.
let mut name = String::from("\u{1}_ZN");

for s in &self.name {
use std::fmt::Write;

match s {
Segment::Ident(v) => write!(name, "{}{}", v.len(), v).unwrap(),
Segment::TemplateArg(_) => todo!(),
Segment::Ctor => name.push_str("C1"),
}
}

name.push('E');

// Build signature.
if let Some(s) = &self.sig {
for p in &s.params {
match p {
Type::Void => name.push('v'),
}
}
}

name
}
}

/// Segment of a C++ name.
#[derive(Debug, PartialEq, Eq)]
pub enum Segment<'a> {
Ident(Cow<'a, str>),
TemplateArg(TemplateArg<'a>),
Ctor,
}

/// Argument of a template instantiation.
Expand All @@ -40,6 +76,24 @@ pub enum TemplateArg<'a> {
Ident(Cow<'a, str>),
}

/// Signature of C++ function.
#[derive(Debug)]
pub struct Signature {
params: Vec<Type>,
}

impl Signature {
pub fn new(params: Vec<Type>) -> Self {
Self { params }
}
}

/// C++ type.
#[derive(Debug)]
pub enum Type {
Void,
}

/// Represents an error when [`Symbol`] fails to parse from a mangled name.
#[derive(Debug, Error)]
pub enum SymbolError {
Expand Down
4 changes: 2 additions & 2 deletions macros/src/symbol/itanium.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::cmp::min;
use std::iter::Peekable;
use std::slice::Iter;

pub fn parse(mangled: &[u8]) -> Result<Symbol, SymbolError> {
pub fn parse(mangled: &[u8]) -> Result<Symbol<'static>, SymbolError> {
let mut name = Vec::new();
let mut iter = mangled.iter().peekable();

Expand All @@ -12,7 +12,7 @@ pub fn parse(mangled: &[u8]) -> Result<Symbol, SymbolError> {
_ => return Err(SymbolError::UnknownSymbol),
}

Ok(Symbol { name })
Ok(Symbol { name, sig: None })
}

fn parse_nested_name(
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ pub struct Heap<T>(*mut T);

impl<T: Memory> Memory for Heap<T> {
type Class = T::Class;

fn as_mut_ptr(&mut self) -> *mut () {
self.0.cast()
}
}

unsafe impl<T: Send> Send for Heap<T> {}
Expand All @@ -13,4 +17,6 @@ unsafe impl<T: Sync> Sync for Heap<T> {}
/// Memory of a C++ class.
pub trait Memory {
type Class;

fn as_mut_ptr(&mut self) -> *mut ();
}

0 comments on commit 3b5342d

Please sign in to comment.