Skip to content

Commit f1ba271

Browse files
committed
A tricky refactor to pull out state.
It turns out the dropping and relocking state in the right order is essential for the test suite to even complete...
1 parent ec5735a commit f1ba271

File tree

1 file changed

+53
-39
lines changed

1 file changed

+53
-39
lines changed

crates/macros/src/module.rs

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::sync::MutexGuard;
2-
31
use anyhow::{anyhow, bail, Result};
42
use proc_macro2::{Ident, Span, TokenStream};
53
use 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

Comments
 (0)