1
+ use std:: collections:: { HashMap , HashSet } ;
2
+
3
+ use darling:: util:: Flag ;
1
4
use darling:: { FromAttributes } ;
2
5
use proc_macro2:: TokenStream ;
3
6
use quote:: { format_ident, quote} ;
4
- use syn:: { ItemTrait , TraitItem , TraitItemFn } ;
5
- use crate :: helpers:: CleanPhpAttr ;
7
+ use syn:: { Expr , Ident , ItemTrait , Path , TraitItem , TraitItemConst , TraitItemFn } ;
8
+ use crate :: class:: ClassEntryAttribute ;
9
+ use crate :: constant:: PhpConstAttribute ;
10
+ use crate :: function:: { Args , Function } ;
11
+ use crate :: helpers:: { get_docs, CleanPhpAttr } ;
6
12
7
- use crate :: parsing:: { PhpRename , RenameRule } ;
13
+ use crate :: impl_:: { Constant , FnBuilder , MethodModifier } ;
14
+ use crate :: parsing:: { PhpRename , RenameRule , Visibility } ;
8
15
use crate :: prelude:: * ;
9
16
10
17
#[ derive( FromAttributes , Debug , Default ) ]
11
18
#[ darling( attributes( php) , forward_attrs( doc) , default ) ]
12
19
pub struct StructAttributes {
13
20
#[ darling( flatten) ]
14
21
rename : PhpRename ,
22
+ #[ darling( multiple) ]
23
+ extends : Vec < ClassEntryAttribute > ,
15
24
}
16
25
17
26
pub fn parser ( mut input : ItemTrait ) -> Result < TokenStream > {
18
27
let attr = StructAttributes :: from_attributes ( & input. attrs ) ?;
19
28
let ident = & input. ident ;
20
29
21
30
let interface_name = format_ident ! ( "PhpInterface{ident}" ) ;
31
+ let ts = quote ! { #interface_name } ;
32
+ let path: Path = syn:: parse2 ( ts) ?;
33
+
22
34
let name = attr. rename . rename ( ident. to_string ( ) , RenameRule :: Pascal ) ;
23
35
input. attrs . clean_php ( ) ;
24
36
25
- let mut interface_methods : Vec < TraitItemFn > = Vec :: new ( ) ;
26
- for i in input . items . clone ( ) . into_iter ( ) {
27
- match i {
28
- TraitItem :: Fn ( f ) => {
29
- if f . default . is_some ( ) {
30
- bail ! ( "Interface could not have default impl" ) ;
37
+ let methods : Vec < FnBuilder > = input . items . iter_mut ( )
38
+ . flat_map (
39
+ | item : & mut TraitItem | {
40
+ match item {
41
+ TraitItem :: Fn ( f ) => Some ( f ) ,
42
+ _ => None ,
31
43
}
32
- interface_methods. push ( f) ;
44
+ } )
45
+ . flat_map ( |f| f. parse ( ) )
46
+ . collect ( ) ;
47
+
48
+ let constants: Vec < _ > = input. items . iter_mut ( )
49
+ . flat_map ( |item : & mut TraitItem | {
50
+ match item {
51
+ TraitItem :: Const ( c) => Some ( c) ,
52
+ _ => None ,
33
53
}
34
- _ => { }
54
+ } )
55
+ . flat_map ( |c| c. parse ( ) )
56
+ . map ( |c| {
57
+ let name = & c. name ;
58
+ let ident = c. ident ;
59
+ let docs = & c. docs ;
60
+ quote ! {
61
+ ( #name, & #path:: #ident, & [ #( #docs) , * ] )
62
+ }
63
+ } )
64
+ . collect ( ) ;
65
+
66
+ let impl_const: Vec < & TraitItemConst > = input. items . iter ( ) . flat_map ( |item| {
67
+ match item {
68
+ TraitItem :: Const ( c) => Some ( c) ,
69
+ _ => None ,
35
70
}
36
- } ;
71
+ } )
72
+ . map ( |c| {
73
+ if c. default . is_none ( ) {
74
+ bail ! ( "Interface const canot be empty" ) ;
75
+ }
76
+ Ok ( c)
77
+ } )
78
+ . flat_map ( |c| c)
79
+ . collect ( ) ;
80
+
81
+ let implements = attr. extends ;
37
82
38
83
Ok ( quote ! {
39
84
#input
40
85
41
86
pub struct #interface_name;
42
87
88
+ impl #interface_name {
89
+ #( pub #impl_const) *
90
+ }
91
+
43
92
impl :: ext_php_rs:: class:: RegisteredClass for #interface_name {
44
93
const CLASS_NAME : & ' static str = #name;
45
94
@@ -51,7 +100,9 @@ pub fn parser(mut input: ItemTrait) -> Result<TokenStream> {
51
100
52
101
const FLAGS : :: ext_php_rs:: flags:: ClassFlags = :: ext_php_rs:: flags:: ClassFlags :: Interface ;
53
102
54
- const IMPLEMENTS : & ' static [ :: ext_php_rs:: class:: ClassEntryInfo ] = & [ ] ;
103
+ const IMPLEMENTS : & ' static [ :: ext_php_rs:: class:: ClassEntryInfo ] = & [
104
+ #( #implements, ) *
105
+ ] ;
55
106
56
107
fn get_metadata( ) -> & ' static :: ext_php_rs:: class:: ClassMetadata <Self > {
57
108
static METADATA : :: ext_php_rs:: class:: ClassMetadata <#interface_name> =
@@ -64,7 +115,7 @@ pub fn parser(mut input: ItemTrait) -> Result<TokenStream> {
64
115
:: ext_php_rs:: builders:: FunctionBuilder <' static >,
65
116
:: ext_php_rs:: flags:: MethodFlags ,
66
117
) > {
67
- vec![ ]
118
+ vec![ # ( #methods ) , * ]
68
119
}
69
120
70
121
fn constructor( ) -> Option <:: ext_php_rs:: class:: ConstructorMeta <Self >> {
@@ -76,14 +127,37 @@ pub fn parser(mut input: ItemTrait) -> Result<TokenStream> {
76
127
& ' static dyn ext_php_rs:: convert:: IntoZvalDyn ,
77
128
ext_php_rs:: describe:: DocComments ,
78
129
) ] {
79
- & [ ]
130
+ use :: ext_php_rs:: internal:: class:: PhpClassImpl ;
131
+ :: ext_php_rs:: internal:: class:: PhpClassImplCollector :: <Self >:: default ( ) . get_constants( )
80
132
}
81
133
82
134
fn get_properties<' a>( ) -> std:: collections:: HashMap <& ' static str , :: ext_php_rs:: internal:: property:: PropertyInfo <' a, Self >> {
83
135
HashMap :: new( )
84
136
}
85
137
86
138
}
139
+ impl :: ext_php_rs:: internal:: class:: PhpClassImpl <#path>
140
+ for :: ext_php_rs:: internal:: class:: PhpClassImplCollector <#path>
141
+ {
142
+ fn get_methods( self ) -> :: std:: vec:: Vec <
143
+ ( :: ext_php_rs:: builders:: FunctionBuilder <' static >, :: ext_php_rs:: flags:: MethodFlags )
144
+ > {
145
+ vec![ ]
146
+ }
147
+
148
+ fn get_method_props<' a>( self ) -> :: std:: collections:: HashMap <& ' static str , :: ext_php_rs:: props:: Property <' a, #path>> {
149
+ todo!( )
150
+ }
151
+
152
+ fn get_constructor( self ) -> :: std:: option:: Option <:: ext_php_rs:: class:: ConstructorMeta <#path>> {
153
+ None
154
+ }
155
+
156
+ fn get_constants( self ) -> & ' static [ ( & ' static str , & ' static dyn :: ext_php_rs:: convert:: IntoZvalDyn , & ' static [ & ' static str ] ) ] {
157
+ & [ #( #constants) , * ]
158
+ }
159
+ }
160
+
87
161
88
162
impl <' a> :: ext_php_rs:: convert:: FromZendObject <' a> for & ' a #interface_name {
89
163
#[ inline]
@@ -150,3 +224,75 @@ pub fn parser(mut input: ItemTrait) -> Result<TokenStream> {
150
224
}
151
225
} )
152
226
}
227
+
228
+ #[ derive( FromAttributes , Default , Debug ) ]
229
+ #[ darling( default , attributes( php) , forward_attrs( doc) ) ]
230
+ pub struct PhpFunctionInterfaceAttribute {
231
+ #[ darling( flatten) ]
232
+ rename : PhpRename ,
233
+ defaults : HashMap < Ident , Expr > ,
234
+ optional : Option < Ident > ,
235
+ vis : Option < Visibility > ,
236
+ attrs : Vec < syn:: Attribute > ,
237
+ getter : Flag ,
238
+ setter : Flag ,
239
+ constructor : Flag ,
240
+ }
241
+
242
+ trait Parse < ' a , T > {
243
+ fn parse ( & ' a mut self ) -> Result < T > ;
244
+ }
245
+
246
+ impl < ' a > Parse < ' a , Constant < ' a > > for TraitItemConst {
247
+ fn parse ( & ' a mut self ) -> Result < Constant < ' a > > {
248
+ let attr = PhpConstAttribute :: from_attributes ( & self . attrs ) ?;
249
+ let name = self . ident . to_string ( ) ;
250
+ let docs = get_docs ( & attr. attrs ) ?;
251
+ self . attrs . clean_php ( ) ;
252
+
253
+ Ok ( Constant :: new ( name, & self . ident , docs) )
254
+ }
255
+ }
256
+
257
+ impl < ' a > Parse < ' a , FnBuilder > for TraitItemFn {
258
+ fn parse ( & ' a mut self ) -> Result < FnBuilder > {
259
+ let php_attr = PhpFunctionInterfaceAttribute :: from_attributes (
260
+ & self . attrs
261
+ ) ?;
262
+ if self . default . is_some ( ) {
263
+ bail ! ( "Interface could not have default impl" ) ;
264
+ }
265
+
266
+ let mut args = Args :: parse_from_fnargs (
267
+ self . sig . inputs . iter ( ) ,
268
+ php_attr. defaults
269
+ ) ?;
270
+ let docs = get_docs ( & php_attr. attrs ) ?;
271
+
272
+ self . attrs . clean_php ( ) ;
273
+
274
+ let mut modifiers: HashSet < MethodModifier > = HashSet :: new ( ) ;
275
+ modifiers. insert ( MethodModifier :: Abstract ) ;
276
+ if args. typed . first ( ) . is_some_and ( |arg| arg. name == "self_" ) {
277
+ args. typed . pop ( ) ;
278
+ } else if args. receiver . is_none ( ) {
279
+ modifiers. insert ( MethodModifier :: Static ) ;
280
+ } ;
281
+
282
+ let f = Function :: new (
283
+ & self . sig ,
284
+ php_attr
285
+ . rename
286
+ . rename ( self . sig . ident . to_string ( ) , RenameRule :: Camel ) ,
287
+ args,
288
+ php_attr. optional ,
289
+ docs,
290
+ ) ;
291
+
292
+ Ok ( FnBuilder {
293
+ builder : f. abstract_function_builder ( ) ,
294
+ vis : php_attr. vis . unwrap_or ( Visibility :: Public ) ,
295
+ modifiers,
296
+ } )
297
+ }
298
+ }
0 commit comments