Skip to content

Commit 4fba939

Browse files
authored
Merge pull request RustPython#4706 from youknowone/py-type
#[pyclass] impl Py<PyType>
2 parents fd02825 + cf2b48f commit 4fba939

38 files changed

+1330
-1162
lines changed

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"rsplitn",
6262
"rustc",
6363
"rustfmt",
64+
"seekfrom",
6465
"splitn",
6566
"subsec",
6667
"timsort",

derive-impl/src/pyclass.rs

Lines changed: 114 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -105,39 +105,114 @@ pub(crate) fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream
105105
Item::Impl(mut imp) => {
106106
extract_items_into_context(&mut context, imp.items.iter_mut());
107107

108-
let ty = &imp.self_ty;
108+
let (impl_ty, payload_guess) = match imp.self_ty.as_ref() {
109+
syn::Type::Path(syn::TypePath {
110+
path: syn::Path { segments, .. },
111+
..
112+
}) if segments.len() == 1 => {
113+
let segment = &segments[0];
114+
let payload_ty = if segment.ident == "Py" || segment.ident == "PyRef" {
115+
match &segment.arguments {
116+
syn::PathArguments::AngleBracketed(
117+
syn::AngleBracketedGenericArguments { args, .. },
118+
) if args.len() == 1 => {
119+
let arg = &args[0];
120+
match arg {
121+
syn::GenericArgument::Type(syn::Type::Path(
122+
syn::TypePath {
123+
path: syn::Path { segments, .. },
124+
..
125+
},
126+
)) if segments.len() == 1 => segments[0].ident.clone(),
127+
_ => {
128+
return Err(syn::Error::new_spanned(
129+
segment,
130+
"Py{Ref}<T> is expected but Py{Ref}<?> is found",
131+
))
132+
}
133+
}
134+
}
135+
_ => {
136+
return Err(syn::Error::new_spanned(
137+
segment,
138+
"Py{Ref}<T> is expected but Py{Ref}? is found",
139+
))
140+
}
141+
}
142+
} else {
143+
if !matches!(segment.arguments, syn::PathArguments::None) {
144+
return Err(syn::Error::new_spanned(
145+
segment,
146+
"PyImpl can only be implemented for Py{Ref}<T> or T",
147+
));
148+
}
149+
segment.ident.clone()
150+
};
151+
(segment.ident.clone(), payload_ty)
152+
}
153+
_ => {
154+
return Err(syn::Error::new_spanned(
155+
imp.self_ty,
156+
"PyImpl can only be implemented for Py{Ref}<T> or T",
157+
))
158+
}
159+
};
160+
109161
let ExtractedImplAttrs {
162+
payload: attr_payload,
110163
with_impl,
111164
flags,
112165
with_slots,
113-
} = extract_impl_attrs(attr, &Ident::new(&quote!(ty).to_string(), ty.span()))?;
114-
166+
} = extract_impl_attrs(attr, &impl_ty)?;
167+
let payload_ty = attr_payload.unwrap_or(payload_guess);
115168
let getset_impl = &context.getset_items;
116169
let member_impl = &context.member_items;
117170
let extend_impl = context.impl_extend_items.validate()?;
118171
let slots_impl = context.extend_slots_items.validate()?;
119172
let class_extensions = &context.class_extensions;
120-
quote! {
121-
#imp
122-
impl ::rustpython_vm::class::PyClassImpl for #ty {
123-
const TP_FLAGS: ::rustpython_vm::types::PyTypeFlags = #flags;
124173

125-
fn impl_extend_class(
174+
let extra_methods = iter_chain![
175+
parse_quote! {
176+
fn __extend_py_class(
126177
ctx: &::rustpython_vm::Context,
127178
class: &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType>,
128179
) {
129180
#getset_impl
130181
#member_impl
131182
#extend_impl
132-
#with_impl
133183
#(#class_extensions)*
134184
}
135-
136-
fn extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
137-
#with_slots
185+
},
186+
parse_quote! {
187+
fn __extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
138188
#slots_impl
139189
}
190+
},
191+
];
192+
imp.items.extend(extra_methods);
193+
let is_main_impl = impl_ty == payload_ty;
194+
if is_main_impl {
195+
quote! {
196+
#imp
197+
impl ::rustpython_vm::class::PyClassImpl for #payload_ty {
198+
const TP_FLAGS: ::rustpython_vm::types::PyTypeFlags = #flags;
199+
200+
fn impl_extend_class(
201+
ctx: &::rustpython_vm::Context,
202+
class: &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType>,
203+
) {
204+
#impl_ty::__extend_py_class(ctx, class);
205+
#with_impl
206+
}
207+
208+
fn extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
209+
#impl_ty::__extend_slots(slots);
210+
#with_slots
211+
}
212+
}
140213
}
214+
} else {
215+
imp.into_token_stream()
141216
}
142217
}
143218
Item::Trait(mut trai) => {
@@ -1163,6 +1238,7 @@ impl MemberItemMeta {
11631238
}
11641239

11651240
struct ExtractedImplAttrs {
1241+
payload: Option<Ident>,
11661242
with_impl: TokenStream,
11671243
with_slots: TokenStream,
11681244
flags: TokenStream,
@@ -1182,6 +1258,7 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
11821258
}
11831259
}
11841260
}];
1261+
let mut payload = None;
11851262

11861263
for attr in attr {
11871264
match attr {
@@ -1191,18 +1268,19 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
11911268
let NestedMeta::Meta(Meta::Path(path)) = meta else {
11921269
bail_span!(meta, "#[pyclass(with(...))] arguments should be paths")
11931270
};
1194-
let (extend_class, extend_slots) = if path.is_ident("PyRef") {
1195-
// special handling for PyRef
1196-
(
1197-
quote!(PyRef::<Self>::impl_extend_class),
1198-
quote!(PyRef::<Self>::extend_slots),
1199-
)
1200-
} else {
1201-
(
1202-
quote!(<Self as #path>::__extend_py_class),
1203-
quote!(<Self as #path>::__extend_slots),
1204-
)
1205-
};
1271+
let (extend_class, extend_slots) =
1272+
if path.is_ident("PyRef") || path.is_ident("Py") {
1273+
// special handling for PyRef
1274+
(
1275+
quote!(#path::<Self>::__extend_py_class),
1276+
quote!(#path::<Self>::__extend_slots),
1277+
)
1278+
} else {
1279+
(
1280+
quote!(<Self as #path>::__extend_py_class),
1281+
quote!(<Self as #path>::__extend_slots),
1282+
)
1283+
};
12061284
let item_span = item.span().resolved_at(Span::call_site());
12071285
withs.push(quote_spanned! { path.span() =>
12081286
#extend_class(ctx, class);
@@ -1227,11 +1305,23 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
12271305
bail_span!(path, "Unknown pyimpl attribute")
12281306
}
12291307
}
1308+
NestedMeta::Meta(Meta::NameValue(syn::MetaNameValue { path, lit, .. })) => {
1309+
if path.is_ident("payload") {
1310+
if let syn::Lit::Str(lit) = lit {
1311+
payload = Some(Ident::new(&lit.value(), lit.span()));
1312+
} else {
1313+
bail_span!(lit, "payload must be a string literal")
1314+
}
1315+
} else {
1316+
bail_span!(path, "Unknown pyimpl attribute")
1317+
}
1318+
}
12301319
attr => bail_span!(attr, "Unknown pyimpl attribute"),
12311320
}
12321321
}
12331322

12341323
Ok(ExtractedImplAttrs {
1324+
payload,
12351325
with_impl: quote! {
12361326
#(#withs)*
12371327
},

examples/call_between_rust_and_python.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ python_person.name: {}",
8686
name: String,
8787
}
8888

89-
impl TryFromBorrowedObject for PythonPerson {
90-
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
89+
impl<'a> TryFromBorrowedObject<'a> for PythonPerson {
90+
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
9191
let name = obj.get_attr("name", vm)?.try_into_value::<String>(vm)?;
9292
Ok(PythonPerson { name })
9393
}

stdlib/src/array.rs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ mod array {
746746
}
747747

748748
#[pymethod]
749-
fn append(zelf: PyRef<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
749+
fn append(zelf: &Py<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
750750
zelf.try_resizable(vm)?.push(x, vm)
751751
}
752752

@@ -762,12 +762,12 @@ mod array {
762762
}
763763

764764
#[pymethod]
765-
fn remove(zelf: PyRef<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
765+
fn remove(zelf: &Py<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
766766
zelf.try_resizable(vm)?.remove(x, vm)
767767
}
768768

769769
#[pymethod]
770-
fn extend(zelf: PyRef<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
770+
fn extend(zelf: &Py<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
771771
let mut w = zelf.try_resizable(vm)?;
772772
if zelf.is(&obj) {
773773
w.imul(2, vm)
@@ -828,7 +828,7 @@ mod array {
828828
}
829829

830830
#[pymethod]
831-
fn fromunicode(zelf: PyRef<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
831+
fn fromunicode(zelf: &Py<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
832832
let utf8 = PyStrRef::try_from_object(vm, obj.clone()).map_err(|_| {
833833
vm.new_type_error(format!(
834834
"fromunicode() argument must be str, not {}",
@@ -922,18 +922,13 @@ mod array {
922922
}
923923

924924
#[pymethod]
925-
fn insert(
926-
zelf: PyRef<Self>,
927-
i: isize,
928-
x: PyObjectRef,
929-
vm: &VirtualMachine,
930-
) -> PyResult<()> {
925+
fn insert(zelf: &Py<Self>, i: isize, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
931926
let mut w = zelf.try_resizable(vm)?;
932927
w.insert(i, x, vm)
933928
}
934929

935930
#[pymethod]
936-
fn pop(zelf: PyRef<Self>, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
931+
fn pop(zelf: &Py<Self>, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
937932
let mut w = zelf.try_resizable(vm)?;
938933
if w.len() == 0 {
939934
Err(vm.new_index_error("pop from empty array".to_owned()))
@@ -982,7 +977,7 @@ mod array {
982977
}
983978

984979
#[pymethod]
985-
fn fromlist(zelf: PyRef<Self>, list: PyListRef, vm: &VirtualMachine) -> PyResult<()> {
980+
fn fromlist(zelf: &Py<Self>, list: PyListRef, vm: &VirtualMachine) -> PyResult<()> {
986981
zelf.try_resizable(vm)?.fromlist(&list, vm)
987982
}
988983

@@ -1014,7 +1009,7 @@ mod array {
10141009
}
10151010

10161011
fn _setitem(
1017-
zelf: PyRef<Self>,
1012+
zelf: &Py<Self>,
10181013
needle: &PyObject,
10191014
value: PyObjectRef,
10201015
vm: &VirtualMachine,
@@ -1052,7 +1047,7 @@ mod array {
10521047

10531048
#[pymethod(magic)]
10541049
fn setitem(
1055-
zelf: PyRef<Self>,
1050+
zelf: &Py<Self>,
10561051
needle: PyObjectRef,
10571052
value: PyObjectRef,
10581053
vm: &VirtualMachine,
@@ -1120,7 +1115,7 @@ mod array {
11201115
}
11211116

11221117
#[pymethod(magic)]
1123-
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<String> {
1118+
fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
11241119
let class = zelf.class();
11251120
let class_name = class.name();
11261121
if zelf.read().typecode() == 'u' {
@@ -1167,7 +1162,7 @@ mod array {
11671162

11681163
#[pymethod(magic)]
11691164
fn reduce_ex(
1170-
zelf: PyRef<Self>,
1165+
zelf: &Py<Self>,
11711166
proto: usize,
11721167
vm: &VirtualMachine,
11731168
) -> PyResult<(PyObjectRef, PyTupleRef, Option<PyDictRef>)> {
@@ -1191,7 +1186,7 @@ mod array {
11911186

11921187
#[pymethod(magic)]
11931188
fn reduce(
1194-
zelf: PyRef<Self>,
1189+
zelf: &Py<Self>,
11951190
vm: &VirtualMachine,
11961191
) -> PyResult<(PyObjectRef, PyTupleRef, Option<PyDictRef>)> {
11971192
let array = zelf.read();
@@ -1325,7 +1320,7 @@ mod array {
13251320
ass_subscript: atomic_func!(|mapping, needle, value, vm| {
13261321
let zelf = PyArray::mapping_downcast(mapping);
13271322
if let Some(value) = value {
1328-
PyArray::_setitem(zelf.to_owned(), needle, value, vm)
1323+
PyArray::_setitem(zelf, needle, value, vm)
13291324
} else {
13301325
zelf._delitem(needle, vm)
13311326
}

stdlib/src/faulthandler.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ pub(crate) use decl::make_module;
22

33
#[pymodule(name = "faulthandler")]
44
mod decl {
5-
use crate::vm::{
6-
frame::FrameRef, function::OptionalArg, stdlib::sys::PyStderr, VirtualMachine,
7-
};
5+
use crate::vm::{frame::Frame, function::OptionalArg, stdlib::sys::PyStderr, VirtualMachine};
86

9-
fn dump_frame(frame: &FrameRef, vm: &VirtualMachine) {
7+
fn dump_frame(frame: &Frame, vm: &VirtualMachine) {
108
let stderr = PyStderr(vm);
119
writeln!(
1210
stderr,

stdlib/src/mmap.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ mod mmap {
7272
Copy = 3,
7373
}
7474

75-
impl TryFromBorrowedObject for AccessMode {
76-
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
75+
impl<'a> TryFromBorrowedObject<'a> for AccessMode {
76+
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
7777
let i = u32::try_from_borrowed_object(vm, obj)?;
7878
Ok(match i {
7979
0 => Self::Default,

stdlib/src/resource.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ mod resource {
129129
}
130130

131131
struct Limits(libc::rlimit);
132-
impl TryFromBorrowedObject for Limits {
133-
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
132+
impl<'a> TryFromBorrowedObject<'a> for Limits {
133+
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
134134
let seq: Vec<libc::rlim_t> = obj.try_to_value(vm)?;
135135
match *seq {
136136
[cur, max] => Ok(Self(libc::rlimit {

0 commit comments

Comments
 (0)