use proc_macro_crate::{FoundCrate, crate_name};
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{AngleBracketedGenericArguments, CapturedParam, GenericArgument, GenericParam, Lifetime, LifetimeParam, Path, PathArguments, ReturnType, Signature, Token, TypeParamBound};
use syn::parse::{Parse, ParseStream};
use syn::token::Brace;
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 {
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 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 {
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,
}
}
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>,
}
impl ClassData {
fn from_input(input: ClassInput, crate_alias: Option<&CrateAlias>) -> ClassData {
let ClassInput {
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
};
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,
}
}
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 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;
};
quote! {
#[doc(hidden)]
pub struct #vtbl_ident {
#vtbl_drop_field
#(pub #vtbl_func_names: #vtbl_fors #vtbl_unsafes fn #vtbl_sigs,)*
}
impl #vtbl_ident {
const BASE: Self = {
#vtbl_drop_func
#(#async_func_impls)*
Self {
#vtbl_drop_set
#(#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 {
let cast_mut = cast_class_ptr_mut(
&plusplus,
&ovr_class,
&self.class_type,
quote! {this},
);
quote! {
let this: &mut #class_name = unsafe{ #cast_mut };
}
} else {
let cast = cast_class_ptr(&plusplus, &ovr_class, &self.class_type, quote! {this});
quote! {
let this: &#class_name = unsafe{ #cast };
}
};
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 cast_root_to_self =
cast_class_ptr_mut(&plusplus, &root_type, &self.class_type, quote!(ref_mut));
let root_type = &root_type;
let set_subclass = self.has_superclass().then(|| quote!{
unsafe{ self.superclass.plusplus__set_subclass(<#class_name as #plusplus::Class>::TYPE_ID) };
{
unsafe fn manually_drop(this: *mut #root_type) {
let ref_mut = unsafe{ &mut *this };
let this = unsafe{ #cast_root_to_self };
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;
}
});
quote! {
fn plusplus__set_vtbls(&mut self) {
#set_subclass
#(#set_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
});
quote! {
#[repr(C)]
#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_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 });
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;
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); }
}
}
}
}
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 class_vis = correct_priv_vis(self.class_vis.clone());
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 {
let mut this = Self {
vtbl: #vtbl_ident::BASE,
memory: #plusplus::InConstruction::default(),
subclass_id: None,
#superclass_field
#(#fields: init.#fields,)*
};
this.plusplus__set_vtbls();
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) }
}
#class_vis fn finish(self: #class_name<#plusplus::InConstruction>) -> #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_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 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
}
#class_impl
#superclass_cast
}
}
}
#[proc_macro]
pub fn class(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
let inputs = parse_macro_input!(tokens as ClassInputs);
let class_data = inputs.inputs.into_iter().map(|input| ClassData::from_input(input, inputs.crate_alias.as_ref()).gen_class());
let output = quote!{
#(#class_data)*
};
output.into()
}