Skip to content

Commit 538e492

Browse files
committed
Add #[pyimpl(with(...))]
1 parent 8a71c7e commit 538e492

File tree

7 files changed

+50
-36
lines changed

7 files changed

+50
-36
lines changed

derive/src/pyclass.rs

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,18 @@ impl Class {
244244
attr_idxs.push(i);
245245
}
246246
}
247-
for idx in attr_idxs {
248-
attrs.remove(idx);
247+
let mut i = 0;
248+
let mut attr_idxs = &*attr_idxs;
249+
attrs.retain(|_| {
250+
let drop = attr_idxs.first().copied() == Some(i);
251+
if drop {
252+
attr_idxs = &attr_idxs[1..];
253+
}
254+
i += 1;
255+
!drop
256+
});
257+
for (i, idx) in attr_idxs.into_iter().enumerate() {
258+
attrs.remove(idx - i);
249259
}
250260
Ok(())
251261
}
@@ -256,7 +266,10 @@ struct ItemSig<'a> {
256266
sig: &'a Signature,
257267
}
258268

259-
fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnostic> {
269+
fn extract_impl_items(
270+
attr: AttributeArgs,
271+
mut items: Vec<ItemSig>,
272+
) -> Result<TokenStream2, Diagnostic> {
260273
let mut diagnostics: Vec<Diagnostic> = Vec::new();
261274

262275
let mut class = Class::default();
@@ -350,13 +363,36 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
350363

351364
Diagnostic::from_vec(diagnostics)?;
352365

366+
let mut withs = Vec::new();
367+
368+
for attr in attr {
369+
match attr {
370+
NestedMeta::Meta(Meta::List(syn::MetaList { path, nested, .. }))
371+
if path_eq(&path, "with") =>
372+
{
373+
for meta in nested {
374+
match meta {
375+
NestedMeta::Meta(Meta::Path(path)) => {
376+
withs.push(quote! {
377+
<Self as #path>::__extend_py_class(ctx, class);
378+
});
379+
}
380+
meta => bail_span!(meta, "#[pyimpl(with(...))] arguments should be paths"),
381+
}
382+
}
383+
}
384+
attr => bail_span!(attr, "Unknown pyimpl attribute"),
385+
}
386+
}
387+
353388
Ok(quote! {
354389
#(#methods)*
355390
#(#properties)*
391+
#(#withs)*
356392
})
357393
}
358394

359-
pub fn impl_pyimpl(_attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
395+
pub fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
360396
match item {
361397
Item::Impl(mut imp) => {
362398
let items = imp
@@ -369,7 +405,7 @@ pub fn impl_pyimpl(_attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
369405
_ => None,
370406
})
371407
.collect();
372-
let extend_impl = extract_impl_items(items)?;
408+
let extend_impl = extract_impl_items(attr, items)?;
373409
let ty = &imp.self_ty;
374410
let ret = quote! {
375411
#imp
@@ -395,7 +431,7 @@ pub fn impl_pyimpl(_attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
395431
_ => None,
396432
})
397433
.collect();
398-
let extend_impl = extract_impl_items(items)?;
434+
let extend_impl = extract_impl_items(attr, items)?;
399435
let item = parse_quote! {
400436
fn __extend_py_class(
401437
ctx: &::rustpython_vm::pyobject::PyContext,

vm/src/descriptor.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use crate::VirtualMachine;
55
// TODO: pyimpl compose pyslot(descr_get) and pymethod(__get__) from this trait
66
#[pyimpl]
77
pub trait PyBuiltinDescriptor: PyValue {
8-
#[pymethod]
8+
#[pymethod(name = "__get__")]
9+
#[pyslot(descr_get)]
910
fn get(
1011
zelf: PyRef<Self>,
1112
obj: PyObjectRef,

vm/src/obj/objbuiltinfunc.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl PyBuiltinDescriptor for PyBuiltinMethod {
8787
}
8888
}
8989

90-
#[pyimpl]
90+
#[pyimpl(with(PyBuiltinDescriptor))]
9191
impl PyBuiltinMethod {
9292
#[pymethod(name = "__call__")]
9393
pub fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
@@ -98,8 +98,4 @@ impl PyBuiltinMethod {
9898
pub fn init(context: &PyContext) {
9999
PyBuiltinFunction::extend_class(context, &context.types.builtin_function_or_method_type);
100100
PyBuiltinMethod::extend_class(context, &context.types.method_descriptor_type);
101-
extend_class!(context, context.types.method_descriptor_type, {
102-
"__get__" => context.new_method(PyBuiltinMethod::get),
103-
(slot descr_get) => PyBuiltinMethod::get,
104-
});
105101
}

vm/src/obj/objclassmethod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl PyBuiltinDescriptor for PyClassMethod {
5959
}
6060
}
6161

62-
#[pyimpl]
62+
#[pyimpl(with(PyBuiltinDescriptor))]
6363
impl PyClassMethod {
6464
#[pyslot]
6565
fn tp_new(
@@ -81,8 +81,4 @@ impl PyClassMethod {
8181

8282
pub(crate) fn init(context: &PyContext) {
8383
PyClassMethod::extend_class(context, &context.types.classmethod_type);
84-
extend_class!(context, context.types.classmethod_type, {
85-
"__get__" => context.new_method(PyClassMethod::get),
86-
(slot descr_get) => PyClassMethod::get,
87-
});
8884
}

vm/src/obj/objfunction.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ impl PyValue for PyFunction {
240240
}
241241
}
242242

243-
#[pyimpl]
243+
#[pyimpl(with(PyBuiltinDescriptor))]
244244
impl PyFunction {
245245
#[pymethod(name = "__call__")]
246246
fn call(zelf: PyObjectRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
@@ -289,10 +289,6 @@ impl PyValue for PyBoundMethod {
289289
pub fn init(context: &PyContext) {
290290
let function_type = &context.types.function_type;
291291
PyFunction::extend_class(context, function_type);
292-
extend_class!(context, function_type, {
293-
"__get__" => context.new_method(PyFunction::get),
294-
(slot descr_get) => PyFunction::get,
295-
});
296292

297293
let method_type = &context.types.bound_method_type;
298294
extend_class!(context, method_type, {

vm/src/obj/objproperty.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl PyBuiltinDescriptor for PyReadOnlyProperty {
4646
}
4747
}
4848

49-
#[pyimpl]
49+
#[pyimpl(with(PyBuiltinDescriptor))]
5050
impl PyReadOnlyProperty {}
5151

5252
/// Property attribute.
@@ -129,7 +129,7 @@ impl PyBuiltinDescriptor for PyProperty {
129129
}
130130
}
131131

132-
#[pyimpl]
132+
#[pyimpl(with(PyBuiltinDescriptor))]
133133
impl PyProperty {
134134
#[pyslot]
135135
fn tp_new(cls: PyClassRef, args: PropertyArgs, vm: &VirtualMachine) -> PyResult<PyPropertyRef> {
@@ -318,15 +318,8 @@ impl<'a> PropertyBuilder<'a> {
318318

319319
pub fn init(context: &PyContext) {
320320
PyReadOnlyProperty::extend_class(context, &context.types.readonly_property_type);
321-
extend_class!(context, context.types.readonly_property_type, {
322-
"__get__" => context.new_method(PyReadOnlyProperty::get),
323-
(slot descr_get) => PyReadOnlyProperty::get,
324-
});
325321

326322
PyProperty::extend_class(context, &context.types.property_type);
327-
extend_class!(context, context.types.property_type, {
328-
"__get__" => context.new_method(PyProperty::get),
329-
});
330323

331324
// This is a bit unfortunate, but this instance attribute overlaps with the
332325
// class __doc__ string..

vm/src/obj/objstaticmethod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl PyBuiltinDescriptor for PyStaticMethod {
2828
}
2929
}
3030

31-
#[pyimpl]
31+
#[pyimpl(with(PyBuiltinDescriptor))]
3232
impl PyStaticMethod {
3333
#[pyslot]
3434
fn tp_new(
@@ -45,8 +45,4 @@ impl PyStaticMethod {
4545

4646
pub fn init(context: &PyContext) {
4747
PyStaticMethod::extend_class(context, &context.types.staticmethod_type);
48-
extend_class!(context, context.types.staticmethod_type, {
49-
"__get__" => context.new_method(PyStaticMethod::get),
50-
(slot descr_get) => PyStaticMethod::get,
51-
});
5248
}

0 commit comments

Comments
 (0)