@@ -14,11 +14,17 @@ use crate::impl_::{FnBuilder, MethodModifier};
1414use crate :: parsing:: { PhpRename , RenameRule , Visibility } ;
1515use crate :: prelude:: * ;
1616
17+ const INTERNAL_INTERFACE_NAME_PREFIX : & str = "PhpInterface" ;
18+
1719#[ derive( FromAttributes , Debug , Default ) ]
1820#[ darling( attributes( php) , forward_attrs( doc) , default ) ]
19- pub struct StructAttributes {
21+ pub struct TraitAttributes {
2022 #[ darling( flatten) ]
2123 rename : PhpRename ,
24+ /// Rename methods to match the given rule.
25+ change_method_case : Option < RenameRule > ,
26+ /// Rename constants to match the given rule.
27+ change_constant_case : Option < RenameRule > ,
2228 #[ darling( multiple) ]
2329 extends : Vec < ClassEntryAttribute > ,
2430 attrs : Vec < syn:: Attribute > ,
@@ -43,7 +49,7 @@ struct InterfaceData<'a> {
4349 ident : & ' a Ident ,
4450 name : String ,
4551 path : Path ,
46- attrs : StructAttributes ,
52+ extends : Vec < ClassEntryAttribute > ,
4753 constructor : Option < Function < ' a > > ,
4854 methods : Vec < FnBuilder > ,
4955 constants : Vec < Constant < ' a > > ,
@@ -53,9 +59,9 @@ struct InterfaceData<'a> {
5359impl ToTokens for InterfaceData < ' _ > {
5460 #[ allow( clippy:: too_many_lines) ]
5561 fn to_tokens ( & self , tokens : & mut TokenStream ) {
56- let interface_name = format_ident ! ( "PhpInterface {}" , self . ident) ;
62+ let interface_name = format_ident ! ( "{INTERNAL_INTERFACE_NAME_PREFIX} {}" , self . ident) ;
5763 let name = & self . name ;
58- let implements = & self . attrs . extends ;
64+ let implements = & self . extends ;
5965 let methods_sig = & self . methods ;
6066 let constants = & self . constants ;
6167 let docs = & self . docs ;
@@ -188,19 +194,19 @@ impl ToTokens for InterfaceData<'_> {
188194
189195impl < ' a > Parse < ' a , InterfaceData < ' a > > for ItemTrait {
190196 fn parse ( & ' a mut self ) -> Result < InterfaceData < ' a > > {
191- let attrs = StructAttributes :: from_attributes ( & self . attrs ) ?;
197+ let attrs = TraitAttributes :: from_attributes ( & self . attrs ) ?;
192198 let ident = & self . ident ;
193199 let name = attrs. rename . rename ( ident. to_string ( ) , RenameRule :: Pascal ) ;
194200 let docs = get_docs ( & attrs. attrs ) ?;
195201 self . attrs . clean_php ( ) ;
196- let interface_name = format_ident ! ( "PhpInterface {ident}" ) ;
202+ let interface_name = format_ident ! ( "{INTERNAL_INTERFACE_NAME_PREFIX} {ident}" ) ;
197203 let ts = quote ! { #interface_name } ;
198204 let path: Path = syn:: parse2 ( ts) ?;
199205 let mut data = InterfaceData {
200206 ident,
201207 name,
202208 path,
203- attrs,
209+ extends : attrs. extends ,
204210 constructor : None ,
205211 methods : Vec :: default ( ) ,
206212 constants : Vec :: default ( ) ,
@@ -210,7 +216,7 @@ impl<'a> Parse<'a, InterfaceData<'a>> for ItemTrait {
210216 for item in & mut self . items {
211217 match item {
212218 TraitItem :: Fn ( f) => {
213- match f . parse ( ) ? {
219+ match parse_trait_item_fn ( f , attrs . change_method_case ) ? {
214220 MethodKind :: Method ( builder) => data. methods . push ( builder) ,
215221 MethodKind :: Constructor ( builder) => {
216222 if data. constructor . replace ( builder) . is_some ( ) {
@@ -219,7 +225,9 @@ impl<'a> Parse<'a, InterfaceData<'a>> for ItemTrait {
219225 }
220226 } ;
221227 }
222- TraitItem :: Const ( c) => data. constants . push ( c. parse ( ) ?) ,
228+ TraitItem :: Const ( c) => data
229+ . constants
230+ . push ( parse_trait_item_const ( c, attrs. change_constant_case ) ?) ,
223231 _ => { }
224232 }
225233 }
@@ -247,63 +255,51 @@ enum MethodKind<'a> {
247255 Constructor ( Function < ' a > ) ,
248256}
249257
250- impl < ' a > Parse < ' a , MethodKind < ' a > > for TraitItemFn {
251- fn parse ( & ' a mut self ) -> Result < MethodKind < ' a > > {
252- if self . default . is_some ( ) {
253- bail ! ( self => "Interface could not have default impl" ) ;
254- }
255-
256- let php_attr = PhpFunctionInterfaceAttribute :: from_attributes ( & self . attrs ) ?;
257- self . attrs . clean_php ( ) ;
258+ fn parse_trait_item_fn (
259+ fn_item : & mut TraitItemFn ,
260+ change_case : Option < RenameRule > ,
261+ ) -> Result < MethodKind < ' _ > > {
262+ if fn_item. default . is_some ( ) {
263+ bail ! ( fn_item => "Interface an not have default impl" ) ;
264+ }
258265
259- let mut args = Args :: parse_from_fnargs ( self . sig . inputs . iter ( ) , php_attr. defaults ) ?;
266+ let php_attr = PhpFunctionInterfaceAttribute :: from_attributes ( & fn_item. attrs ) ?;
267+ fn_item. attrs . clean_php ( ) ;
260268
261- let docs = get_docs ( & php_attr. attrs ) ?;
269+ let mut args = Args :: parse_from_fnargs ( fn_item . sig . inputs . iter ( ) , php_attr. defaults ) ?;
262270
263- let mut modifiers: HashSet < MethodModifier > = HashSet :: new ( ) ;
264- modifiers. insert ( MethodModifier :: Abstract ) ;
271+ let docs = get_docs ( & php_attr. attrs ) ?;
265272
266- if args. typed . first ( ) . is_some_and ( |arg| arg. name == "self_" ) {
267- args. typed . pop ( ) ;
268- } else if args. receiver . is_none ( ) {
269- modifiers. insert ( MethodModifier :: Static ) ;
270- }
273+ let mut modifiers: HashSet < MethodModifier > = HashSet :: new ( ) ;
274+ modifiers. insert ( MethodModifier :: Abstract ) ;
271275
272- let f = Function :: new (
273- & self . sig ,
274- php_attr
275- . rename
276- . rename ( self . sig . ident . to_string ( ) , RenameRule :: Camel ) ,
277- args,
278- php_attr. optional ,
279- docs,
280- ) ;
281-
282- if php_attr. constructor . is_present ( ) {
283- Ok ( MethodKind :: Constructor ( f) )
284- } else {
285- let builder = FnBuilder {
286- builder : f. abstract_function_builder ( ) ,
287- vis : php_attr. vis . unwrap_or ( Visibility :: Public ) ,
288- modifiers,
289- } ;
290-
291- Ok ( MethodKind :: Method ( builder) )
292- }
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 ) ;
293280 }
294- }
295281
296- impl < ' a > Parse < ' a , Vec < MethodKind < ' a > > > for ItemTrait {
297- fn parse ( & ' a mut self ) -> Result < Vec < MethodKind < ' a > > > {
298- Ok ( self
299- . items
300- . iter_mut ( )
301- . filter_map ( |item| match item {
302- TraitItem :: Fn ( f) => Some ( f) ,
303- _ => None ,
304- } )
305- . flat_map ( Parse :: parse)
306- . collect ( ) )
282+ let f = Function :: new (
283+ & fn_item. sig ,
284+ php_attr. rename . rename (
285+ fn_item. sig . ident . to_string ( ) ,
286+ change_case. unwrap_or ( RenameRule :: Camel ) ,
287+ ) ,
288+ args,
289+ php_attr. optional ,
290+ docs,
291+ ) ;
292+
293+ if php_attr. constructor . is_present ( ) {
294+ Ok ( MethodKind :: Constructor ( f) )
295+ } else {
296+ let builder = FnBuilder {
297+ builder : f. abstract_function_builder ( ) ,
298+ vis : php_attr. vis . unwrap_or ( Visibility :: Public ) ,
299+ modifiers,
300+ } ;
301+
302+ Ok ( MethodKind :: Method ( builder) )
307303 }
308304}
309305
@@ -332,32 +328,22 @@ impl<'a> Constant<'a> {
332328 }
333329}
334330
335- impl < ' a > Parse < ' a , Constant < ' a > > for TraitItemConst {
336- fn parse ( & ' a mut self ) -> Result < Constant < ' a > > {
337- if self . default . is_none ( ) {
338- bail ! ( self => "Interface const could not be empty" ) ;
339- }
340-
341- let attr = PhpConstAttribute :: from_attributes ( & self . attrs ) ?;
342- let name = self . ident . to_string ( ) ;
343- let docs = get_docs ( & attr. attrs ) ?;
344- self . attrs . clean_php ( ) ;
345-
346- let ( _, expr) = self . default . as_ref ( ) . unwrap ( ) ;
347- Ok ( Constant :: new ( name, expr, docs) )
331+ fn parse_trait_item_const (
332+ const_item : & mut TraitItemConst ,
333+ change_case : Option < RenameRule > ,
334+ ) -> Result < Constant < ' _ > > {
335+ if const_item. default . is_none ( ) {
336+ bail ! ( const_item => "PHP Interface const can not be empty" ) ;
348337 }
349- }
350338
351- impl < ' a > Parse < ' a , Vec < Constant < ' a > > > for ItemTrait {
352- fn parse ( & ' a mut self ) -> Result < Vec < Constant < ' a > > > {
353- Ok ( self
354- . items
355- . iter_mut ( )
356- . filter_map ( |item| match item {
357- TraitItem :: Const ( c) => Some ( c) ,
358- _ => None ,
359- } )
360- . flat_map ( Parse :: parse)
361- . collect ( ) )
362- }
339+ let attr = PhpConstAttribute :: from_attributes ( & const_item. attrs ) ?;
340+ let name = attr. rename . rename (
341+ const_item. ident . to_string ( ) ,
342+ change_case. unwrap_or ( RenameRule :: ScreamingSnake ) ,
343+ ) ;
344+ let docs = get_docs ( & attr. attrs ) ?;
345+ const_item. attrs . clean_php ( ) ;
346+
347+ let ( _, expr) = const_item. default . as_ref ( ) . unwrap ( ) ;
348+ Ok ( Constant :: new ( name, expr, docs) )
363349}
0 commit comments