From 5d1fda4666b621c317731175ca385f501daebc35 Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Sat, 1 Oct 2022 00:23:48 +0200 Subject: [PATCH] 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 --- crates/macros/src/class.rs | 4 ++++ crates/macros/src/startup_function.rs | 29 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/crates/macros/src/class.rs b/crates/macros/src/class.rs index 4e5e81e..c10a015 100644 --- a/crates/macros/src/class.rs +++ b/crates/macros/src/class.rs @@ -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, + pub flags: Option, } #[derive(Debug)] @@ -37,6 +38,7 @@ pub enum ParsedAttribute { pub struct AttrArgs { name: Option, modifier: Option, + flags: Option, } pub fn parser(args: AttributeArgs, mut input: ItemStruct) -> Result { @@ -117,6 +119,7 @@ pub fn parser(args: AttributeArgs, mut input: ItemStruct) -> Result 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 docs: comments, properties, modifier: args.modifier, + flags, ..Default::default() }; diff --git a/crates/macros/src/startup_function.rs b/crates/macros/src/startup_function.rs index c6f078c..47fcfeb 100644 --- a/crates/macros/src/startup_function.rs +++ b/crates/macros/src/startup_function.rs @@ -121,6 +121,31 @@ fn build_classes(classes: &HashMap) -> Result> { } }); + 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) -> Result> { #(#interfaces)* // #(#properties)* #parent - .object_override::<#ident>(); + #flags + #object_override + ; #class_modifier let class = builder.build() .expect(concat!("Unable to build class `", #class_name, "`"));