Support marking classes as interfaces (#155)

* Support marking classes as interfaces

This allows passing flags as part of `#[php_class(flags=Interface]` etc, which allows one to mark a class as being an interface.

When a class is an interface, it also shouldn't get a constructor created for it.

* rustfmt
This commit is contained in:
Joe Hoyle 2022-10-01 00:23:48 +02:00 committed by GitHub
parent 90cbbc0fca
commit 5d1fda4666
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 1 deletions

View File

@ -22,6 +22,7 @@ pub struct Class {
/// A function name called when creating the class entry. Given an instance
/// of `ClassBuilder` and must return it.
pub modifier: Option<String>,
pub flags: Option<String>,
}
#[derive(Debug)]
@ -37,6 +38,7 @@ pub enum ParsedAttribute {
pub struct AttrArgs {
name: Option<String>,
modifier: Option<String>,
flags: Option<Expr>,
}
pub fn parser(args: AttributeArgs, mut input: ItemStruct) -> Result<TokenStream> {
@ -117,6 +119,7 @@ pub fn parser(args: AttributeArgs, mut input: ItemStruct) -> Result<TokenStream>
let ItemStruct { ident, .. } = &input;
let class_name = args.name.unwrap_or_else(|| ident.to_string());
let struct_path = ident.to_string();
let flags = args.flags.map(|flags| flags.to_token_stream().to_string());
let class = Class {
class_name,
struct_path,
@ -125,6 +128,7 @@ pub fn parser(args: AttributeArgs, mut input: ItemStruct) -> Result<TokenStream>
docs: comments,
properties,
modifier: args.modifier,
flags,
..Default::default()
};

View File

@ -121,6 +121,31 @@ fn build_classes(classes: &HashMap<String, Class>) -> Result<Vec<TokenStream>> {
}
});
let flags = {
if let Some(flags) = &class.flags {
let mut name = "::ext_php_rs::flags::ClassFlags::".to_owned();
name.push_str(flags);
let expr: Expr = syn::parse_str(&name).map_err(|_| {
anyhow!("Invalid expression given for `{}` flags", class_name)
})?;
Some(quote! { .flags(#expr) })
} else {
None
}
};
let object_override = {
if let Some(flags) = &class.flags {
if flags == "Interface" {
None
} else {
Some(quote! { .object_override::<#ident>() })
}
} else {
Some(quote! { .object_override::<#ident>() })
}
};
Ok(quote! {{
let builder = ::ext_php_rs::builders::ClassBuilder::new(#class_name)
#(#methods)*
@ -128,7 +153,9 @@ fn build_classes(classes: &HashMap<String, Class>) -> Result<Vec<TokenStream>> {
#(#interfaces)*
// #(#properties)*
#parent
.object_override::<#ident>();
#flags
#object_override
;
#class_modifier
let class = builder.build()
.expect(concat!("Unable to build class `", #class_name, "`"));