@@ -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> {
309352impl < ' 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