@@ -249,7 +249,7 @@ fn impl_from_args(input: DeriveInput) -> TokenStream2 {
249
249
}
250
250
251
251
#[ proc_macro_attribute]
252
- pub fn py_class ( attr : TokenStream , item : TokenStream ) -> TokenStream {
252
+ pub fn pyclass ( attr : TokenStream , item : TokenStream ) -> TokenStream {
253
253
let attr = parse_macro_input ! ( attr as AttributeArgs ) ;
254
254
let item = parse_macro_input ! ( item as Item ) ;
255
255
impl_py_class ( attr, item) . into ( )
@@ -276,50 +276,65 @@ struct Method {
276
276
kind : MethodKind ,
277
277
}
278
278
279
- fn item_impl_to_methods < ' a > ( imp : & ' a syn:: ItemImpl ) -> impl Iterator < Item = Method > + ' a {
280
- imp. items . iter ( ) . filter_map ( |item| {
279
+ /// Parse an impl block into an iterator of methods
280
+ fn item_impl_to_methods < ' a > ( imp : & ' a mut syn:: ItemImpl ) -> impl Iterator < Item = Method > + ' a {
281
+ imp. items . iter_mut ( ) . filter_map ( |item| {
281
282
if let ImplItem :: Method ( meth) = item {
282
283
let mut py_name = None ;
283
284
let mut kind = MethodKind :: Method ;
284
- let metas_iter = meth
285
+ let mut pymethod_to_remove = Vec :: new ( ) ;
286
+ let metas = meth
285
287
. attrs
286
288
. iter ( )
287
- . filter_map ( |attr| {
288
- if attr. path . is_ident ( "py_class" ) {
289
+ . enumerate ( )
290
+ . filter_map ( |( i, attr) | {
291
+ if attr. path . is_ident ( "pymethod" ) {
289
292
let meta = attr. parse_meta ( ) . expect ( "Invalid attribute" ) ;
290
- if let Meta :: List ( list) = meta {
291
- Some ( list)
292
- } else {
293
- panic ! (
294
- "#[py_class] attribute on a method should be a list, like \
295
- #[py_class(...)]"
296
- )
293
+ // remove #[pymethod] because there's no actual proc macro
294
+ // implementation for it
295
+ pymethod_to_remove. push ( i) ;
296
+ match meta {
297
+ Meta :: List ( list) => Some ( list) ,
298
+ Meta :: Word ( _) => None ,
299
+ Meta :: NameValue ( _) => panic ! (
300
+ "#[pymethod = ...] attribute on a method should be a list, like \
301
+ #[pymethod(...)]"
302
+ ) ,
297
303
}
298
304
} else {
299
305
None
300
306
}
301
307
} )
302
308
. flat_map ( |attr| attr. nested ) ;
303
- for meta in metas_iter {
309
+ for meta in metas {
304
310
if let NestedMeta :: Meta ( meta) = meta {
305
311
match meta {
306
312
Meta :: NameValue ( name_value) => {
307
313
if name_value. ident == "name" {
308
314
if let Lit :: Str ( s) = & name_value. lit {
309
315
py_name = Some ( s. value ( ) ) ;
310
316
} else {
311
- panic ! ( "#[py_class (name = ...)] must be a string" ) ;
317
+ panic ! ( "#[pymethod (name = ...)] must be a string" ) ;
312
318
}
313
319
}
314
320
}
315
- Meta :: Word ( ident) => match ident. to_string ( ) . as_str ( ) {
316
- "property" => kind = MethodKind :: Property ,
317
- _ => { }
318
- } ,
321
+ Meta :: Word ( ident) => {
322
+ if ident == "property" {
323
+ kind = MethodKind :: Property
324
+ }
325
+ }
319
326
_ => { }
320
327
}
321
328
}
322
329
}
330
+ // if there are no #[pymethods]s, then it's not a method, so exclude it from
331
+ // the final result
332
+ if pymethod_to_remove. is_empty ( ) {
333
+ return None ;
334
+ }
335
+ for i in pymethod_to_remove {
336
+ meth. attrs . remove ( i) ;
337
+ }
323
338
let py_name = py_name. unwrap_or_else ( || meth. sig . ident . to_string ( ) ) ;
324
339
Some ( Method {
325
340
fn_name : meth. sig . ident . clone ( ) ,
@@ -333,7 +348,7 @@ fn item_impl_to_methods<'a>(imp: &'a syn::ItemImpl) -> impl Iterator<Item = Meth
333
348
}
334
349
335
350
fn impl_py_class ( attr : AttributeArgs , item : Item ) -> TokenStream2 {
336
- let imp = if let Item :: Impl ( imp) = item {
351
+ let mut imp = if let Item :: Impl ( imp) = item {
337
352
imp
338
353
} else {
339
354
return quote ! ( #item) ;
@@ -347,13 +362,13 @@ fn impl_py_class(attr: AttributeArgs, item: Item) -> TokenStream2 {
347
362
if let Lit :: Str ( s) = name_value. lit {
348
363
class_name = Some ( s. value ( ) ) ;
349
364
} else {
350
- panic ! ( "#[py_class (name = ...)] must be a string" ) ;
365
+ panic ! ( "#[pyclass (name = ...)] must be a string" ) ;
351
366
}
352
367
}
353
368
}
354
369
}
355
370
}
356
- let class_name = class_name. expect ( "#[py_class ] must have a name" ) ;
371
+ let class_name = class_name. expect ( "#[pyclass ] must have a name" ) ;
357
372
let mut doc: Option < Vec < String > > = None ;
358
373
for attr in imp. attrs . iter ( ) {
359
374
if attr. path . is_ident ( "doc" ) {
@@ -380,8 +395,9 @@ fn impl_py_class(attr: AttributeArgs, item: Item) -> TokenStream2 {
380
395
}
381
396
None => quote ! ( None ) ,
382
397
} ;
398
+ let methods: Vec < _ > = item_impl_to_methods ( & mut imp) . collect ( ) ;
383
399
let ty = & imp. self_ty ;
384
- let methods = item_impl_to_methods ( & imp ) . map (
400
+ let methods = methods . iter ( ) . map (
385
401
|Method {
386
402
py_name,
387
403
fn_name,
0 commit comments