Skip to content

Commit fbe37d0

Browse files
committed
Add trait support for #[pyimpl]
1 parent 43b0760 commit fbe37d0

File tree

1 file changed

+61
-30
lines changed

1 file changed

+61
-30
lines changed

derive/src/pyclass.rs

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use super::rustpython_path_attr;
22
use proc_macro2::{Span, TokenStream as TokenStream2};
33
use quote::quote;
4-
use syn::{Attribute, AttributeArgs, Ident, ImplItem, Item, Lit, Meta, MethodSig, NestedMeta};
4+
use syn::{
5+
Attribute, AttributeArgs, Ident, ImplItem, Item, Lit, Meta, MethodSig, NestedMeta, TraitItem,
6+
};
57

68
enum MethodKind {
79
Method,
@@ -89,27 +91,7 @@ impl Method {
8991
}
9092
}
9193

92-
pub fn impl_pyimpl(attr: AttributeArgs, item: Item) -> TokenStream2 {
93-
let mut imp = if let Item::Impl(imp) = item {
94-
imp
95-
} else {
96-
return quote!(#item);
97-
};
98-
99-
let rp_path = rustpython_path_attr(&attr);
100-
101-
let methods = imp
102-
.items
103-
.iter_mut()
104-
.filter_map(|item| {
105-
if let ImplItem::Method(meth) = item {
106-
Method::from_syn(&mut meth.attrs, &meth.sig)
107-
} else {
108-
None
109-
}
110-
})
111-
.collect::<Vec<_>>();
112-
let ty = &imp.self_ty;
94+
fn get_pyimpl_impl(rp_path: &syn::Path, methods: &[Method]) -> TokenStream2 {
11395
let methods = methods.iter().map(
11496
|Method {
11597
py_name,
@@ -122,17 +104,66 @@ pub fn impl_pyimpl(attr: AttributeArgs, item: Item) -> TokenStream2 {
122104
}
123105
},
124106
);
125-
126107
quote! {
127-
#imp
128-
impl #rp_path::pyobject::PyClassImpl for #ty {
129-
fn impl_extend_class(
130-
ctx: &#rp_path::pyobject::PyContext,
131-
class: &#rp_path::obj::objtype::PyClassRef,
132-
) {
133-
#(#methods)*
108+
fn impl_extend_class(
109+
ctx: &#rp_path::pyobject::PyContext,
110+
class: &#rp_path::obj::objtype::PyClassRef,
111+
) {
112+
#(#methods)*
113+
}
114+
}
115+
}
116+
117+
pub fn impl_pyimpl(attr: AttributeArgs, item: Item) -> TokenStream2 {
118+
let rp_path = rustpython_path_attr(&attr);
119+
let pyclassimpl_path = quote!(#rp_path::pyobject::PyClassImpl);
120+
match item {
121+
Item::Impl(mut imp) => {
122+
let methods = imp
123+
.items
124+
.iter_mut()
125+
.filter_map(|item| {
126+
if let ImplItem::Method(meth) = item {
127+
Method::from_syn(&mut meth.attrs, &meth.sig)
128+
} else {
129+
None
130+
}
131+
})
132+
.collect::<Vec<_>>();
133+
134+
let pyimpl_impl = get_pyimpl_impl(&rp_path, &methods);
135+
let ty = &imp.self_ty;
136+
137+
quote! {
138+
#imp
139+
impl #pyclassimpl_path for #ty {
140+
#pyimpl_impl
141+
}
142+
}
143+
}
144+
Item::Trait(mut trai) => {
145+
let methods = trai
146+
.items
147+
.iter_mut()
148+
.filter_map(|item| {
149+
if let TraitItem::Method(meth) = item {
150+
Method::from_syn(&mut meth.attrs, &meth.sig)
151+
} else {
152+
None
153+
}
154+
})
155+
.collect::<Vec<_>>();
156+
157+
let pyimpl_impl = get_pyimpl_impl(&rp_path, &methods);
158+
let ty = &trai.ident;
159+
160+
quote! {
161+
impl<T: #ty> #pyclassimpl_path for T {
162+
#pyimpl_impl
163+
}
134164
}
135165
}
166+
_ => panic!("#[pyimpl] can only be applied to impl blocks and trait definitions"),
136167
}
137168
}
138169

0 commit comments

Comments
 (0)