diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs index e744703..2e6deaf 100644 --- a/crates/macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -87,10 +87,11 @@ pub fn php_module(_: TokenStream, input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn php_startup(_: TokenStream, input: TokenStream) -> TokenStream { +pub fn php_startup(args: TokenStream, input: TokenStream) -> TokenStream { + let args = parse_macro_input!(args as AttributeArgs); let input = parse_macro_input!(input as ItemFn); - match startup_function::parser(input) { + match startup_function::parser(Some(args), input) { Ok(parsed) => parsed, Err(e) => syn::Error::new(Span::call_site(), e).to_compile_error(), } diff --git a/crates/macros/src/module.rs b/crates/macros/src/module.rs index 9eb2df3..2c118c0 100644 --- a/crates/macros/src/module.rs +++ b/crates/macros/src/module.rs @@ -34,7 +34,7 @@ pub fn parser(input: ItemFn) -> Result { fn php_module_startup() {} }) .map_err(|_| anyhow!("Unable to generate PHP module startup function."))?; - let startup = startup_function::parser(parsed)?; + let startup = startup_function::parser(None, parsed)?; state = STATE.lock(); Some(startup) diff --git a/crates/macros/src/startup_function.rs b/crates/macros/src/startup_function.rs index 47fcfeb..76b9877 100644 --- a/crates/macros/src/startup_function.rs +++ b/crates/macros/src/startup_function.rs @@ -1,13 +1,27 @@ use std::collections::HashMap; use anyhow::{anyhow, Result}; +use darling::FromMeta; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; -use syn::{Expr, ItemFn, Signature}; +use syn::{AttributeArgs, Expr, ItemFn, Signature}; use crate::{class::Class, constant::Constant, STATE}; -pub fn parser(input: ItemFn) -> Result { +#[derive(Default, Debug, FromMeta)] +#[darling(default)] +struct StartupArgs { + before: bool, +} + +pub fn parser(args: Option, input: ItemFn) -> Result { + let args = if let Some(args) = args { + StartupArgs::from_list(&args) + .map_err(|e| anyhow!("Unable to parse attribute arguments: {:?}", e))? + } else { + StartupArgs::default() + }; + let ItemFn { sig, block, .. } = input; let Signature { ident, .. } = sig; let stmts = &block.stmts; @@ -17,6 +31,11 @@ pub fn parser(input: ItemFn) -> Result { let classes = build_classes(&state.classes)?; let constants = build_constants(&state.constants); + let (before, after) = if args.before { + (Some(quote! { internal(); }), None) + } else { + (None, Some(quote! { internal(); })) + }; let func = quote! { #[doc(hidden)] @@ -30,11 +49,10 @@ pub fn parser(input: ItemFn) -> Result { ::ext_php_rs::internal::ext_php_rs_startup(); + #before #(#classes)* #(#constants)* - - // TODO return result? - internal(); + #after 0 } diff --git a/src/lib.rs b/src/lib.rs index 41216a3..7d9f5b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -518,6 +518,11 @@ pub use ext_php_rs_derive::php_class; /// this macro if you have registered any classes or constants when using the /// [`macro@php_module`] macro. /// +/// The attribute accepts one optional flag -- `#[php_startup(before)]` -- +/// which forces the annotated function to be called _before_ the other classes +/// and constants are registered. By default the annotated function is called +/// after these classes and constants are registered. +/// /// # Example /// /// ```