Skip to content

Commit 8b84db4

Browse files
committed
feat: Define constructor
1 parent 8dbac98 commit 8b84db4

File tree

1 file changed

+64
-21
lines changed

1 file changed

+64
-21
lines changed

crates/macros/src/interface.rs

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct InterfaceData<'a> {
4343
name: String,
4444
path: Path,
4545
attrs: StructAttributes,
46+
constructor: Option<Function<'a>>,
4647
methods: Vec<FnBuilder>,
4748
constants: Vec<Constant<'a>>,
4849
}
@@ -55,6 +56,12 @@ impl ToTokens for InterfaceData<'_> {
5556
let methods_sig = &self.methods;
5657
let path = &self.path;
5758
let constants = &self.constants;
59+
60+
let constructor = self.constructor
61+
.as_ref()
62+
.map(|func| func.constructor_meta(&path))
63+
.option_tokens();
64+
5865
quote! {
5966
pub struct #interface_name;
6067

@@ -88,8 +95,7 @@ impl ToTokens for InterfaceData<'_> {
8895
}
8996

9097
fn constructor() -> Option<::ext_php_rs::class::ConstructorMeta<Self>> {
91-
use ::ext_php_rs::internal::class::PhpClassImpl;
92-
::ext_php_rs::internal::class::PhpClassImplCollector::<Self>::default().get_constructor()
98+
None
9399
}
94100

95101
fn constants() -> &'static [(
@@ -178,6 +184,7 @@ impl<'a> InterfaceData<'a> {
178184
name: String,
179185
path: Path,
180186
attrs: StructAttributes,
187+
constructor: Option<Function<'a>>,
181188
methods: Vec<FnBuilder>,
182189
constants: Vec<Constant<'a>>,
183190
) -> Self {
@@ -186,6 +193,7 @@ impl<'a> InterfaceData<'a> {
186193
name,
187194
path,
188195
attrs,
196+
constructor,
189197
methods,
190198
constants,
191199
}
@@ -201,11 +209,28 @@ impl<'a> Parse<'a, InterfaceData<'a>> for ItemTrait {
201209
let interface_name = format_ident!("PhpInterface{ident}");
202210
let ts = quote! { #interface_name };
203211
let path: Path = syn::parse2(ts)?;
204-
let mut data = InterfaceData::new(ident, name, path, attrs, Vec::new(), Vec::new());
212+
let mut data = InterfaceData::new(
213+
ident,
214+
name,
215+
path,
216+
attrs,
217+
None,
218+
Vec::new(),
219+
Vec::new()
220+
);
205221

206222
for item in &mut self.items {
207223
match item {
208-
TraitItem::Fn(f) => data.methods.push(f.parse()?),
224+
TraitItem::Fn(f) => {
225+
match f.parse()? {
226+
MethodKind::Method(builder) => data.methods.push(builder),
227+
MethodKind::Constructor(builder) => {
228+
if data.constructor.replace(builder).is_some() {
229+
bail!("Only one constructor can be provided per class.");
230+
}
231+
}
232+
};
233+
},
209234
TraitItem::Const(c) => data.constants.push(c.parse()?),
210235
_ => {}
211236
}
@@ -229,20 +254,32 @@ pub struct PhpFunctionInterfaceAttribute {
229254
constructor: Flag,
230255
}
231256

232-
impl<'a> Parse<'a, FnBuilder> for TraitItemFn {
233-
fn parse(&'a mut self) -> Result<FnBuilder> {
234-
let php_attr = PhpFunctionInterfaceAttribute::from_attributes(&self.attrs)?;
257+
enum MethodKind<'a> {
258+
Method(FnBuilder),
259+
Constructor(Function<'a>),
260+
}
261+
262+
impl<'a> Parse<'a, MethodKind<'a>> for TraitItemFn {
263+
fn parse(&'a mut self) -> Result<MethodKind<'a>> {
235264
if self.default.is_some() {
236-
bail!("Interface could not have default impl");
265+
bail!(self => "Interface could not have default impl");
237266
}
238267

239-
let mut args = Args::parse_from_fnargs(self.sig.inputs.iter(), php_attr.defaults)?;
240-
let docs = get_docs(&php_attr.attrs)?;
241-
268+
let php_attr = PhpFunctionInterfaceAttribute::from_attributes(
269+
&self.attrs
270+
)?;
242271
self.attrs.clean_php();
243272

273+
let mut args = Args::parse_from_fnargs(
274+
self.sig.inputs.iter(),
275+
php_attr.defaults
276+
)?;
277+
278+
let docs = get_docs(&php_attr.attrs)?;
279+
244280
let mut modifiers: HashSet<MethodModifier> = HashSet::new();
245281
modifiers.insert(MethodModifier::Abstract);
282+
246283
if args.typed.first().is_some_and(|arg| arg.name == "self_") {
247284
args.typed.pop();
248285
} else if args.receiver.is_none() {
@@ -259,20 +296,26 @@ impl<'a> Parse<'a, FnBuilder> for TraitItemFn {
259296
docs,
260297
);
261298

262-
Ok(FnBuilder {
263-
builder: f.abstract_function_builder(),
264-
vis: php_attr.vis.unwrap_or(Visibility::Public),
265-
modifiers,
266-
})
299+
if php_attr.constructor.is_present() {
300+
Ok(MethodKind::Constructor(f))
301+
} else {
302+
let builder = FnBuilder {
303+
builder: f.abstract_function_builder(),
304+
vis: php_attr.vis.unwrap_or(Visibility::Public),
305+
modifiers,
306+
};
307+
308+
Ok(MethodKind::Method(builder))
309+
}
267310
}
268311
}
269312

270-
impl<'a> Parse<'a, Vec<FnBuilder>> for ItemTrait {
271-
fn parse(&'a mut self) -> Result<Vec<FnBuilder>> {
313+
impl<'a> Parse<'a, Vec<MethodKind<'a>>> for ItemTrait {
314+
fn parse(&'a mut self) -> Result<Vec<MethodKind<'a>>> {
272315
Ok(self
273316
.items
274317
.iter_mut()
275-
.filter_map(|item: &mut TraitItem| match item {
318+
.filter_map(|item| match item {
276319
TraitItem::Fn(f) => Some(f),
277320
_ => None,
278321
})
@@ -309,7 +352,7 @@ impl<'a> Constant<'a> {
309352
impl<'a> Parse<'a, Constant<'a>> for TraitItemConst {
310353
fn parse(&'a mut self) -> Result<Constant<'a>> {
311354
if self.default.is_none() {
312-
bail!("Interface const could not be empty");
355+
bail!(self => "Interface const could not be empty");
313356
}
314357

315358
let attr = PhpConstAttribute::from_attributes(&self.attrs)?;
@@ -327,7 +370,7 @@ impl<'a> Parse<'a, Vec<Constant<'a>>> for ItemTrait {
327370
Ok(self
328371
.items
329372
.iter_mut()
330-
.filter_map(|item: &mut TraitItem| match item {
373+
.filter_map(|item| match item {
331374
TraitItem::Const(c) => Some(c),
332375
_ => None,
333376
})

0 commit comments

Comments
 (0)