use proc_macro_crate::{FoundCrate, crate_name};
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::token::Brace;
use syn::{
AngleBracketedGenericArguments, AttrStyle, CapturedParam, Error, GenericArgument, GenericParam,
Lifetime, LifetimeParam, MacroDelimiter, Meta, Path, PathArguments, ReturnType, Signature,
Token, TypeParamBound, parse2,
};
use syn::{
Attribute, Field, FnArg, Ident, ImplItemFn, Pat, Type, Visibility, braced, parse_macro_input,
parse_quote,
};
mod kw {
syn::custom_keyword!(class);
}
#[derive(Debug, Clone)]
struct OverrideItem {
_override_token: Token![override],
override_class: Type,
_brace_token: Brace,
items: Vec<ImplItemFn>,
}
fn correct_priv_vis(vis: Visibility) -> Visibility {
match vis {
Visibility::Public(p) => Visibility::Public(p),
Visibility::Restricted(mut restricted) => {
if restricted.path.segments.get(0) != Some(&parse_quote!(crate)) {
restricted.path.segments.insert(0, parse_quote!(super));
}
Visibility::Restricted(restricted)
}
Visibility::Inherited => {
parse_quote!(pub(super))
}
}
}
impl Parse for OverrideItem {
fn parse(input: ParseStream) -> syn::Result<Self> {
let content;
let override_token = input.parse()?;
let override_class = input.parse()?;
let brace_token = braced!(content in input);
let mut items = Vec::new();
while !content.is_empty() {
let mut item: ImplItemFn = content.parse()?;
item.vis = correct_priv_vis(item.vis);
items.push(item);
}
Ok(OverrideItem {
_override_token: override_token,
override_class,
_brace_token: brace_token,
items,
})
}
}
#[derive(Debug, Clone)]
enum ClassItem {
Field {
field: Field,
_semi_token: Token![;],
},
ImplItemFn(ImplItemFn),
OverrideItem(OverrideItem),
}
impl Parse for ClassItem {
fn parse(input: ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![override]) {
return Ok(ClassItem::OverrideItem(OverrideItem::parse(input)?));
}
let begin = input.fork();
let _attrs = input.call(Attribute::parse_outer)?;
let _vis: Visibility = begin.parse()?;
let lookahead = begin.lookahead1();
if lookahead.peek(Token![fn])
|| lookahead.peek(Token![unsafe])
|| lookahead.peek(Token![async])
{
return Ok(ClassItem::ImplItemFn(ImplItemFn::parse(input)?));
}
let mut field = Field::parse_named(input)?;
field.vis = correct_priv_vis(field.vis);
let semi_token = input.parse()?;
Ok(ClassItem::Field {
field,
_semi_token: semi_token,
})
}
}
#[derive(Debug, Clone)]
struct SuperclassInput {
_colon_token: Token![:],
ty: Type,
}
impl Parse for SuperclassInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(SuperclassInput {
_colon_token: input.parse()?,
ty: input.parse()?,
})
}
}
#[derive(Debug, Clone)]
struct ClassInput {
attrs: Vec<Attribute>,
vis: Visibility,
_class_token: kw::class,
ident: Ident,
superclass: Option<SuperclassInput>,
_brace_token: Brace,
items: Vec<ClassItem>,
}
impl Parse for ClassInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let content;
let vis = input.parse()?;
let class_token = input.parse()?;
let ident = input.parse()?;
let lookahead = input.lookahead1();
let superclass = if lookahead.peek(Token![:]) {
Some(input.parse()?)
} else {
None
};
let brace_token = braced!(content in input);
let mut items = Vec::new();
while !content.is_empty() {
items.push(content.parse()?);
}
Ok(ClassInput {
attrs,
vis,
_class_token: class_token,
ident,
superclass,
_brace_token: brace_token,
items,
})
}
}
#[derive(Debug, Clone)]
struct CrateAlias {
_crate_token: Token![crate],
_as_token: Token![as],
ident: Ident,
_semi_token: Token![;],
}
impl Parse for CrateAlias {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(CrateAlias {
_crate_token: input.parse()?,
_as_token: input.parse()?,
ident: input.parse()?,
_semi_token: input.parse()?,
})
}
}
struct ClassInputs {
crate_alias: Option<CrateAlias>,
inputs: Vec<ClassInput>,
}
impl Parse for ClassInputs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
let crate_alias = if lookahead.peek(Token![crate]) {
Some(input.parse()?)
} else {
None
};
let mut inputs = Vec::new();
while !input.is_empty() {
inputs.push(input.parse()?);
}
Ok(ClassInputs {
crate_alias,
inputs,
})
}
}
fn plusplus() -> proc_macro2::TokenStream {
let found_crate = crate_name("plusplus").expect("plusplus is present in `Cargo.toml`");
match found_crate {
FoundCrate::Itself => quote!(crate),
FoundCrate::Name(name) => {
let ident = Ident::new(&name, Span::call_site());
quote!( #ident )
}
}
}
fn cast_class_ptr(
plusplus: &proc_macro2::TokenStream,
from: &Type,
to: &Type,
expr: impl Into<proc_macro2::TokenStream>,
) -> proc_macro2::TokenStream {
let expr = expr.into();
quote! {{
let t: &#from = #expr;
let self_size = std::mem::size_of_val(t);
let target_size = std::mem::size_of::<#to<#plusplus::InConstruction>>();
assert!(self_size >= target_size);
let array_size = self_size - target_size;
let target_ptr = std::ptr::slice_from_raw_parts(t as *const #from as *const u8, array_size);
let target_ref = &*(target_ptr as *const #to);
assert_eq!(self_size, std::mem::size_of_val(target_ref));
target_ref
}}
}
fn cast_class_ptr_mut(
plusplus: &TokenStream,
from: &Type,
to: &Type,
expr: impl Into<TokenStream>,
) -> TokenStream {
let expr = expr.into();
quote! {{
let t: &mut #from = #expr;
let self_size = std::mem::size_of_val(t);
let target_size = std::mem::size_of::<#to<#plusplus::InConstruction>>();
assert!(self_size >= target_size);
let array_size = self_size - target_size;
let target_ptr = std::ptr::slice_from_raw_parts_mut(t as *mut #from as *mut u8, array_size);
let target_ref = &mut *(target_ptr as *mut #to);
assert_eq!(self_size, std::mem::size_of_val(target_ref));
target_ref
}}
}
fn set_arg_blank_lifetime(arg: &mut FnArg, lifetime: &Lifetime, lifetime_set: &mut bool) {
match arg {
FnArg::Receiver(rx) => {
if let Some((_, lt)) = &mut rx.reference {
maybe_set_lifetime_opt(lt, lifetime, lifetime_set);
}
}
FnArg::Typed(ty) => {
set_blank_type_lifetimes(&mut ty.ty, lifetime, lifetime_set);
}
}
}
fn set_blank_type_lifetimes(ty: &mut Type, lifetime: &Lifetime, lifetime_set: &mut bool) {
match ty {
Type::Array(arr) => set_blank_type_lifetimes(&mut arr.elem, lifetime, lifetime_set),
Type::BareFn(_) => {}
Type::Group(group) => set_blank_type_lifetimes(&mut group.elem, lifetime, lifetime_set),
Type::ImplTrait(_) => {} Type::Infer(_) => {}
Type::Macro(_) => {}
Type::Never(_) => {}
Type::Paren(paren) => set_blank_type_lifetimes(&mut paren.elem, lifetime, lifetime_set),
Type::Path(path) => {
if let Some(qself) = &mut path.qself {
set_blank_type_lifetimes(&mut qself.ty, lifetime, lifetime_set);
}
set_blank_path_lifetimes(&mut path.path, lifetime, lifetime_set);
}
Type::Ptr(ptr) => set_blank_type_lifetimes(&mut ptr.elem, lifetime, lifetime_set),
Type::Reference(refer) => {
maybe_set_lifetime_opt(&mut refer.lifetime, lifetime, lifetime_set);
set_blank_type_lifetimes(&mut refer.elem, lifetime, lifetime_set)
}
Type::Slice(slice) => set_blank_type_lifetimes(&mut slice.elem, lifetime, lifetime_set),
Type::TraitObject(obj) => {
set_blank_type_param_bounds(&mut obj.bounds, lifetime, lifetime_set)
}
Type::Tuple(tup) => {
for ty in &mut tup.elems {
set_blank_type_lifetimes(ty, lifetime, lifetime_set);
}
}
Type::Verbatim(_) => {}
_ => (),
}
}
fn set_blank_path_lifetimes(path: &mut Path, lifetime: &Lifetime, lifetime_set: &mut bool) {
for path_args in path.segments.iter_mut().map(|seg| &mut seg.arguments) {
match path_args {
PathArguments::None => {}
PathArguments::AngleBracketed(angle_args) => {
set_blank_angle_bracket_lifetimes(angle_args, lifetime, lifetime_set)
}
PathArguments::Parenthesized(paren_args) => {
for ty in &mut paren_args.inputs {
set_blank_type_lifetimes(ty, lifetime, lifetime_set);
}
if let ReturnType::Type(_, ty) = &mut paren_args.output {
set_blank_type_lifetimes(ty, lifetime, lifetime_set);
}
}
}
}
}
fn set_blank_angle_bracket_lifetimes(
angle: &mut AngleBracketedGenericArguments,
lifetime: &Lifetime,
lifetime_set: &mut bool,
) {
for arg in &mut angle.args {
set_blank_generic_lifetimes(arg, lifetime, lifetime_set);
}
}
fn maybe_set_lifetime(set: &mut Lifetime, to: &Lifetime, lifetime_set: &mut bool) {
if set.ident == format_ident!("_") {
*set = to.clone();
*lifetime_set = true;
}
}
fn maybe_set_lifetime_opt(set: &mut Option<Lifetime>, to: &Lifetime, lifetime_set: &mut bool) {
match set {
Some(lt) => maybe_set_lifetime(lt, to, lifetime_set),
None => {
*set = Some(to.clone());
*lifetime_set = true;
}
}
}
fn set_blank_type_param_bounds<'a>(
bounds: impl IntoIterator<Item = &'a mut TypeParamBound>,
lifetime: &Lifetime,
lifetime_set: &mut bool,
) {
for bound in bounds {
match bound {
TypeParamBound::Trait(trait_bound) => {
set_blank_path_lifetimes(&mut trait_bound.path, lifetime, lifetime_set)
}
TypeParamBound::Lifetime(lt) => maybe_set_lifetime(lt, lifetime, lifetime_set),
TypeParamBound::PreciseCapture(cap) => {
for p in &mut cap.params {
match p {
CapturedParam::Lifetime(lt) => {
maybe_set_lifetime(lt, lifetime, lifetime_set)
}
CapturedParam::Ident(_) => {}
_ => (),
}
}
}
TypeParamBound::Verbatim(_) => {}
_ => (),
}
}
}
fn set_blank_generic_lifetimes(
arg: &mut GenericArgument,
lifetime: &Lifetime,
lifetime_set: &mut bool,
) {
match arg {
GenericArgument::Lifetime(lt) => maybe_set_lifetime(lt, lifetime, lifetime_set),
GenericArgument::Type(ty) => set_blank_type_lifetimes(ty, lifetime, lifetime_set),
GenericArgument::Const(_) => {}
GenericArgument::AssocType(ty) => {
if let Some(args) = &mut ty.generics {
set_blank_angle_bracket_lifetimes(args, lifetime, lifetime_set);
}
set_blank_type_lifetimes(&mut ty.ty, lifetime, lifetime_set);
}
GenericArgument::AssocConst(_) => {}
GenericArgument::Constraint(constraint) => {
if let Some(args) = &mut constraint.generics {
set_blank_angle_bracket_lifetimes(args, lifetime, lifetime_set);
}
set_blank_type_param_bounds(&mut constraint.bounds, lifetime, lifetime_set);
}
_ => (),
}
}
#[derive(Debug, Clone)]
struct FuncInfo {
func: ImplItemFn,
name: Ident,
vtbl_name: Ident,
lifetime_bounds: Option<TokenStream>,
vtbl_sig: TokenStream,
args: Vec<Box<Pat>>,
mut_self: bool,
}
fn get_func_sig(class_name: &Type, f: &ImplItemFn) -> FuncInfo {
let func_name = &f.sig.ident;
let is_async = f.sig.asyncness.is_some();
let mut inputs = f.sig.inputs.clone();
let mut mut_self = false;
if let Some(FnArg::Receiver(rx)) = &f.sig.inputs.get(0) {
let receiver = &mut inputs[0];
if let Some((_, rx_lifetime)) = &rx.reference {
if rx.mutability.is_some() {
*receiver = FnArg::Typed(parse_quote!(this: & #rx_lifetime mut #class_name));
} else {
*receiver = FnArg::Typed(parse_quote!(this: & #rx_lifetime #class_name));
}
}
mut_self = rx.mutability.is_some();
};
let mut lifetimes: Vec<LifetimeParam> = Vec::new();
let future_fallback_lt: Lifetime = parse_quote!('rpp_future);
let mut using_future_lifetime = false;
let mut vtbl_inputs = inputs.clone();
if is_async {
for arg in &mut vtbl_inputs {
set_arg_blank_lifetime(arg, &future_fallback_lt, &mut using_future_lifetime);
}
if using_future_lifetime {
lifetimes.push(parse_quote!(#future_fallback_lt));
}
}
for generic in &f.sig.generics.params {
match generic {
GenericParam::Lifetime(lt) => {
let mut lt = lt.clone();
if using_future_lifetime {
lt.bounds.push(future_fallback_lt.clone());
}
lifetimes.push(lt)
}
GenericParam::Type(_) => {}
GenericParam::Const(_) => {}
}
}
let lifetime_bounds = if lifetimes.len() > 0 {
Some(quote!(<#(#lifetimes),*>))
} else {
None
};
let mut output = f.sig.output.clone();
if is_async {
let future_output = match output {
ReturnType::Default => quote!(()),
ReturnType::Type(_, ty) => quote!(#ty),
};
let future_lifetimes = if using_future_lifetime {
future_fallback_lt
} else {
assert!(lifetimes.len() > 0);
lifetimes[0].lifetime.clone()
};
output = parse_quote!(-> std::pin::Pin<Box<dyn #future_lifetimes + Future<Output=#future_output>>>);
}
let vtbl_name = format_ident!("fn_{func_name}");
let vtbl_sig = quote! {
(#vtbl_inputs) #output
};
let func_args = inputs
.into_iter()
.skip(1)
.map(|arg| match arg {
FnArg::Receiver(_) => unreachable!(),
FnArg::Typed(arg) => arg.pat,
})
.collect::<Vec<_>>();
FuncInfo {
func: f.clone(),
name: func_name.clone(),
vtbl_name,
lifetime_bounds,
vtbl_sig,
args: func_args,
mut_self,
}
}
#[derive(Debug, Clone, Copy)]
struct Derives {
clone: bool,
}
impl Derives {
fn from_attributes(attrs: impl Iterator<Item = Attribute>) -> syn::Result<Derives> {
let mut clone = false;
for attr in attrs {
if let AttrStyle::Inner(_) = attr.style {
return Err(Error::new(
attr.span(),
"did not expect inner attribute in class macro",
));
}
let derive_tokens = match attr.meta {
Meta::List(list) if list.path == parse_quote!(derive) => {
if !matches!(list.delimiter, MacroDelimiter::Paren(_)) {
return Err(Error::new(
list.delimiter.span().open(),
"derive attribute must have parenthesis",
));
}
list.tokens
}
_ => return Err(Error::new(attr.span(), "unsupported attribute on class")),
};
let derive_path: Path = parse2(derive_tokens)?;
if derive_path == parse_quote!(Clone) {
if clone {
return Err(Error::new(
derive_path.span(),
"Clone derive already specified",
));
}
clone = true;
}
}
Ok(Derives { clone })
}
fn has_any_derives(&self) -> bool {
self.clone
}
}
struct ClassData {
plusplus: TokenStream,
class_name: Ident,
class_type: Type,
class_mod_name: Ident,
vtbl_ident: Ident,
class_vis: Visibility,
fields: Vec<Field>,
constructors: Vec<FuncInfo>,
member_funcs: Vec<FuncInfo>,
overrides: Vec<OverrideItem>,
override_funcs: Vec<FuncInfo>,
superclass_type: Option<Type>,
mod_superclass_type: Option<Type>,
derives: Derives,
}
impl ClassData {
fn from_input(input: ClassInput, crate_alias: Option<&CrateAlias>) -> syn::Result<ClassData> {
let ClassInput {
attrs,
vis: class_vis,
_class_token: _,
ident: class_name,
superclass,
_brace_token: _,
items: class_items,
} = input;
let mut fields = Vec::new();
let mut constructors = Vec::new();
let mut member_funcs = Vec::new();
let mut overrides = Vec::new();
let mut override_funcs = Vec::new();
let class_type: Type = parse_quote!(#class_name);
for item in class_items {
match item {
ClassItem::Field { field, .. } => fields.push(field),
ClassItem::ImplItemFn(func) => {
if let Some(FnArg::Receiver(_)) = func.sig.inputs.get(0) {
member_funcs.push(get_func_sig(&class_type, &func))
} else {
constructors.push(get_func_sig(&class_type, &func));
}
}
ClassItem::OverrideItem(override_item) => {
override_funcs.extend(
override_item
.items
.iter()
.map(|f| get_func_sig(&class_type, &f)),
);
overrides.push(override_item);
}
}
}
let class_mod_name =
format_ident!("plusplus__class_{}", class_name.to_string().to_lowercase());
let plusplus = if let Some(alias) = crate_alias {
let alias = &alias.ident;
quote!(#alias)
} else {
plusplus()
};
let superclass_type = superclass.map(|sc| sc.ty);
let mod_superclass_type = match superclass_type.clone() {
Some(Type::Path(mut type_path)) => {
if type_path.path.segments.get(0) != Some(&parse_quote!(crate)) {
type_path.path.segments.insert(0, parse_quote!(super));
}
Some(Type::Path(type_path))
}
ty => ty,
};
let derives = Derives::from_attributes(attrs.into_iter())?;
Ok(ClassData {
plusplus,
vtbl_ident: format_ident!("{}Vtbl", class_name),
class_vis,
class_name,
class_type,
class_mod_name,
fields,
constructors,
member_funcs,
overrides,
override_funcs,
superclass_type,
mod_superclass_type,
derives,
})
}
fn has_superclass(&self) -> bool {
self.superclass_type.is_some()
}
fn gen_mod_vtbl_struct(&self) -> TokenStream {
let vtbl_ident = &self.vtbl_ident;
let class_name = &self.class_name;
let plusplus = &self.plusplus;
let mut vtbl_func_names = Vec::new();
let mut vtbl_sigs = Vec::new();
let mut my_func_names = Vec::new();
let mut async_func_impls = Vec::new();
let mut func_setters = Vec::new();
let mut vtbl_fors = Vec::new();
let mut vtbl_unsafes = Vec::new();
for f in self.member_funcs.iter() {
let FuncInfo {
func:
ImplItemFn {
sig:
Signature {
asyncness,
unsafety,
..
},
..
},
name: func_name,
vtbl_name: vtbl_func_name,
lifetime_bounds,
vtbl_sig,
args,
mut_self: _,
} = f;
let my_func_name = format_ident!("my_{func_name}");
let vtbl_for = lifetime_bounds.as_ref().map(|bounds| quote!(for #bounds));
vtbl_fors.push(vtbl_for.clone());
vtbl_unsafes.push(unsafety);
if asyncness.is_some() {
async_func_impls.push(quote!{
let #my_func_name: #vtbl_for #unsafety fn #vtbl_sig = |this, #(#args)*| #unsafety {
Box::pin(#class_name::#my_func_name(this, #(#args)*))
};
});
func_setters.push(quote! {
#vtbl_func_name: #my_func_name,
})
} else {
func_setters.push(quote! {
#vtbl_func_name: #class_name::#my_func_name,
})
}
my_func_names.push(my_func_name);
vtbl_func_names.push(vtbl_func_name);
vtbl_sigs.push(vtbl_sig);
}
let vtbl_drop_field: Option<_>;
let vtbl_drop_func: Option<_>;
let vtbl_drop_set: Option<_>;
if !self.has_superclass() {
vtbl_drop_field = Some(quote! {
pub manually_drop: unsafe fn(*mut #class_name),
});
vtbl_drop_func = Some(quote! {
unsafe fn manually_drop(this: *mut #class_name) {
unsafe{ std::ptr::drop_in_place(this) }
}
});
vtbl_drop_set = Some(quote! {
manually_drop,
});
} else {
vtbl_drop_field = None;
vtbl_drop_func = None;
vtbl_drop_set = None;
};
let mut vtbl_trait_fields = None;
let mut vtbl_trait_impls = None;
let mut vtbl_trait_setters = None;
if self.derives.has_any_derives() && !self.has_superclass() {
let Derives { clone } = self.derives;
let clone_field = clone.then(|| {
quote! {
class_clone: fn(&#class_name) -> #plusplus::ClassBox<#class_name>,
}
});
let clone_impl = clone.then(|| {
quote! {
fn class_clone(this: &#class_name) -> #plusplus::ClassBox<#class_name> {
use #plusplus::{Class, ClassInConstruction};
let in_construction = unsafe{ this.as_in_construction() };
in_construction.clone().finish()
}
}
});
let clone_set = clone.then(|| {
quote! {
class_clone,
}
});
vtbl_trait_fields = Some(quote! {
#clone_field
});
vtbl_trait_impls = Some(quote! {
#clone_impl
});
vtbl_trait_setters = Some(quote! {
#clone_set
})
};
quote! {
#[doc(hidden)]
#[derive(Clone, Copy)]
pub struct #vtbl_ident {
#vtbl_drop_field
#vtbl_trait_fields
#(pub #vtbl_func_names: #vtbl_fors #vtbl_unsafes fn #vtbl_sigs,)*
}
impl #vtbl_ident {
const BASE: Self = {
#vtbl_drop_func
#vtbl_trait_impls
#(#async_func_impls)*
Self {
#vtbl_drop_set
#vtbl_trait_setters
#(#func_setters)*
}
};
}
}
}
fn gen_fn_set_vtbls(&self) -> TokenStream {
let plusplus = &self.plusplus;
let class_name = &self.class_name;
let set_vtbls = self.overrides.iter().map(|ovr| {
let ovr_class = &ovr.override_class;
let ovr_class = match ovr_class.clone() {
Type::Path(mut type_path) => {
type_path.path.segments.insert(0, parse_quote!(super));
Type::Path(type_path)
}
ty => ty,
};
let mut ol_func_names = Vec::new();
let mut ol_func_sigs = Vec::new();
let mut ol_func_self_call_impls = Vec::new();
let mut ol_lifetime_bounds = Vec::new();
for f in &ovr.items {
let FuncInfo {
func:
ImplItemFn {
sig:
Signature {
asyncness,
unsafety,
..
},
..
},
name: func_name,
vtbl_name,
lifetime_bounds,
vtbl_sig: func_sig,
args: func_args,
mut_self,
} = get_func_sig(&ovr_class, f);
ol_func_names.push(vtbl_name);
ol_func_sigs.push(func_sig);
ol_lifetime_bounds.push(lifetime_bounds);
let func_name = format_ident!("my_{}", func_name);
let make_this = if mut_self {
quote! {
let this: &mut #class_name = unsafe{ #class_name::from_root_class_mut(this.root_class_mut()) };
}
} else {
quote! {
let this: &#class_name = unsafe{ #class_name::from_root_class_ref(this.root_class()) };
}
};
let self_call = if asyncness.is_some() {
quote! {
#make_this
#unsafety { Box::pin(this.#func_name(#(#func_args,)*)) }
}
} else {
quote! {
#make_this
#unsafety { this.#func_name(#(#func_args,)*) }
}
};
ol_func_self_call_impls.push(self_call);
}
quote! {{
let this: &mut #ovr_class = &mut *(unsafe{ self.to_constructed() });
#(
fn #ol_func_names #ol_lifetime_bounds #ol_func_sigs {
#ol_func_self_call_impls
}
unsafe{ this.plusplus__vtbl_mut().#ol_func_names = #ol_func_names };
)*
}}
});
let root_type: Type = parse_quote!(<#class_name as #plusplus::Class>::RootClass);
let root_type = &root_type;
let set_subclass = self.has_superclass().then(|| quote!{
use #plusplus::Class as _;
unsafe{ self.superclass.plusplus__set_subclass(<#class_name as #plusplus::Class>::TYPE_ID) };
{
unsafe fn manually_drop(this: *mut #root_type) {
let this = unsafe{ #class_name::from_root_class_mut(&mut *this) };
unsafe{ std::ptr::drop_in_place(this) };
}
let root_vtbl = unsafe{ <#class_name as #plusplus::Class>::root_class_mut(self.to_constructed()).plusplus__vtbl_mut() };
root_vtbl.manually_drop = manually_drop;
}
});
let mut set_trait_vtbls = None;
if !self.has_superclass() {
let mut derive_trait_bounds = None;
let mut derive_trait_impls = None;
if self.derives.has_any_derives() {
let Derives { clone } = self.derives;
let clone_trait_bound = clone.then(|| quote!(Clone));
let clone_impl = clone.then(|| quote!{
let class_clone = |this: &#class_name| -> #plusplus::ClassBox<#class_name> {
use #plusplus::{Class as _, ClassBox, ClassInConstruction};
let child_class = unsafe{ Class::from_root_class_ref(this).as_in_construction() };
let cloned = child_class.clone().finish();
unsafe{ ClassBox::from_raw(ClassBox::leak(cloned).root_class_mut()) }
};
self.vtbl.class_clone = class_clone;
});
derive_trait_bounds =
Some(quote! {where Class::InConstruction: #clone_trait_bound});
derive_trait_impls = Some(quote! {
#clone_impl
});
}
set_trait_vtbls = Some(quote! {
#[doc(hidden)]
pub fn plusplus__set_trait_vtbls<Class: ?Sized + #plusplus::Class<RootClass=#class_name>>(&mut self)
#derive_trait_bounds
{
#derive_trait_impls
}
});
}
quote! {
fn plusplus__set_vtbls(&mut self) {
#set_subclass
#(#set_vtbls)*
}
#set_trait_vtbls
}
}
fn gen_mod_class_struct(&self) -> TokenStream {
let plusplus = &self.plusplus;
let superclass_field = self.mod_superclass_type.as_ref().map(|sc_type| {
quote! {
superclass: #sc_type<#plusplus::InConstruction>,
}
});
let superclass_field = superclass_field.as_ref();
let superclass_bound = self.mod_superclass_type.as_ref().map(|sc_ident| {
quote! {
where #sc_ident: #plusplus::Class
}
});
let class_struct_vis = correct_priv_vis(self.class_vis.clone());
let vtbl_ident = &self.vtbl_ident;
let class_name = &self.class_name;
let fields = &self.fields;
let init_superclass_field = superclass_field.map(|f| quote!(pub #f));
let init_fields = self.fields.iter().cloned().map(|f| Field {
vis: Visibility::Public(parse_quote!(pub)),
..f
});
let derives = self.derives.has_any_derives().then(|| {
let Derives { clone } = self.derives;
let clone = clone.then(|| quote!(Clone,));
quote!(#[derive(#clone)])
});
quote! {
#[repr(C)]
#derives
#class_struct_vis struct #class_name<C: ?Sized + #plusplus::ClassMemory = #plusplus::Constructed>
#superclass_bound
{
#superclass_field
vtbl: #vtbl_ident,
subclass_id: Option<&'static std::any::TypeId>,
#(#fields,)*
memory: C,
}
pub struct PlusPlus__InitClass {
#init_superclass_field
#(#init_fields,)*
}
}
}
fn gen_mod_trait_impls(&self) -> TokenStream {
let plusplus = &self.plusplus;
let class_name = &self.class_name;
let Derives { clone } = self.derives;
let clone_impl = clone.then(|| {
if self.has_superclass() {
quote! {
impl #plusplus::ClassClone for #class_name {
fn class_clone(&self) -> #plusplus::ClassBox<Self> {
use #plusplus::{ClassBox, Class, ClassClone};
let root_ref: &mut _ = ClassBox::leak(self.root_class().class_clone());
let self_ref = unsafe{ Self::from_root_class_mut(root_ref) };
unsafe{ ClassBox::from_raw(self_ref) }
}
}
}
} else {
quote! {
impl #plusplus::ClassClone for #class_name {
fn class_clone(&self) -> #plusplus::ClassBox<Self> {
(self.vtbl.class_clone)(self)
}
}
}
}
});
quote! {
#clone_impl
}
}
fn gen_superclass_casters(&self) -> Option<TokenStream> {
let Some(sc_type) = self.superclass_type.as_ref() else {
return None;
};
let class_name = &self.class_name;
let deref_upcast = cast_class_ptr(&self.plusplus, &self.class_type, sc_type, quote! {self});
let deref_upcast_mut =
cast_class_ptr_mut(&self.plusplus, &self.class_type, sc_type, quote! {self});
let ref_downcast = cast_class_ptr(&self.plusplus, sc_type, &self.class_type, quote! {self});
let ref_downcast_mut =
cast_class_ptr_mut(&self.plusplus, sc_type, &self.class_type, quote! {self});
let plusplus = &self.plusplus;
Some(quote! {
impl std::ops::Deref for #class_name {
type Target = #sc_type;
fn deref(&self) -> &Self::Target {
unsafe { #deref_upcast }
}
}
impl std::ops::DerefMut for #class_name {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { #deref_upcast_mut }
}
}
impl<'a> #plusplus::Downcast<#class_name> for &'a #sc_type {
type Wrapped = &'a #class_name;
fn downcast(self) -> Result<&'a #class_name, Self> {
use #plusplus::Class;
let subclass_type_id = <#class_name as #plusplus::Class>::TYPE_ID;
if self.subclass_id() == Some(subclass_type_id) {
Ok(unsafe{ #ref_downcast })
} else {
Err(self)
}
}
}
impl<'a> #plusplus::Downcast<#class_name> for &'a mut #sc_type {
type Wrapped = &'a mut #class_name;
fn downcast(self) -> Result<&'a mut #class_name, Self> {
use #plusplus::Class;
let subclass_type_id = <#class_name as #plusplus::Class>::TYPE_ID;
if self.subclass_id() == Some(subclass_type_id) {
Ok(unsafe{ #ref_downcast_mut })
} else {
Err(self)
}
}
}
})
}
fn gen_mod_impl_class_trait(&self) -> TokenStream {
let plusplus = &self.plusplus;
let class_name = &self.class_name;
let root_class = self
.mod_superclass_type
.as_ref()
.map(|sc_ident| quote! { <#sc_ident as #plusplus::Class>::RootClass })
.unwrap_or_else(|| quote! { #class_name });
let from_root_class_ref = cast_class_ptr(
plusplus,
&parse_quote!(#root_class),
&parse_quote!(#class_name),
quote!(root),
);
let from_root_class_mut = cast_class_ptr_mut(
plusplus,
&parse_quote!(#root_class),
&parse_quote!(#class_name),
quote!(root),
);
quote! {
unsafe impl #plusplus::Class for #class_name {
const TYPE_ID: &'static std::any::TypeId = &std::any::TypeId::of::<#class_name>();
type RootClass = #root_class;
type InConstruction = #class_name<#plusplus::InConstruction>;
fn subclass_id(&self) -> Option<&'static std::any::TypeId> {
self.subclass_id
}
fn root_class(&self) -> &Self::RootClass {
self
}
fn root_class_mut(&mut self) -> &mut Self::RootClass {
self
}
unsafe fn manually_drop(slot: &mut std::mem::ManuallyDrop<Self>) {
let as_root_class = slot.root_class_mut();
let manual_drop_fn = unsafe{ as_root_class.plusplus__vtbl_mut().manually_drop };
unsafe{ manual_drop_fn(as_root_class); }
}
unsafe fn as_in_construction(&self) -> &#class_name<#plusplus::InConstruction> {
unsafe{ &*(self as *const Self as *const #class_name<#plusplus::InConstruction>) }
}
unsafe fn as_in_construction_mut(&mut self) -> &mut #class_name<#plusplus::InConstruction> {
unsafe{ &mut *(self as *mut Self as *mut #class_name<#plusplus::InConstruction>) }
}
unsafe fn from_root_class_ref(root: &Self::RootClass) -> &Self {
unsafe{ #from_root_class_ref }
}
unsafe fn from_root_class_mut(root: &mut Self::RootClass) -> &mut Self {
unsafe{ #from_root_class_mut }
}
}
impl #plusplus::ClassInConstruction for #class_name<#plusplus::InConstruction> {
type Class = #class_name;
fn finish(self) -> #plusplus::ClassBox<#class_name> {
let boxed = Box::new(self);
let leaked = Box::leak(boxed);
let constructed = unsafe{ leaked.to_constructed() };
unsafe{ #plusplus::ClassBox::from_raw(constructed) }
}
}
}
}
fn gen_mod_class_impl(&self) -> TokenStream {
let class_name = &self.class_name;
let vtbl_ident = &self.vtbl_ident;
let mut call_vtbl_impls = Vec::new();
for f in self.member_funcs.iter() {
let FuncInfo {
func: ImplItemFn { vis, sig, .. },
name: _,
vtbl_name,
lifetime_bounds: _,
vtbl_sig: _,
args: func_args,
mut_self: _,
} = f;
let vis = correct_priv_vis(vis.clone());
let do_await = sig.asyncness.is_some().then(|| quote!(.await));
let call_vtbl = quote! {
#vis #sig {
(self.vtbl.#vtbl_name)(self, #(#func_args,)*) #do_await
}
};
call_vtbl_impls.push(call_vtbl);
}
let mut my_func_impls = Vec::new();
let mut super_func_impls = Vec::new();
for (f, is_override) in self
.member_funcs
.iter()
.cloned()
.map(|f| (f, false))
.chain(self.override_funcs.iter().cloned().map(|f| (f, true)))
{
let FuncInfo {
func:
ImplItemFn {
attrs: _,
vis,
defaultness: _,
sig,
block,
},
name: func_name,
vtbl_name: _,
lifetime_bounds: _,
vtbl_sig: _,
args: func_args,
mut_self,
} = f;
let my_impl_name = format_ident!("my_{}", func_name);
let mut my_impl_sig = sig.clone();
my_impl_sig.ident = my_impl_name.clone();
my_func_impls.push(quote! {
#vis #my_impl_sig {
#block
}
});
if is_override {
let super_impl_name = format_ident!("super_{}", func_name);
let mut super_impl_sig = sig.clone();
super_impl_sig.ident = super_impl_name.clone();
let get_super = if mut_self {
quote! {
self.plusplus__super_mut()
}
} else {
quote! {
self.plusplus__super_ref()
}
};
let super_impl_block = if sig.asyncness.is_some() {
quote! { #get_super.#my_impl_name(#(#func_args,)*).await }
} else {
quote! { #get_super.#my_impl_name(#(#func_args,)*) }
};
super_func_impls.push(quote! {
#vis #super_impl_sig {
#super_impl_block
}
});
}
}
let superclass_getters = self.mod_superclass_type.as_ref().map(|sc_ident| {
quote! {
fn plusplus__super_ref(&self) -> &#sc_ident {
self
}
fn plusplus__super_mut(&mut self) -> &mut #sc_ident {
self
}
}
});
quote! {
impl #class_name {
#(#call_vtbl_impls)*
#(#super_func_impls)*
#superclass_getters
#[doc(hidden)]
pub unsafe fn plusplus__vtbl_mut(&mut self) -> &mut #vtbl_ident {
&mut self.vtbl
}
}
}
}
fn gen_mod_in_construction_class_impl(&self) -> TokenStream {
let plusplus = &self.plusplus;
let class_name = &self.class_name;
let vtbl_ident = &self.vtbl_ident;
let set_vtbl_func = self.gen_fn_set_vtbls();
let superclass_field = self
.has_superclass()
.then(|| quote! {superclass: init.superclass,});
let fields = self.fields.iter().map(|f| &f.ident).collect::<Vec<_>>();
quote! {
impl #class_name<#plusplus::InConstruction> {
#set_vtbl_func
pub(super) fn plusplus__new_from_init(init: PlusPlus__InitClass) -> Self {
use #plusplus::Class;
let mut this = Self {
vtbl: #vtbl_ident::BASE,
memory: #plusplus::InConstruction::default(),
subclass_id: None,
#superclass_field
#(#fields: init.#fields,)*
};
this.plusplus__set_vtbls();
unsafe{ this.to_constructed().root_class_mut().as_in_construction_mut() }.plusplus__set_trait_vtbls::<#class_name>();
this
}
#[doc(hidden)]
pub unsafe fn plusplus__set_subclass(&mut self, subclass_id: &'static std::any::TypeId) {
self.subclass_id = Some(subclass_id);
}
pub unsafe fn to_constructed(&mut self) -> &mut #class_name {
unsafe{ &mut *(std::ptr::slice_from_raw_parts_mut::<u8>(self as *mut _ as *mut u8, 0) as *mut #class_name) }
}
}
}
}
fn gen_init_class_macro(&self) -> TokenStream {
let plusplus = &self.plusplus;
let class_name = &self.class_name;
let class_mod_name = &self.class_mod_name;
quote! {
macro_rules! init_class {
($($tt:tt)*) => {{
#class_name::<#plusplus::InConstruction>::plusplus__new_from_init(#class_mod_name::PlusPlus__InitClass {
$($tt)*
})
}}
}
}
}
fn gen_class_impl(&self) -> TokenStream {
let class_name = &self.class_name;
let mut my_func_impls = Vec::new();
for f in self
.member_funcs
.iter()
.cloned()
.chain(self.override_funcs.iter().cloned())
{
let FuncInfo {
func:
ImplItemFn {
attrs: _,
vis,
defaultness: _,
sig,
block,
},
name: func_name,
vtbl_name: _,
lifetime_bounds: _,
vtbl_sig: _,
args: _,
mut_self: _,
} = f;
let my_impl_name = format_ident!("my_{}", func_name);
let mut my_impl_sig = sig.clone();
my_impl_sig.ident = my_impl_name.clone();
my_func_impls.push(quote! {
#vis #my_impl_sig {
#block
}
});
}
let init_class_macro = self.gen_init_class_macro();
let mut constructor_impls = Vec::new();
for c in self.constructors.iter() {
let ImplItemFn {
attrs,
vis,
defaultness,
sig,
block,
} = &c.func;
let vis = correct_priv_vis(vis.clone());
constructor_impls.push(quote! {
#(#attrs)* #vis #defaultness #sig {
#init_class_macro
#block
}
});
}
quote! {
impl #class_name {
#(#constructor_impls)*
#(#my_func_impls)*
}
}
}
fn gen_class(&self) -> TokenStream {
let class_vis = &self.class_vis;
let class_name = &self.class_name;
let class_mod_name = &self.class_mod_name;
let mod_vtbl_struct = self.gen_mod_vtbl_struct();
let mod_class_struct = self.gen_mod_class_struct();
let mod_impl_class_trait = self.gen_mod_impl_class_trait();
let mod_trait_impls = self.gen_mod_trait_impls();
let superclass_cast = self.gen_superclass_casters();
let mod_class_impl = self.gen_mod_class_impl();
let mod_in_construction_class_impl = self.gen_mod_in_construction_class_impl();
let class_impl = self.gen_class_impl();
quote! {
#class_vis use #class_mod_name::#class_name;
mod #class_mod_name {
use super::*;
#mod_vtbl_struct
#mod_class_struct
#mod_class_impl
#mod_impl_class_trait
#mod_in_construction_class_impl
#mod_trait_impls
}
#class_impl
#superclass_cast
}
}
}
fn do_class(inputs: ClassInputs) -> syn::Result<TokenStream> {
let class_data = inputs
.inputs
.into_iter()
.map(|input| Ok(ClassData::from_input(input, inputs.crate_alias.as_ref())?.gen_class()))
.collect::<Result<Vec<_>, syn::Error>>()?;
Ok(quote! {
#(#class_data)*
})
}
#[proc_macro]
pub fn class(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
let inputs = parse_macro_input!(tokens as ClassInputs);
do_class(inputs)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}