Skip to content

Commit 2f75562

Browse files
Merge pull request RustPython#1045 from RustPython/coolreader18/pyclassmethod-attr
Add #[pyclassmethod] to #[pyimpl]
2 parents 9bb5dcc + e68b494 commit 2f75562

File tree

1 file changed

+59
-12
lines changed

1 file changed

+59
-12
lines changed

derive/src/pyclass.rs

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ enum ClassItem {
1111
item_ident: Ident,
1212
py_name: String,
1313
},
14+
ClassMethod {
15+
item_ident: Ident,
16+
py_name: String,
17+
},
1418
Property {
1519
item_ident: Ident,
1620
py_name: String,
@@ -49,8 +53,8 @@ impl ClassItem {
4953
let nesteds = meta_to_vec(meta).map_err(|meta| {
5054
err_span!(
5155
meta,
52-
"#[pyproperty = \"...\"] cannot be a name/value, you probably meant \
53-
#[pyproperty(name = \"...\")]",
56+
"#[pymethod = \"...\"] cannot be a name/value, you probably meant \
57+
#[pymethod(name = \"...\")]",
5458
)
5559
})?;
5660
let mut py_name = None;
@@ -80,6 +84,47 @@ impl ClassItem {
8084
py_name: py_name.unwrap_or_else(|| sig.ident.to_string()),
8185
});
8286
attr_idx = Some(i);
87+
} else if name == "pyclassmethod" {
88+
if item.is_some() {
89+
bail_span!(
90+
sig.ident,
91+
"You can only have one #[py*] attribute on an impl item"
92+
)
93+
}
94+
let nesteds = meta_to_vec(meta).map_err(|meta| {
95+
err_span!(
96+
meta,
97+
"#[pyclassmethod = \"...\"] cannot be a name/value, you probably meant \
98+
#[pyclassmethod(name = \"...\")]",
99+
)
100+
})?;
101+
let mut py_name = None;
102+
for meta in nesteds {
103+
let meta = match meta {
104+
NestedMeta::Meta(meta) => meta,
105+
NestedMeta::Literal(_) => continue,
106+
};
107+
match meta {
108+
Meta::NameValue(name_value) => {
109+
if name_value.ident == "name" {
110+
if let Lit::Str(s) = &name_value.lit {
111+
py_name = Some(s.value());
112+
} else {
113+
bail_span!(
114+
&sig.ident,
115+
"#[pyclassmethod(name = ...)] must be a string"
116+
);
117+
}
118+
}
119+
}
120+
_ => {}
121+
}
122+
}
123+
item = Some(ClassItem::ClassMethod {
124+
item_ident: sig.ident.clone(),
125+
py_name: py_name.unwrap_or_else(|| sig.ident.to_string()),
126+
});
127+
attr_idx = Some(i);
83128
} else if name == "pyproperty" {
84129
if item.is_some() {
85130
bail_span!(
@@ -210,18 +255,20 @@ pub fn impl_pyimpl(_attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
210255
_ => {}
211256
}
212257
}
213-
let methods = items.iter().filter_map(|item| {
214-
if let ClassItem::Method {
258+
let methods = items.iter().filter_map(|item| match item {
259+
ClassItem::Method {
215260
item_ident,
216261
py_name,
217-
} = item
218-
{
219-
Some(quote! {
220-
class.set_str_attr(#py_name, ctx.new_rustfunc(Self::#item_ident));
221-
})
222-
} else {
223-
None
224-
}
262+
} => Some(quote! {
263+
class.set_str_attr(#py_name, ctx.new_rustfunc(Self::#item_ident));
264+
}),
265+
ClassItem::ClassMethod {
266+
item_ident,
267+
py_name,
268+
} => Some(quote! {
269+
class.set_str_attr(#py_name, ctx.new_classmethod(Self::#item_ident));
270+
}),
271+
_ => None,
225272
});
226273
let properties = properties
227274
.iter()

0 commit comments

Comments
 (0)