1- use std:: sync:: MutexGuard ;
2-
31use anyhow:: { anyhow, bail, Result } ;
42use proc_macro2:: { Ident , Span , TokenStream } ;
53use quote:: quote;
@@ -11,56 +9,36 @@ use crate::{
119 startup_function, State , STATE ,
1210} ;
1311
14- pub fn parser ( input : ItemFn ) -> Result < TokenStream > {
12+ fn prepare < ' a > (
13+ input : ItemFn ,
14+ functions : & [ Function ] ,
15+ startup_fn : Option < & TokenStream > ,
16+ startup_function_name : Option < & str > ,
17+ classes : impl Iterator < Item = & ' a Class > ,
18+ describe : & TokenStream ,
19+ ) -> Result < TokenStream > {
1520 let ItemFn { sig, block, .. } = input;
1621 let Signature { output, inputs, .. } = sig;
1722 let stmts = & block. stmts ;
1823
19- let mut state = STATE . lock ( ) ;
20-
21- if state. built_module {
22- bail ! ( "You may only define a module with the `#[php_module]` attribute once." ) ;
23- }
24-
25- state. built_module = true ;
26-
2724 // Generate startup function if one hasn't already been tagged with the macro.
28- let startup_fn = if ( !state. classes . is_empty ( ) || !state. constants . is_empty ( ) )
29- && state. startup_function . is_none ( )
30- {
31- drop ( state) ;
32-
33- let parsed = syn:: parse2 ( quote ! {
34- fn php_module_startup( ) { }
35- } )
36- . map_err ( |_| anyhow ! ( "Unable to generate PHP module startup function." ) ) ?;
37- let startup = startup_function:: parser ( None , parsed) ?;
3825
39- state = STATE . lock ( ) ;
40- Some ( startup)
41- } else {
42- None
43- } ;
44-
45- let functions = state
46- . functions
26+ let functions = functions
4727 . iter ( )
4828 . map ( |func| func. get_builder ( ) )
4929 . collect :: < Vec < _ > > ( ) ;
50- let startup = state . startup_function . as_ref ( ) . map ( |ident| {
30+ let startup = startup_function_name . as_ref ( ) . map ( |ident| {
5131 let ident = Ident :: new ( ident, Span :: call_site ( ) ) ;
5232 quote ! {
5333 . startup_function( #ident)
5434 }
5535 } ) ;
56- let registered_classes_impls = state
57- . classes
58- . values ( )
36+ let registered_classes_impls = classes
5937 . map ( generate_registered_class_impl)
6038 . collect :: < Result < Vec < _ > > > ( ) ?;
61- let describe_fn = generate_stubs ( & state ) ;
39+ let describe_fn = generate_stubs ( describe ) ;
6240
63- let result = quote ! {
41+ Ok ( quote ! {
6442 #( #registered_classes_impls) *
6543
6644 #startup_fn
@@ -90,8 +68,46 @@ pub fn parser(input: ItemFn) -> Result<TokenStream> {
9068 }
9169
9270 #describe_fn
71+ } )
72+ }
73+
74+ fn prepare_startup ( ) -> Result < TokenStream > {
75+ let parsed = syn:: parse2 ( quote ! {
76+ fn php_module_startup( ) { }
77+ } )
78+ . map_err ( |_| anyhow ! ( "Unable to generate PHP module startup function." ) ) ?;
79+ startup_function:: parser ( None , parsed)
80+ }
81+
82+ pub fn parser ( input : ItemFn ) -> Result < TokenStream > {
83+ let mut state = STATE . lock ( ) ;
84+
85+ if state. built_module {
86+ bail ! ( "You may only define a module with the `#[php_module]` attribute once." ) ;
87+ }
88+
89+ state. built_module = true ;
90+
91+ // Generate startup function if one hasn't already been tagged with the macro.
92+ let startup_fn = if ( !state. classes . is_empty ( ) || !state. constants . is_empty ( ) )
93+ && state. startup_function . is_none ( )
94+ {
95+ drop ( state) ;
96+ let prepared = prepare_startup ( ) ?;
97+ state = STATE . lock ( ) ;
98+ Some ( prepared)
99+ } else {
100+ None
93101 } ;
94- Ok ( result)
102+
103+ prepare (
104+ input,
105+ & state. functions ,
106+ startup_fn. as_ref ( ) ,
107+ state. startup_function . as_deref ( ) ,
108+ state. classes . values ( ) ,
109+ & state. describe ( ) ,
110+ )
95111}
96112
97113/// Generates an implementation for `RegisteredClass` on the given class.
@@ -151,9 +167,7 @@ pub trait Describe {
151167 fn describe ( & self ) -> TokenStream ;
152168}
153169
154- fn generate_stubs ( state : & MutexGuard < State > ) -> TokenStream {
155- let module = state. describe ( ) ;
156-
170+ fn generate_stubs ( module : & TokenStream ) -> TokenStream {
157171 quote ! {
158172 #[ cfg( debug_assertions) ]
159173 #[ no_mangle]
0 commit comments