11use super :: Diagnostic ;
22use crate :: util:: {
33 path_eq, pyclass_ident_and_attrs, ClassItemMeta , ContentItem , ContentItemInner , ErrorVec ,
4- ItemMeta , ItemMetaInner , ItemNursery , ALL_ALLOWED_NAMES ,
4+ ItemMeta , ItemMetaInner , ItemNursery , SimpleItemMeta , ALL_ALLOWED_NAMES ,
55} ;
66use proc_macro2:: TokenStream ;
77use quote:: { quote, quote_spanned, ToTokens } ;
@@ -216,6 +216,11 @@ struct SlotItem {
216216 inner : ContentItemInner ,
217217}
218218
219+ /// #[pyattr]
220+ struct AttributeItem {
221+ inner : ContentItemInner ,
222+ }
223+
219224/// #[extend_class]
220225struct ExtendClassItem {
221226 inner : ContentItemInner ,
@@ -236,6 +241,11 @@ impl ContentItem for SlotItem {
236241 & self . inner
237242 }
238243}
244+ impl ContentItem for AttributeItem {
245+ fn inner ( & self ) -> & ContentItemInner {
246+ & self . inner
247+ }
248+ }
239249impl ContentItem for ExtendClassItem {
240250 fn inner ( & self ) -> & ContentItemInner {
241251 & self . inner
@@ -357,6 +367,51 @@ where
357367 Ok ( ( ) )
358368 }
359369}
370+
371+ impl < Item > ImplItem < Item > for AttributeItem
372+ where
373+ Item : ItemLike + ToTokens + GetIdent ,
374+ {
375+ fn gen_impl_item ( & self , args : ImplItemArgs < ' _ , Item > ) -> Result < ( ) > {
376+ let cfgs = args. cfgs . to_vec ( ) ;
377+ let attr = args. attrs . remove ( self . index ( ) ) ;
378+
379+ let get_py_name = |attr : & Attribute , ident : & Ident | -> Result < _ > {
380+ let item_meta = SimpleItemMeta :: from_attr ( ident. clone ( ) , attr) ?;
381+ let py_name = item_meta. simple_name ( ) ?;
382+ Ok ( py_name)
383+ } ;
384+ let ( py_name, tokens) = if args. item . is_function_or_method ( ) || args. item . is_const ( ) {
385+ let ident = args. item . get_ident ( ) . unwrap ( ) ;
386+ let py_name = get_py_name ( & attr, & ident) ?;
387+
388+ let value = if args. item . is_const ( ) {
389+ // TODO: ctx.new_value
390+ quote_spanned ! ( ident. span( ) => ctx. new_int( Self :: #ident) )
391+ } else {
392+ quote_spanned ! ( ident. span( ) => Self :: #ident( ctx) )
393+ } ;
394+ (
395+ py_name. clone ( ) ,
396+ quote ! {
397+ class. set_str_attr( #py_name, #value) ;
398+ } ,
399+ )
400+ } else {
401+ return Err ( self . new_syn_error (
402+ args. item . span ( ) ,
403+ "can only be on a const or an associated method without argument" ,
404+ ) ) ;
405+ } ;
406+
407+ args. context
408+ . impl_extend_items
409+ . add_item ( py_name, cfgs, tokens) ?;
410+
411+ Ok ( ( ) )
412+ }
413+ }
414+
360415impl < Item > ImplItem < Item > for ExtendClassItem
361416where
362417 Item : ItemLike + ToTokens + GetIdent ,
@@ -705,6 +760,9 @@ where
705760 "pyslot" => Box :: new ( SlotItem {
706761 inner : ContentItemInner { index, attr_name } ,
707762 } ) ,
763+ "pyattr" => Box :: new ( AttributeItem {
764+ inner : ContentItemInner { index, attr_name } ,
765+ } ) ,
708766 "extend_class" => Box :: new ( ExtendClassItem {
709767 inner : ContentItemInner { index, attr_name } ,
710768 } ) ,
0 commit comments