Skip to content

Commit 97f3434

Browse files
committed
Add AttrItemMeta for handling attribute item attathced with once
Signed-off-by: snowapril <sinjihng@gmail.com>
1 parent ab1693e commit 97f3434

File tree

2 files changed

+46
-46
lines changed

2 files changed

+46
-46
lines changed

derive/src/pymodule.rs

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::error::Diagnostic;
22
use crate::util::{
3-
iter_use_idents, path_eq, pyclass_ident_and_attrs, text_signature, AttributeExt, ClassItemMeta,
4-
ContentItem, ContentItemInner, ErrorVec, ItemMeta, ItemNursery, SimpleItemMeta,
3+
iter_use_idents, pyclass_ident_and_attrs, text_signature, AttrItemMeta, AttributeExt,
4+
ClassItemMeta, ContentItem, ContentItemInner, ErrorVec, ItemMeta, ItemNursery, SimpleItemMeta,
55
ALL_ALLOWED_NAMES,
66
};
77
use proc_macro2::TokenStream;
@@ -37,41 +37,6 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
3737
// collect to context
3838
for item in items.iter_mut() {
3939
let r = item.try_split_attr_mut(|attrs, item| {
40-
// If attribute is #[pyattr] and item is ItemFn, then
41-
// wrapping it with static_cell for preventing it from using it as function
42-
if attrs.iter().any(|attr| {
43-
path_eq(&attr.path, "pyattr")
44-
&& if let Ok(syn::Meta::List(l)) = attr.parse_meta() {
45-
l.nested
46-
.into_iter()
47-
.any(|n| n.get_ident().map_or(false, |p| p == "once"))
48-
} else {
49-
false
50-
}
51-
}) {
52-
if let Item::Fn(syn::ItemFn { sig, block, .. }) = item {
53-
let stmts = &block.stmts;
54-
let return_type = match &sig.output {
55-
syn::ReturnType::Default => {
56-
unreachable!("#[pyattr] attached function must have return type.")
57-
}
58-
syn::ReturnType::Type(_, ty) => ty,
59-
};
60-
let stmt: syn::Stmt = parse_quote! {
61-
{
62-
rustpython_common::static_cell! {
63-
static ERROR: #return_type;
64-
}
65-
ERROR
66-
.get_or_init(|| {
67-
#(#stmts)*
68-
})
69-
.clone()
70-
}
71-
};
72-
block.stmts = vec![stmt];
73-
}
74-
}
7540
let (pyitems, cfgs) = attrs_to_module_items(attrs, new_module_item)?;
7641
for pyitem in pyitems.iter().rev() {
7742
let r = pyitem.gen_module_item(ModuleItemArgs {
@@ -276,7 +241,7 @@ impl ContentItem for AttributeItem {
276241
}
277242

278243
struct ModuleItemArgs<'a> {
279-
item: &'a Item,
244+
item: &'a mut Item,
280245
attrs: &'a mut Vec<Attribute>,
281246
context: &'a mut ModuleContext,
282247
cfgs: &'a [Attribute],
@@ -405,15 +370,36 @@ impl ModuleItem for AttributeItem {
405370
fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()> {
406371
let cfgs = args.cfgs.to_vec();
407372
let attr = args.attrs.remove(self.index());
408-
let get_py_name = |attr: &Attribute, ident: &Ident| -> Result<_> {
409-
let item_meta = SimpleItemMeta::from_attr(ident.clone(), attr)?;
410-
let py_name = item_meta.simple_name()?;
411-
Ok(py_name)
412-
};
413373
let (py_name, tokens) = match args.item {
414-
Item::Fn(syn::ItemFn { sig, .. }) => {
374+
Item::Fn(syn::ItemFn { sig, block, .. }) => {
415375
let ident = &sig.ident;
416-
let py_name = get_py_name(&attr, ident)?;
376+
// If `once` keyword is in #[pyattr],
377+
// wrapping it with static_cell for preventing it from using it as function
378+
let attr_meta = AttrItemMeta::from_attr(ident.clone(), &attr)?;
379+
if attr_meta.inner()._bool("once")? {
380+
let stmts = &block.stmts;
381+
let return_type = match &sig.output {
382+
syn::ReturnType::Default => {
383+
unreachable!("#[pyattr] attached function must have return type.")
384+
}
385+
syn::ReturnType::Type(_, ty) => ty,
386+
};
387+
let stmt: syn::Stmt = parse_quote! {
388+
{
389+
rustpython_common::static_cell! {
390+
static ERROR: #return_type;
391+
}
392+
ERROR
393+
.get_or_init(|| {
394+
#(#stmts)*
395+
})
396+
.clone()
397+
}
398+
};
399+
block.stmts = vec![stmt];
400+
}
401+
402+
let py_name = attr_meta.simple_name()?;
417403
(
418404
py_name.clone(),
419405
quote_spanned! { ident.span() =>
@@ -422,7 +408,8 @@ impl ModuleItem for AttributeItem {
422408
)
423409
}
424410
Item::Const(syn::ItemConst { ident, .. }) => {
425-
let py_name = get_py_name(&attr, ident)?;
411+
let item_meta = SimpleItemMeta::from_attr(ident.clone(), &attr)?;
412+
let py_name = item_meta.simple_name()?;
426413
(
427414
py_name.clone(),
428415
quote_spanned! { ident.span() =>

derive/src/util.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,19 @@ pub(crate) trait ItemMeta: Sized {
226226
pub(crate) struct SimpleItemMeta(pub ItemMetaInner);
227227

228228
impl ItemMeta for SimpleItemMeta {
229+
const ALLOWED_NAMES: &'static [&'static str] = &["name"];
230+
231+
fn from_inner(inner: ItemMetaInner) -> Self {
232+
Self(inner)
233+
}
234+
fn inner(&self) -> &ItemMetaInner {
235+
&self.0
236+
}
237+
}
238+
239+
pub(crate) struct AttrItemMeta(pub ItemMetaInner);
240+
241+
impl ItemMeta for AttrItemMeta {
229242
const ALLOWED_NAMES: &'static [&'static str] = &["name", "once"];
230243

231244
fn from_inner(inner: ItemMetaInner) -> Self {

0 commit comments

Comments
 (0)