From 55709b71b6464688116b0a69d61aa424645fe26d Mon Sep 17 00:00:00 2001 From: eldpswp99 Date: Thu, 2 Sep 2021 23:08:02 +0900 Subject: [PATCH] implement SlotConstructor for every class --- derive/src/pyclass.rs | 10 +- vm/src/builtins/bytearray.rs | 4 +- vm/src/builtins/bytes.rs | 30 ++- vm/src/builtins/classmethod.rs | 19 +- vm/src/builtins/code.rs | 3 +- vm/src/builtins/complex.rs | 155 +++++------ vm/src/builtins/dict.rs | 4 +- vm/src/builtins/enumerate.rs | 17 +- vm/src/builtins/filter.rs | 28 +- vm/src/builtins/float.rs | 21 +- vm/src/builtins/frame.rs | 4 +- vm/src/builtins/function.rs | 54 ++-- vm/src/builtins/int.rs | 2 +- vm/src/builtins/list.rs | 10 +- vm/src/builtins/map.rs | 21 +- vm/src/builtins/mappingproxy.rs | 15 +- vm/src/builtins/memory.rs | 27 +- vm/src/builtins/module.rs | 4 +- vm/src/builtins/namespace.rs | 16 +- vm/src/builtins/object.rs | 5 +- vm/src/builtins/property.rs | 4 +- vm/src/builtins/pybool.rs | 56 ++-- vm/src/builtins/pystr.rs | 19 +- vm/src/builtins/pysuper.rs | 62 +++-- vm/src/builtins/pytype.rs | 2 +- vm/src/builtins/range.rs | 8 +- vm/src/builtins/set.rs | 54 ++-- vm/src/builtins/singletons.rs | 35 ++- vm/src/builtins/slice.rs | 21 +- vm/src/builtins/staticmethod.rs | 17 +- vm/src/builtins/tuple.rs | 63 +++-- vm/src/builtins/weakproxy.rs | 30 ++- vm/src/builtins/weakref.rs | 39 ++- vm/src/builtins/zip.rs | 17 +- vm/src/exceptions.rs | 14 +- vm/src/pyobject.rs | 4 + vm/src/stdlib/array.rs | 40 +-- vm/src/stdlib/collections.rs | 75 +++--- vm/src/stdlib/io.rs | 110 ++++---- vm/src/stdlib/itertools.rs | 455 ++++++++++++++++++++------------ vm/src/stdlib/json.rs | 15 +- vm/src/stdlib/operator.rs | 28 +- vm/src/stdlib/pystruct.rs | 19 +- vm/src/stdlib/random.rs | 20 +- vm/src/stdlib/socket.rs | 4 +- vm/src/stdlib/ssl.rs | 34 +-- vm/src/stdlib/thread.rs | 8 +- vm/src/stdlib/time.rs | 7 +- 48 files changed, 972 insertions(+), 737 deletions(-) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index e00e899b5..21da59ba4 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -476,14 +476,8 @@ where let slot_ident = item_meta.slot_name()?; let slot_name = slot_ident.to_string(); let tokens = { - let into_func = if slot_name == "new" { - quote_spanned! {ident.span() => - ::rustpython_vm::function::IntoPyNativeFunc::into_func(Self::#ident) - } - } else { - quote_spanned! {ident.span() => - Self::#ident as _ - } + let into_func = quote_spanned! {ident.span() => + Self::#ident as _ }; const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer"]; if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) { diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 8eb5c079c..2c7376ef1 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -102,8 +102,8 @@ pub(crate) fn init(context: &PyContext) { #[pyimpl(flags(BASETYPE), with(Hashable, Comparable, AsBuffer, Iterable))] impl PyByteArray { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - PyByteArray::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + PyByteArray::default().into_pyresult_with_type(vm, cls) } #[pymethod(magic)] diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 4a6e2a56c..e9a69939a 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -12,12 +12,14 @@ use crate::bytesinner::{ use crate::byteslike::ArgBytesLike; use crate::common::hash::PyHash; use crate::function::{OptionalArg, OptionalOption}; -use crate::slots::{AsBuffer, Callable, Comparable, Hashable, Iterable, PyComparisonOp, PyIter}; +use crate::slots::{ + AsBuffer, Callable, Comparable, Hashable, Iterable, PyComparisonOp, PyIter, SlotConstructor, +}; use crate::utils::Either; use crate::vm::VirtualMachine; use crate::{ - IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, - PyRef, PyResult, PyValue, TryFromBorrowedObject, TypeProtocol, + IdProtocol, IntoPyObject, IntoPyResult, PyClassImpl, PyComparisonValue, PyContext, PyIterable, + PyObjectRef, PyRef, PyResult, PyValue, TryFromBorrowedObject, TypeProtocol, }; use bstr::ByteSlice; use crossbeam_utils::atomic::AtomicCell; @@ -96,17 +98,19 @@ pub(crate) fn init(context: &PyContext) { PyBytesIterator::extend_class(context, &context.types.bytes_iterator_type); } -#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, AsBuffer, Iterable))] -impl PyBytes { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - options: ByteInnerNewOptions, - vm: &VirtualMachine, - ) -> PyResult> { - options.get_bytes(cls, vm) - } +impl SlotConstructor for PyBytes { + type Args = ByteInnerNewOptions; + fn py_new(cls: PyTypeRef, options: Self::Args, vm: &VirtualMachine) -> PyResult { + options.get_bytes(cls, vm).into_pyresult(vm) + } +} + +#[pyimpl( + flags(BASETYPE), + with(Hashable, Comparable, AsBuffer, Iterable, SlotConstructor) +)] +impl PyBytes { #[pymethod(magic)] pub(crate) fn repr(&self) -> String { self.inner.repr("", "") diff --git a/vm/src/builtins/classmethod.rs b/vm/src/builtins/classmethod.rs index 4f536d048..9c5fd9435 100644 --- a/vm/src/builtins/classmethod.rs +++ b/vm/src/builtins/classmethod.rs @@ -1,7 +1,7 @@ use super::pytype::PyTypeRef; -use crate::slots::SlotDescriptor; +use crate::slots::{SlotConstructor, SlotDescriptor}; use crate::vm::VirtualMachine; -use crate::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol}; +use crate::{PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol}; /// classmethod(function) -> method /// @@ -54,13 +54,16 @@ impl SlotDescriptor for PyClassMethod { } } -#[pyimpl(with(SlotDescriptor), flags(BASETYPE, HAS_DICT))] -impl PyClassMethod { - #[pyslot] - fn tp_new(cls: PyTypeRef, callable: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - PyClassMethod { callable }.into_ref_with_type(vm, cls) - } +impl SlotConstructor for PyClassMethod { + type Args = PyObjectRef; + fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult { + PyClassMethod { callable }.into_pyresult_with_type(vm, cls) + } +} + +#[pyimpl(with(SlotDescriptor, SlotConstructor), flags(BASETYPE, HAS_DICT))] +impl PyClassMethod { #[pyproperty(magic)] fn func(&self) -> PyObjectRef { self.callable.clone() diff --git a/vm/src/builtins/code.rs b/vm/src/builtins/code.rs index 881ac97aa..f489b6246 100644 --- a/vm/src/builtins/code.rs +++ b/vm/src/builtins/code.rs @@ -7,6 +7,7 @@ use std::ops::Deref; use super::{PyStrRef, PyTypeRef}; use crate::bytecode::{self, BorrowedConstant, Constant, ConstantBag}; +use crate::function::FuncArgs; use crate::VirtualMachine; use crate::{ IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, StaticType, @@ -196,7 +197,7 @@ impl PyCode {} #[pyimpl] impl PyCodeRef { #[pyslot] - fn tp_new(_cls: PyTypeRef, vm: &VirtualMachine) -> PyResult { + fn tp_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error("Cannot directly create code object".to_owned())) } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 52374d965..117567851 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -6,7 +6,7 @@ use super::float; use super::pystr::PyStr; use super::pytype::PyTypeRef; use crate::function::{OptionalArg, OptionalOption}; -use crate::slots::{Comparable, Hashable, PyComparisonOp}; +use crate::slots::{Comparable, Hashable, PyComparisonOp, SlotConstructor}; use crate::VirtualMachine; use crate::{ IdProtocol, IntoPyObject, @@ -83,7 +83,83 @@ fn inner_pow(v1: Complex64, v2: Complex64, vm: &VirtualMachine) -> PyResult PyResult { + let imag_missing = args.imag.is_missing(); + let (real, real_was_complex) = match args.real { + OptionalArg::Missing => (Complex64::new(0.0, 0.0), false), + OptionalArg::Present(val) => { + let val = if cls.is(&vm.ctx.types.complex_type) && imag_missing { + match val.downcast_exact::(vm) { + Ok(c) => { + return Ok(c.into_object()); + } + Err(val) => val, + } + } else { + val + }; + + if let Some(c) = try_complex(&val, vm)? { + c + } else if let Some(s) = val.payload_if_subclass::(vm) { + if args.imag.is_present() { + return Err(vm.new_type_error( + "complex() can't take second arg if first is a string".to_owned(), + )); + } + let value = parse_str(s.as_str().trim()).ok_or_else(|| { + vm.new_value_error("complex() arg is a malformed string".to_owned()) + })?; + return Self::from(value).into_pyresult_with_type(vm, cls); + } else { + return Err(vm.new_type_error(format!( + "complex() first argument must be a string or a number, not '{}'", + val.class().name + ))); + } + } + }; + + let (imag, imag_was_complex) = match args.imag { + // Copy the imaginary from the real to the real of the imaginary + // if an imaginary argument is not passed in + OptionalArg::Missing => (Complex64::new(real.im, 0.0), false), + OptionalArg::Present(obj) => { + if let Some(c) = try_complex(&obj, vm)? { + c + } else if obj.class().issubclass(&vm.ctx.types.str_type) { + return Err( + vm.new_type_error("complex() second arg can't be a string".to_owned()) + ); + } else { + return Err(vm.new_type_error(format!( + "complex() second argument must be a number, not '{}'", + obj.class().name + ))); + } + } + }; + + let final_real = if imag_was_complex { + real.re - imag.im + } else { + real.re + }; + + let final_imag = if real_was_complex && !imag_missing { + imag.re + real.im + } else { + imag.re + }; + let value = Complex64::new(final_real, final_imag); + Self::from(value).into_pyresult_with_type(vm, cls) + } +} + +#[pyimpl(flags(BASETYPE), with(Comparable, Hashable, SlotConstructor))] impl PyComplex { pub fn to_complex(&self) -> Complex64 { self.value @@ -267,79 +343,6 @@ impl PyComplex { !Complex64::is_zero(&self.value) } - #[pyslot] - fn tp_new(cls: PyTypeRef, args: ComplexArgs, vm: &VirtualMachine) -> PyResult> { - let imag_missing = args.imag.is_missing(); - let (real, real_was_complex) = match args.real { - OptionalArg::Missing => (Complex64::new(0.0, 0.0), false), - OptionalArg::Present(val) => { - let val = if cls.is(&vm.ctx.types.complex_type) && imag_missing { - match val.downcast_exact::(vm) { - Ok(c) => { - return Ok(c); - } - Err(val) => val, - } - } else { - val - }; - - if let Some(c) = try_complex(&val, vm)? { - c - } else if let Some(s) = val.payload_if_subclass::(vm) { - if args.imag.is_present() { - return Err(vm.new_type_error( - "complex() can't take second arg if first is a string".to_owned(), - )); - } - let value = parse_str(s.as_str().trim()).ok_or_else(|| { - vm.new_value_error("complex() arg is a malformed string".to_owned()) - })?; - return Self::from(value).into_ref_with_type(vm, cls); - } else { - return Err(vm.new_type_error(format!( - "complex() first argument must be a string or a number, not '{}'", - val.class().name - ))); - } - } - }; - - let (imag, imag_was_complex) = match args.imag { - // Copy the imaginary from the real to the real of the imaginary - // if an imaginary argument is not passed in - OptionalArg::Missing => (Complex64::new(real.im, 0.0), false), - OptionalArg::Present(obj) => { - if let Some(c) = try_complex(&obj, vm)? { - c - } else if obj.class().issubclass(&vm.ctx.types.str_type) { - return Err( - vm.new_type_error("complex() second arg can't be a string".to_owned()) - ); - } else { - return Err(vm.new_type_error(format!( - "complex() second argument must be a number, not '{}'", - obj.class().name - ))); - } - } - }; - - let final_real = if imag_was_complex { - real.re - imag.im - } else { - real.re - }; - - let final_imag = if real_was_complex && !imag_missing { - imag.re + real.im - } else { - imag.re - }; - let value = Complex64::new(final_real, final_imag); - Self::from(value).into_ref_with_type(vm, cls) - } - #[pymethod(magic)] fn getnewargs(&self, vm: &VirtualMachine) -> PyObjectRef { let Complex64 { re, im } = self.value; @@ -377,7 +380,7 @@ impl Hashable for PyComplex { } #[derive(FromArgs)] -struct ComplexArgs { +pub struct ComplexArgs { #[pyarg(any, optional)] real: OptionalArg, #[pyarg(any, optional)] diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index b9c8e18d4..35ab231d4 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -54,8 +54,8 @@ impl PyValue for PyDict { #[pyimpl(with(Hashable, Comparable, Iterable), flags(BASETYPE))] impl PyDict { #[pyslot] - fn tp_new(class: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - PyDict::default().into_ref_with_type(vm, class) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + PyDict::default().into_pyresult_with_type(vm, cls) } #[pymethod(magic)] diff --git a/vm/src/builtins/enumerate.rs b/vm/src/builtins/enumerate.rs index 45c4f34bb..106bb30df 100644 --- a/vm/src/builtins/enumerate.rs +++ b/vm/src/builtins/enumerate.rs @@ -11,7 +11,7 @@ use super::iter::{ }; use super::pytype::PyTypeRef; use crate::function::OptionalArg; -use crate::slots::PyIter; +use crate::slots::{PyIter, SlotConstructor}; use crate::vm::VirtualMachine; use crate::{iterator, ItemProtocol, TypeProtocol}; use crate::{IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; @@ -30,17 +30,17 @@ impl PyValue for PyEnumerate { } #[derive(FromArgs)] -struct EnumerateArgs { +pub struct EnumerateArgs { #[pyarg(any)] iterable: PyObjectRef, #[pyarg(any, optional)] start: OptionalArg, } -#[pyimpl(with(PyIter), flags(BASETYPE))] -impl PyEnumerate { - #[pyslot] - fn tp_new(cls: PyTypeRef, args: EnumerateArgs, vm: &VirtualMachine) -> PyResult> { +impl SlotConstructor for PyEnumerate { + type Args = EnumerateArgs; + + fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { let counter = match args.start { OptionalArg::Present(start) => start.as_bigint().clone(), OptionalArg::Missing => BigInt::zero(), @@ -51,10 +51,13 @@ impl PyEnumerate { counter: PyRwLock::new(counter), iterator, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } +#[pyimpl(with(PyIter, SlotConstructor), flags(BASETYPE))] +impl PyEnumerate {} + impl PyIter for PyEnumerate { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let next_obj = iterator::call_next(vm, &zelf.iterator)?; diff --git a/vm/src/builtins/filter.rs b/vm/src/builtins/filter.rs index 82aa9d4d3..e9bbde7dc 100644 --- a/vm/src/builtins/filter.rs +++ b/vm/src/builtins/filter.rs @@ -1,7 +1,7 @@ use super::pybool; use super::pytype::PyTypeRef; use crate::iterator; -use crate::slots::PyIter; +use crate::slots::{PyIter, SlotConstructor}; use crate::vm::VirtualMachine; use crate::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; @@ -22,25 +22,35 @@ impl PyValue for PyFilter { } } -#[pyimpl(with(PyIter), flags(BASETYPE))] -impl PyFilter { - #[pyslot] - fn tp_new( +#[derive(FromArgs)] +pub struct FilterArgs { + #[pyarg(positional)] + function: PyObjectRef, + #[pyarg(positional)] + iterable: PyObjectRef, +} + +impl SlotConstructor for PyFilter { + type Args = FilterArgs; + + fn py_new( cls: PyTypeRef, - function: PyObjectRef, - iterable: PyObjectRef, + Self::Args { function, iterable }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let iterator = iterator::get_iter(vm, iterable)?; Self { predicate: function, iterator, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } +#[pyimpl(with(PyIter, SlotConstructor), flags(BASETYPE))] +impl PyFilter {} + impl PyIter for PyFilter { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let predicate = &zelf.predicate; diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index f2d0ad61a..163eba219 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -2,7 +2,7 @@ use super::{int, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyTypeRef}; use crate::common::{float_ops, hash}; use crate::format::FormatSpec; use crate::function::{OptionalArg, OptionalOption}; -use crate::slots::{Comparable, Hashable, PyComparisonOp}; +use crate::slots::{Comparable, Hashable, PyComparisonOp, SlotConstructor}; use crate::VirtualMachine; use crate::{ IdProtocol, IntoPyObject, @@ -154,20 +154,16 @@ pub fn float_pow(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult { } } -#[pyimpl(flags(BASETYPE), with(Comparable, Hashable))] -impl PyFloat { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - arg: OptionalArg, - vm: &VirtualMachine, - ) -> PyResult> { +impl SlotConstructor for PyFloat { + type Args = OptionalArg; + + fn py_new(cls: PyTypeRef, arg: Self::Args, vm: &VirtualMachine) -> PyResult { let float_val = match arg { OptionalArg::Missing => 0.0, OptionalArg::Present(val) => { let val = if cls.is(&vm.ctx.types.float_type) { match val.downcast_exact::(vm) { - Ok(f) => return Ok(f), + Ok(f) => return Ok(f.into_object()), Err(val) => val, } } else { @@ -195,9 +191,12 @@ impl PyFloat { } } }; - PyFloat::from(float_val).into_ref_with_type(vm, cls) + PyFloat::from(float_val).into_pyresult_with_type(vm, cls) } +} +#[pyimpl(flags(BASETYPE), with(Comparable, Hashable, SlotConstructor))] +impl PyFloat { #[pymethod(magic)] fn format(&self, spec: PyStrRef, vm: &VirtualMachine) -> PyResult { match FormatSpec::parse(spec.as_str()) diff --git a/vm/src/builtins/frame.rs b/vm/src/builtins/frame.rs index caa3a7ff9..f85a25e7d 100644 --- a/vm/src/builtins/frame.rs +++ b/vm/src/builtins/frame.rs @@ -5,7 +5,9 @@ use super::code::PyCodeRef; use super::dict::PyDictRef; use super::pystr::PyStrRef; +use crate::builtins::PyTypeRef; use crate::frame::{Frame, FrameRef}; +use crate::function::FuncArgs; use crate::vm::VirtualMachine; use crate::{IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult}; @@ -19,7 +21,7 @@ impl Frame {} #[pyimpl] impl FrameRef { #[pyslot] - fn tp_new(_cls: FrameRef, vm: &VirtualMachine) -> PyResult { + fn tp_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error("Cannot directly create frame object".to_owned())) } diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index a02f33262..0fcd84f93 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -14,7 +14,9 @@ use crate::common::lock::PyMutex; use crate::frame::Frame; use crate::function::{FuncArgs, OptionalArg}; use crate::scope::Scope; -use crate::slots::{Callable, Comparable, PyComparisonOp, SlotDescriptor, SlotGetattro}; +use crate::slots::{ + Callable, Comparable, PyComparisonOp, SlotConstructor, SlotDescriptor, SlotGetattro, +}; #[cfg(feature = "jit")] use crate::IntoPyObject; use crate::VirtualMachine; @@ -465,22 +467,35 @@ impl SlotGetattro for PyBoundMethod { } } -#[pyimpl(with(Callable, Comparable, SlotGetattro), flags(HAS_DICT))] +#[derive(FromArgs)] +pub struct PyBoundMethodNewArgs { + #[pyarg(positional)] + function: PyObjectRef, + #[pyarg(positional)] + object: PyObjectRef, +} + +impl SlotConstructor for PyBoundMethod { + type Args = PyBoundMethodNewArgs; + + fn py_new( + cls: PyTypeRef, + Self::Args { function, object }: Self::Args, + vm: &VirtualMachine, + ) -> PyResult { + PyBoundMethod::new(object, function).into_pyresult_with_type(vm, cls) + } +} + +#[pyimpl( + with(Callable, Comparable, SlotGetattro, SlotConstructor), + flags(HAS_DICT) +)] impl PyBoundMethod { pub fn new(object: PyObjectRef, function: PyObjectRef) -> Self { PyBoundMethod { object, function } } - #[pyslot] - fn tp_new( - cls: PyTypeRef, - function: PyObjectRef, - object: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - PyBoundMethod::new(object, function).into_ref_with_type(vm, cls) - } - #[pymethod(magic)] fn repr(&self, vm: &VirtualMachine) -> PyResult { let funcname = @@ -559,13 +574,16 @@ impl PyValue for PyCell { } } -#[pyimpl] -impl PyCell { - #[pyslot] - fn tp_new(cls: PyTypeRef, value: OptionalArg, vm: &VirtualMachine) -> PyResult> { - Self::new(value.into_option()).into_ref_with_type(vm, cls) - } +impl SlotConstructor for PyCell { + type Args = OptionalArg; + fn py_new(cls: PyTypeRef, value: Self::Args, vm: &VirtualMachine) -> PyResult { + Self::new(value.into_option()).into_pyresult_with_type(vm, cls) + } +} + +#[pyimpl(with(SlotConstructor))] +impl PyCell { pub fn new(contents: Option) -> Self { Self { contents: PyMutex::new(contents), diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 208ebd56c..39dee95c6 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -238,7 +238,7 @@ fn inner_truediv(i1: &BigInt, i2: &BigInt, vm: &VirtualMachine) -> PyResult { impl SlotConstructor for PyInt { type Args = IntOptions; - fn py_new(cls: PyTypeRef, options: IntOptions, vm: &VirtualMachine) -> PyResult { + fn py_new(cls: PyTypeRef, options: Self::Args, vm: &VirtualMachine) -> PyResult { let value = if let OptionalArg::Present(val) = options.val_options { if let OptionalArg::Present(base) = options.base { let base = vm diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index 4d7e29fb7..da5b72cfb 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -16,7 +16,7 @@ use super::PyInt; use crate::common::lock::{ PyMappedRwLockReadGuard, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard, }; -use crate::function::OptionalArg; +use crate::function::{FuncArgs, OptionalArg}; use crate::sequence::{self, SimpleSeq}; use crate::sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}; use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable}; @@ -397,12 +397,8 @@ impl PyList { } #[pyslot] - fn tp_new( - cls: PyTypeRef, - _iterable: OptionalArg, - vm: &VirtualMachine, - ) -> PyResult> { - PyList::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + PyList::default().into_pyresult_with_type(vm, cls) } #[pymethod(magic)] diff --git a/vm/src/builtins/map.rs b/vm/src/builtins/map.rs index d99b367df..35498a7f4 100644 --- a/vm/src/builtins/map.rs +++ b/vm/src/builtins/map.rs @@ -1,7 +1,7 @@ use super::pytype::PyTypeRef; use crate::function::Args; use crate::iterator; -use crate::slots::PyIter; +use crate::slots::{PyIter, SlotConstructor}; use crate::vm::VirtualMachine; use crate::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; @@ -22,15 +22,10 @@ impl PyValue for PyMap { } } -#[pyimpl(with(PyIter), flags(BASETYPE))] -impl PyMap { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - function: PyObjectRef, - iterables: Args, - vm: &VirtualMachine, - ) -> PyResult> { +impl SlotConstructor for PyMap { + type Args = (PyObjectRef, Args); + + fn py_new(cls: PyTypeRef, (function, iterables): Self::Args, vm: &VirtualMachine) -> PyResult { let iterators = iterables .into_iter() .map(|iterable| iterator::get_iter(vm, iterable)) @@ -39,10 +34,12 @@ impl PyMap { mapper: function, iterators, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } +} - /// Return an estimate of the number of items. +#[pyimpl(with(PyIter, SlotConstructor), flags(BASETYPE))] +impl PyMap { #[pymethod(magic)] fn length_hint(&self, vm: &VirtualMachine) -> PyResult { self.iterators.iter().try_fold(0, |prev, cur| { diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 1d78da758..6a13fffba 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -3,7 +3,7 @@ use super::pystr::PyStrRef; use super::pytype::PyTypeRef; use crate::function::OptionalArg; use crate::iterator; -use crate::slots::Iterable; +use crate::slots::{Iterable, SlotConstructor}; use crate::vm::VirtualMachine; use crate::{ IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, @@ -36,16 +36,19 @@ impl PyMappingProxy { } } -#[pyimpl(with(Iterable))] -impl PyMappingProxy { - #[pyslot] - fn tp_new(cls: PyTypeRef, mapping: PyObjectRef, vm: &VirtualMachine) -> PyResult> { +impl SlotConstructor for PyMappingProxy { + type Args = PyObjectRef; + + fn py_new(cls: PyTypeRef, mapping: Self::Args, vm: &VirtualMachine) -> PyResult { Self { mapping: MappingProxyInner::Dict(mapping), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } +} +#[pyimpl(with(Iterable, SlotConstructor))] +impl PyMappingProxy { fn get_inner(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult> { let opt = match &self.mapping { MappingProxyInner::Class(class) => { diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 0e3fba0c7..e0166256b 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -10,7 +10,7 @@ use crate::common::hash::PyHash; use crate::common::lock::OnceCell; use crate::function::{FuncArgs, OptionalArg}; use crate::sliceable::{convert_slice, saturate_range, wrap_index, SequenceIndex}; -use crate::slots::{AsBuffer, Comparable, Hashable, PyComparisonOp}; +use crate::slots::{AsBuffer, Comparable, Hashable, PyComparisonOp, SlotConstructor}; use crate::stdlib::pystruct::_struct::FormatSpec; use crate::utils::Either; use crate::{ @@ -25,7 +25,7 @@ use num_traits::{One, Signed, ToPrimitive, Zero}; use std::fmt::Debug; #[derive(FromArgs)] -struct PyMemoryViewNewArgs { +pub struct PyMemoryViewNewArgs { #[pyarg(any)] object: PyObjectRef, } @@ -49,9 +49,19 @@ pub struct PyMemoryView { hash: OnceCell, } +impl SlotConstructor for PyMemoryView { + type Args = PyMemoryViewNewArgs; + + fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + let buffer = PyBufferRef::try_from_borrowed_object(vm, &args.object)?; + let zelf = PyMemoryView::from_buffer(args.object, buffer, vm)?; + zelf.into_pyresult_with_type(vm, cls) + } +} + type PyMemoryViewRef = PyRef; -#[pyimpl(with(Hashable, Comparable, AsBuffer))] +#[pyimpl(with(Hashable, Comparable, AsBuffer, SlotConstructor))] impl PyMemoryView { fn parse_format(format: &str, vm: &VirtualMachine) -> PyResult { FormatSpec::parse(format, vm) @@ -116,17 +126,6 @@ impl PyMemoryView { }) } - #[pyslot] - fn tp_new( - cls: PyTypeRef, - args: PyMemoryViewNewArgs, - vm: &VirtualMachine, - ) -> PyResult> { - let buffer = PyBufferRef::try_from_borrowed_object(vm, &args.object)?; - let zelf = PyMemoryView::from_buffer(args.object, buffer, vm)?; - zelf.into_ref_with_type(vm, cls) - } - #[pymethod] fn release(&self) { // avoid double release diff --git a/vm/src/builtins/module.rs b/vm/src/builtins/module.rs index e273eb11b..ee8762ebb 100644 --- a/vm/src/builtins/module.rs +++ b/vm/src/builtins/module.rs @@ -53,8 +53,8 @@ struct ModuleInitArgs { #[pyimpl(with(SlotGetattro), flags(BASETYPE, HAS_DICT))] impl PyModule { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - PyModule {}.into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + PyModule {}.into_pyresult_with_type(vm, cls) } #[pymethod(magic)] diff --git a/vm/src/builtins/namespace.rs b/vm/src/builtins/namespace.rs index b86180357..dbd3f3aba 100644 --- a/vm/src/builtins/namespace.rs +++ b/vm/src/builtins/namespace.rs @@ -1,7 +1,8 @@ use super::pytype::PyTypeRef; use crate::function::KwArgs; +use crate::slots::SlotConstructor; use crate::vm::VirtualMachine; -use crate::{PyClassImpl, PyContext, PyRef, PyResult, PyValue}; +use crate::{IntoPyObject, PyClassImpl, PyContext, PyResult, PyValue}; /// A simple attribute-based namespace. /// @@ -16,18 +17,21 @@ impl PyValue for PyNamespace { } } -#[pyimpl(flags(BASETYPE, HAS_DICT))] -impl PyNamespace { - #[pyslot] - fn tp_new(cls: PyTypeRef, kwargs: KwArgs, vm: &VirtualMachine) -> PyResult> { +impl SlotConstructor for PyNamespace { + type Args = KwArgs; + + fn py_new(cls: PyTypeRef, kwargs: Self::Args, vm: &VirtualMachine) -> PyResult { let zelf = PyNamespace.into_ref_with_type(vm, cls)?; for (name, value) in kwargs.into_iter() { vm.set_attr(zelf.as_object(), name, value)?; } - Ok(zelf) + Ok(zelf.into_pyobject(vm)) } } +#[pyimpl(flags(BASETYPE, HAS_DICT), with(SlotConstructor))] +impl PyNamespace {} + pub fn init(context: &PyContext) { PyNamespace::extend_class(context, &context.types.namespace_type); } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 9fdf2999e..5d05bce32 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -11,7 +11,7 @@ use crate::utils::Either; use crate::vm::VirtualMachine; use crate::{ IdProtocol, ItemProtocol, PyArithmaticValue, PyAttributes, PyClassImpl, PyComparisonValue, - PyContext, PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol, + PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol, }; /// object() @@ -35,9 +35,8 @@ impl PyValue for PyBaseObject { impl PyBaseObject { /// Create and return a new object. See help(type) for accurate signature. #[pyslot] - fn tp_new(mut args: FuncArgs, vm: &VirtualMachine) -> PyResult { + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { // more or less __new__ operator - let cls = PyTypeRef::try_from_object(vm, args.shift())?; let dict = if cls.is(&vm.ctx.types.object_type) { None } else { diff --git a/vm/src/builtins/property.rs b/vm/src/builtins/property.rs index 513b5e1d2..699db7257 100644 --- a/vm/src/builtins/property.rs +++ b/vm/src/builtins/property.rs @@ -91,14 +91,14 @@ impl SlotDescriptor for PyProperty { #[pyimpl(with(SlotDescriptor), flags(BASETYPE))] impl PyProperty { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { PyProperty { getter: PyRwLock::new(None), setter: PyRwLock::new(None), deleter: PyRwLock::new(None), doc: PyRwLock::new(None), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } #[pymethod(magic)] diff --git a/vm/src/builtins/pybool.rs b/vm/src/builtins/pybool.rs index 6c5821c0b..abe8aa24e 100644 --- a/vm/src/builtins/pybool.rs +++ b/vm/src/builtins/pybool.rs @@ -3,12 +3,15 @@ use num_traits::Zero; use super::int::PyInt; use super::pystr::PyStrRef; +use crate::builtins::PyTypeRef; use crate::function::OptionalArg; +use crate::slots::SlotConstructor; use crate::vm::VirtualMachine; use crate::{ - IdProtocol, IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyResult, TryFromBorrowedObject, - TryFromObject, TypeProtocol, + IdProtocol, IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, + TryFromBorrowedObject, TryFromObject, TypeProtocol, }; +use std::fmt::{Debug, Formatter}; impl IntoPyObject for bool { fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { @@ -79,7 +82,38 @@ pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { #[pyclass(name = "bool", module = false, base = "PyInt")] pub struct PyBool; -#[pyimpl] +impl PyValue for PyBool { + fn class(vm: &VirtualMachine) -> &PyTypeRef { + &vm.ctx.types.bool_type + } +} + +impl Debug for PyBool { + fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +impl SlotConstructor for PyBool { + type Args = OptionalArg; + + fn py_new(zelf: PyTypeRef, x: Self::Args, vm: &VirtualMachine) -> PyResult { + if !zelf.isinstance(&vm.ctx.types.type_type) { + let actual_type = &zelf.class().name; + return Err(vm.new_type_error(format!( + "requires a 'type' object but received a '{}'", + actual_type + ))); + } + let val = match x { + OptionalArg::Present(val) => boolval(vm, val)?, + OptionalArg::Missing => false, + }; + Ok(vm.ctx.new_bool(val)) + } +} + +#[pyimpl(with(SlotConstructor))] impl PyBool { #[pymethod(magic)] fn repr(zelf: bool) -> String { @@ -130,22 +164,6 @@ impl PyBool { get_py_int(&lhs).xor(rhs, vm).into_pyobject(vm) } } - - #[pyslot] - fn tp_new(zelf: PyObjectRef, x: OptionalArg, vm: &VirtualMachine) -> PyResult { - if !zelf.isinstance(&vm.ctx.types.type_type) { - let actual_type = &zelf.class().name; - return Err(vm.new_type_error(format!( - "requires a 'type' object but received a '{}'", - actual_type - ))); - } - let val = match x { - OptionalArg::Present(val) => boolval(vm, val)?, - OptionalArg::Missing => false, - }; - Ok(vm.ctx.new_bool(val)) - } } pub(crate) fn init(context: &PyContext) { diff --git a/vm/src/builtins/pystr.rs b/vm/src/builtins/pystr.rs index 09a1197e2..4fc384ef8 100644 --- a/vm/src/builtins/pystr.rs +++ b/vm/src/builtins/pystr.rs @@ -24,7 +24,7 @@ use crate::exceptions::IntoPyException; use crate::format::{FormatSpec, FormatString, FromTemplate}; use crate::function::{FuncArgs, OptionalArg, OptionalOption}; use crate::sliceable::PySliceableSequence; -use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter}; +use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, SlotConstructor}; use crate::utils::Either; use crate::VirtualMachine; use crate::{ @@ -203,7 +203,7 @@ impl PyIter for PyStrIterator { } #[derive(FromArgs)] -struct StrArgs { +pub struct StrArgs { #[pyarg(any, optional)] object: OptionalArg, #[pyarg(any, optional)] @@ -212,10 +212,10 @@ struct StrArgs { errors: OptionalArg, } -#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))] -impl PyStr { - #[pyslot] - fn tp_new(cls: PyTypeRef, args: StrArgs, vm: &VirtualMachine) -> PyResult { +impl SlotConstructor for PyStr { + type Args = StrArgs; + + fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { let string: PyStrRef = match args.object { OptionalArg::Present(input) => { if let OptionalArg::Present(enc) = args.encoding { @@ -234,12 +234,15 @@ impl PyStr { } }; if string.class().is(&cls) { - Ok(string) + Ok(string.into_object()) } else { - PyStr::from(string.as_str()).into_ref_with_type(vm, cls) + PyStr::from(string.as_str()).into_pyresult_with_type(vm, cls) } } +} +#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable, SlotConstructor))] +impl PyStr { #[pymethod(magic)] fn add(zelf: PyRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if let Some(other) = other.payload::() { diff --git a/vm/src/builtins/pysuper.rs b/vm/src/builtins/pysuper.rs index e71bf525b..67aa7af18 100644 --- a/vm/src/builtins/pysuper.rs +++ b/vm/src/builtins/pysuper.rs @@ -9,7 +9,7 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/ use super::pystr::PyStrRef; use super::pytype::{PyType, PyTypeRef}; use crate::function::OptionalArg; -use crate::slots::{SlotDescriptor, SlotGetattro}; +use crate::slots::{SlotConstructor, SlotDescriptor, SlotGetattro}; use crate::vm::VirtualMachine; use crate::{ IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, @@ -28,34 +28,22 @@ impl PyValue for PySuper { } } -#[pyimpl(with(SlotGetattro, SlotDescriptor))] -impl PySuper { - fn new(typ: PyTypeRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let obj = if vm.is_none(&obj) { - None - } else { - let obj_type = supercheck(typ.clone(), obj.clone(), vm)?; - Some((obj, obj_type)) - }; - Ok(Self { typ, obj }) - } +#[derive(FromArgs)] +pub struct PySuperNewArgs { + #[pyarg(positional, optional)] + py_type: OptionalArg, + #[pyarg(positional, optional)] + py_obj: OptionalArg, +} - #[pymethod(magic)] - fn repr(&self) -> String { - let typname = &self.typ.name; - match self.obj { - Some((_, ref ty)) => format!(", <{} object>>", typname, ty.name), - None => format!(", NULL>", typname), - } - } +impl SlotConstructor for PySuper { + type Args = PySuperNewArgs; - #[pyslot] - fn tp_new( + fn py_new( cls: PyTypeRef, - py_type: OptionalArg, - py_obj: OptionalArg, + Self::Args { py_type, py_obj }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { // Get the type: let (typ, obj) = if let OptionalArg::Present(ty) = py_type { (ty, py_obj.unwrap_or_none(vm)) @@ -107,7 +95,29 @@ impl PySuper { (typ, obj) }; - PySuper::new(typ, obj, vm)?.into_ref_with_type(vm, cls) + PySuper::new(typ, obj, vm)?.into_pyresult_with_type(vm, cls) + } +} + +#[pyimpl(with(SlotGetattro, SlotDescriptor, SlotConstructor))] +impl PySuper { + fn new(typ: PyTypeRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let obj = if vm.is_none(&obj) { + None + } else { + let obj_type = supercheck(typ.clone(), obj.clone(), vm)?; + Some((obj, obj_type)) + }; + Ok(Self { typ, obj }) + } + + #[pymethod(magic)] + fn repr(&self) -> String { + let typname = &self.typ.name; + match self.obj { + Some((_, ref ty)) => format!(", <{} object>>", typname, ty.name), + None => format!(", NULL>", typname), + } } } diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/pytype.rs index df286c2c0..0b681500f 100644 --- a/vm/src/builtins/pytype.rs +++ b/vm/src/builtins/pytype.rs @@ -405,7 +405,7 @@ impl PyType { ) } #[pyslot] - fn tp_new(metatype: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult { + fn tp_new(metatype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { vm_trace!("type.__new__ {:?}", args); let is_type_type = metatype.is(&vm.ctx.types.type_type); diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 7017f120a..8d04ebf8f 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -362,12 +362,12 @@ impl PyRange { } #[pyslot] - fn tp_new(args: FuncArgs, vm: &VirtualMachine) -> PyResult { - let range = if args.args.len() <= 2 { - let (cls, stop) = args.bind(vm)?; + fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let range = if args.args.len() <= 1 { + let stop = args.bind(vm)?; PyRange::new(cls, stop, vm) } else { - let (cls, start, stop, step) = args.bind(vm)?; + let (start, stop, step) = args.bind(vm)?; PyRange::new_from(cls, start, stop, step, vm) }?; diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index 185c32384..ba7d768cf 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -4,9 +4,12 @@ use super::{pytype::PyTypeRef, IterStatus, PyDictRef}; use crate::common::hash::PyHash; use crate::common::rc::PyRc; -use crate::dictdatatype::{self, DictSize}; +use crate::dictdatatype; +use crate::dictdatatype::DictSize; use crate::function::{Args, FuncArgs, OptionalArg}; -use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable}; +use crate::slots::{ + Comparable, Hashable, Iterable, PyComparisonOp, PyIter, SlotConstructor, Unhashable, +}; use crate::vm::{ReprGuard, VirtualMachine}; use crate::{ IdProtocol, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, @@ -359,8 +362,8 @@ macro_rules! multi_args_set { #[pyimpl(with(Hashable, Comparable, Iterable), flags(BASETYPE))] impl PySet { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - PySet::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + PySet::default().into_pyresult_with_type(vm, cls) } #[pymethod(magic)] @@ -595,30 +598,14 @@ macro_rules! multi_args_frozenset { }}; } -#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))] -impl PyFrozenSet { - // Also used by ssl.rs windows. - pub(crate) fn from_iter( - vm: &VirtualMachine, - it: impl IntoIterator, - ) -> PyResult { - let inner = PySetInner::default(); - for elem in it { - inner.add(elem, vm)?; - } - Ok(Self { inner }) - } +impl SlotConstructor for PyFrozenSet { + type Args = OptionalArg; - #[pyslot] - fn tp_new( - cls: PyTypeRef, - iterable: OptionalArg, - vm: &VirtualMachine, - ) -> PyResult> { + fn py_new(cls: PyTypeRef, iterable: Self::Args, vm: &VirtualMachine) -> PyResult { let elements = if let OptionalArg::Present(iterable) = iterable { let iterable = if cls.is(&vm.ctx.types.frozenset_type) { match iterable.downcast_exact::(vm) { - Ok(fs) => return Ok(fs), + Ok(fs) => return Ok(fs.into_object()), Err(iterable) => iterable, } } else { @@ -631,11 +618,26 @@ impl PyFrozenSet { // Return empty fs if iterable passed is empty and only for exact fs types. if elements.is_empty() && cls.is(&vm.ctx.types.frozenset_type) { - Ok(vm.ctx.empty_frozenset.clone()) + Ok(vm.ctx.empty_frozenset.clone().into_object()) } else { - Self::from_iter(vm, elements).and_then(|o| o.into_ref_with_type(vm, cls)) + Self::from_iter(vm, elements).and_then(|o| o.into_pyresult_with_type(vm, cls)) } } +} + +#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable, SlotConstructor))] +impl PyFrozenSet { + // Also used by ssl.rs windows. + pub(crate) fn from_iter( + vm: &VirtualMachine, + it: impl IntoIterator, + ) -> PyResult { + let inner = PySetInner::default(); + for elem in it { + inner.add(elem, vm)?; + } + Ok(Self { inner }) + } #[pymethod(magic)] fn len(&self) -> usize { diff --git a/vm/src/builtins/singletons.rs b/vm/src/builtins/singletons.rs index d43a822cb..e1a1fcd55 100644 --- a/vm/src/builtins/singletons.rs +++ b/vm/src/builtins/singletons.rs @@ -1,6 +1,9 @@ use super::pytype::PyTypeRef; +use crate::slots::SlotConstructor; use crate::vm::VirtualMachine; -use crate::{IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyValue, TypeProtocol}; +use crate::{ + IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, +}; #[pyclass(module = false, name = "NoneType")] #[derive(Debug)] @@ -30,13 +33,16 @@ impl IntoPyObject for Option { } } -#[pyimpl] -impl PyNone { - #[pyslot] - fn tp_new(_: PyTypeRef, vm: &VirtualMachine) -> PyRef { - vm.ctx.none.clone() - } +impl SlotConstructor for PyNone { + type Args = (); + fn py_new(_: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + Ok(vm.ctx.none.clone().into_object()) + } +} + +#[pyimpl(with(SlotConstructor))] +impl PyNone { #[pymethod(magic)] fn repr(&self) -> String { "None".to_owned() @@ -59,13 +65,16 @@ impl PyValue for PyNotImplemented { } } -#[pyimpl] -impl PyNotImplemented { - #[pyslot] - fn tp_new(_: PyTypeRef, vm: &VirtualMachine) -> PyRef { - vm.ctx.not_implemented.clone() - } +impl SlotConstructor for PyNotImplemented { + type Args = (); + fn py_new(_: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + Ok(vm.ctx.not_implemented.clone().into_object()) + } +} + +#[pyimpl(with(SlotConstructor))] +impl PyNotImplemented { // TODO: As per https://bugs.python.org/issue35712, using NotImplemented // in boolean contexts will need to raise a DeprecationWarning in 3.9 // and, eventually, a TypeError. diff --git a/vm/src/builtins/slice.rs b/vm/src/builtins/slice.rs index f94914b7a..017082336 100644 --- a/vm/src/builtins/slice.rs +++ b/vm/src/builtins/slice.rs @@ -3,7 +3,7 @@ use super::int::{PyInt, PyIntRef}; use super::pytype::PyTypeRef; use crate::function::{FuncArgs, OptionalArg}; -use crate::slots::{Comparable, Hashable, PyComparisonOp, Unhashable}; +use crate::slots::{Comparable, Hashable, PyComparisonOp, SlotConstructor, Unhashable}; use crate::VirtualMachine; use crate::{ IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, @@ -94,7 +94,7 @@ impl PySlice { } #[pyslot] - fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { let slice: PySlice = match args.args.len() { 0 => { return Err( @@ -119,7 +119,7 @@ impl PySlice { } } }; - slice.into_ref_with_type(vm, cls) + slice.into_pyresult_with_type(vm, cls) } pub(crate) fn inner_indices( @@ -293,13 +293,16 @@ impl PyValue for PyEllipsis { } } -#[pyimpl] -impl PyEllipsis { - #[pyslot] - fn tp_new(_cls: PyTypeRef, vm: &VirtualMachine) -> PyRef { - vm.ctx.ellipsis.clone() - } +impl SlotConstructor for PyEllipsis { + type Args = (); + fn py_new(_cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + Ok(vm.ctx.ellipsis.clone().into_object()) + } +} + +#[pyimpl(with(SlotConstructor))] +impl PyEllipsis { #[pymethod(magic)] fn repr(&self) -> String { "Ellipsis".to_owned() diff --git a/vm/src/builtins/staticmethod.rs b/vm/src/builtins/staticmethod.rs index c5a20c1fa..95856f495 100644 --- a/vm/src/builtins/staticmethod.rs +++ b/vm/src/builtins/staticmethod.rs @@ -1,7 +1,7 @@ use super::pytype::PyTypeRef; -use crate::slots::SlotDescriptor; +use crate::slots::{SlotConstructor, SlotDescriptor}; use crate::vm::VirtualMachine; -use crate::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; +use crate::{PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue}; #[pyclass(module = false, name = "staticmethod")] #[derive(Clone, Debug)] @@ -33,14 +33,17 @@ impl From for PyStaticMethod { } } -#[pyimpl(with(SlotDescriptor), flags(BASETYPE, HAS_DICT))] -impl PyStaticMethod { - #[pyslot] - fn tp_new(cls: PyTypeRef, callable: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - PyStaticMethod { callable }.into_ref_with_type(vm, cls) +impl SlotConstructor for PyStaticMethod { + type Args = PyObjectRef; + + fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult { + PyStaticMethod { callable }.into_pyresult_with_type(vm, cls) } } +#[pyimpl(with(SlotDescriptor, SlotConstructor), flags(BASETYPE, HAS_DICT))] +impl PyStaticMethod {} + pub fn init(context: &PyContext) { PyStaticMethod::extend_class(context, &context.types.staticmethod_type); } diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 52429c7c5..9e29a63b5 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -15,7 +15,7 @@ use crate::common::hash::PyHash; use crate::function::OptionalArg; use crate::sequence::{self, SimpleSeq}; use crate::sliceable::PySliceableSequence; -use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter}; +use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, SlotConstructor}; use crate::utils::Either; use crate::vm::{ReprGuard, VirtualMachine}; use crate::{ @@ -83,7 +83,36 @@ impl PyTupleRef { } } -#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))] +impl SlotConstructor for PyTuple { + type Args = OptionalArg; + + fn py_new(cls: PyTypeRef, iterable: Self::Args, vm: &VirtualMachine) -> PyResult { + let elements = if let OptionalArg::Present(iterable) = iterable { + let iterable = if cls.is(&vm.ctx.types.tuple_type) { + match iterable.downcast_exact::(vm) { + Ok(tuple) => return Ok(tuple.into_object()), + Err(iterable) => iterable, + } + } else { + iterable + }; + vm.extract_elements(&iterable)? + } else { + vec![] + }; + // Return empty tuple only for exact tuple types if the iterable is empty. + if elements.is_empty() && cls.is(&vm.ctx.types.tuple_type) { + Ok(vm.ctx.empty_tuple.clone().into_object()) + } else { + Self { + elements: elements.into_boxed_slice(), + } + .into_pyresult_with_type(vm, cls) + } + } +} + +#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable, SlotConstructor))] impl PyTuple { /// Creating a new tuple with given boxed slice. /// NOTE: for usual case, you probably want to use PyTupleRef::with_elements. @@ -254,36 +283,6 @@ impl PyTuple { }; (tup_arg,) } - - #[pyslot] - fn tp_new( - cls: PyTypeRef, - iterable: OptionalArg, - vm: &VirtualMachine, - ) -> PyResult> { - let elements = if let OptionalArg::Present(iterable) = iterable { - let iterable = if cls.is(&vm.ctx.types.tuple_type) { - match iterable.downcast_exact::(vm) { - Ok(tuple) => return Ok(tuple), - Err(iterable) => iterable, - } - } else { - iterable - }; - vm.extract_elements(&iterable)? - } else { - vec![] - }; - // Return empty tuple only for exact tuple types if the iterable is empty. - if elements.is_empty() && cls.is(&vm.ctx.types.tuple_type) { - Ok(vm.ctx.empty_tuple.clone()) - } else { - Self { - elements: elements.into_boxed_slice(), - } - .into_ref_with_type(vm, cls) - } - } } impl Hashable for PyTuple { diff --git a/vm/src/builtins/weakproxy.rs b/vm/src/builtins/weakproxy.rs index 89f3ffd27..54f805ed5 100644 --- a/vm/src/builtins/weakproxy.rs +++ b/vm/src/builtins/weakproxy.rs @@ -2,7 +2,7 @@ use super::pytype::PyTypeRef; use super::weakref::PyWeak; use super::PyStrRef; use crate::function::OptionalArg; -use crate::slots::SlotSetattro; +use crate::slots::{SlotConstructor, SlotSetattro}; use crate::vm::VirtualMachine; use crate::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; @@ -18,25 +18,35 @@ impl PyValue for PyWeakProxy { } } -#[pyimpl(with(SlotSetattro))] -impl PyWeakProxy { - // TODO: callbacks - #[pyslot] - fn tp_new( +#[derive(FromArgs)] +pub struct WeakProxyNewArgs { + #[pyarg(positional)] + referent: PyObjectRef, + #[pyarg(positional, optional)] + callback: OptionalArg, +} + +impl SlotConstructor for PyWeakProxy { + type Args = WeakProxyNewArgs; + + fn py_new( cls: PyTypeRef, - referent: PyObjectRef, - callback: OptionalArg, + Self::Args { referent, callback }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { if callback.is_present() { panic!("Passed a callback to weakproxy, but weakproxy does not yet support proxies."); } PyWeakProxy { weak: PyWeak::downgrade(&referent), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } +} +#[pyimpl(with(SlotSetattro, SlotConstructor))] +impl PyWeakProxy { + // TODO: callbacks #[pymethod(magic)] fn getattr(&self, attr_name: PyObjectRef, vm: &VirtualMachine) -> PyResult { match self.weak.upgrade() { diff --git a/vm/src/builtins/weakref.rs b/vm/src/builtins/weakref.rs index 17186b500..15453970a 100644 --- a/vm/src/builtins/weakref.rs +++ b/vm/src/builtins/weakref.rs @@ -1,7 +1,7 @@ use super::pytype::PyTypeRef; use crate::common::hash::PyHash; use crate::function::{FuncArgs, OptionalArg}; -use crate::slots::{Callable, Comparable, Hashable, PyComparisonOp}; +use crate::slots::{Callable, Comparable, Hashable, PyComparisonOp, SlotConstructor}; use crate::vm::VirtualMachine; use crate::{ IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyObjectWeak, PyRef, PyResult, PyValue, @@ -30,6 +30,14 @@ impl PyWeak { } } +#[derive(FromArgs)] +pub struct WeakNewArgs { + #[pyarg(positional)] + referent: PyObjectRef, + #[pyarg(positional, optional)] + _callback: OptionalArg, +} + impl PyValue for PyWeak { fn class(vm: &VirtualMachine) -> &PyTypeRef { &vm.ctx.types.weakref_type @@ -43,19 +51,24 @@ impl Callable for PyWeak { } } -#[pyimpl(with(Callable, Hashable, Comparable), flags(BASETYPE))] -impl PyWeak { - // TODO callbacks - #[pyslot] - fn tp_new( - cls: PyTypeRef, - referent: PyObjectRef, - _callback: OptionalArg, - vm: &VirtualMachine, - ) -> PyResult> { - PyWeak::downgrade(&referent).into_ref_with_type(vm, cls) - } +impl SlotConstructor for PyWeak { + type Args = WeakNewArgs; + // TODO callbacks + fn py_new( + cls: PyTypeRef, + Self::Args { + referent, + _callback, + }: Self::Args, + vm: &VirtualMachine, + ) -> PyResult { + PyWeak::downgrade(&referent).into_pyresult_with_type(vm, cls) + } +} + +#[pyimpl(with(Callable, Hashable, Comparable, SlotConstructor), flags(BASETYPE))] +impl PyWeak { #[pymethod(magic)] fn repr(zelf: PyRef) -> String { let id = zelf.get_id(); diff --git a/vm/src/builtins/zip.rs b/vm/src/builtins/zip.rs index 8a7795d69..fa4da39da 100644 --- a/vm/src/builtins/zip.rs +++ b/vm/src/builtins/zip.rs @@ -1,12 +1,10 @@ use super::pytype::PyTypeRef; use crate::function::Args; use crate::iterator; -use crate::slots::PyIter; +use crate::slots::{PyIter, SlotConstructor}; use crate::vm::VirtualMachine; use crate::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; -pub type PyZipRef = PyRef; - #[pyclass(module = false, name = "zip")] #[derive(Debug)] pub struct PyZip { @@ -19,18 +17,21 @@ impl PyValue for PyZip { } } -#[pyimpl(with(PyIter), flags(BASETYPE))] -impl PyZip { - #[pyslot] - fn tp_new(cls: PyTypeRef, iterables: Args, vm: &VirtualMachine) -> PyResult { +impl SlotConstructor for PyZip { + type Args = Args; + + fn py_new(cls: PyTypeRef, iterables: Self::Args, vm: &VirtualMachine) -> PyResult { let iterators = iterables .into_iter() .map(|iterable| iterator::get_iter(vm, iterable)) .collect::, _>>()?; - PyZip { iterators }.into_ref_with_type(vm, cls) + PyZip { iterators }.into_pyresult_with_type(vm, cls) } } +#[pyimpl(with(PyIter, SlotConstructor), flags(BASETYPE))] +impl PyZip {} + impl PyIter for PyZip { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { if zelf.iterators.is_empty() { diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 90a130fc2..b3a1e99c4 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -63,12 +63,8 @@ impl PyBaseException { } #[pyslot] - pub(crate) fn tp_new( - cls: PyTypeRef, - args: FuncArgs, - vm: &VirtualMachine, - ) -> PyResult> { - PyBaseException::new(args.args, vm).into_ref_with_type(vm, cls) + pub(crate) fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + PyBaseException::new(args.args, vm).into_pyresult_with_type(vm, cls) } #[pymethod(magic)] @@ -555,11 +551,7 @@ macro_rules! extends_exception { #[pyimpl(flags(BASETYPE, HAS_DICT))] impl $class_name { #[pyslot] - fn tp_new( - cls: PyTypeRef, - args: FuncArgs, - vm: &VirtualMachine, - ) -> PyResult> { + fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // We need this method, because of how `CPython` copies `init` // from `BaseException` in `SimpleExtendsException` macro. // See: `BaseException_new` diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index ea66d3db2..d93e43f11 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1016,6 +1016,10 @@ pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static { ))) } } + + fn into_pyresult_with_type(self, vm: &VirtualMachine, cls: PyTypeRef) -> PyResult { + self.into_ref_with_type(vm, cls).into_pyresult(vm) + } } pub trait PyObjectPayload: Any + fmt::Debug + PyThreadingConstraint + 'static {} diff --git a/vm/src/stdlib/array.rs b/vm/src/stdlib/array.rs index 5ed78c649..bc8cca896 100644 --- a/vm/src/stdlib/array.rs +++ b/vm/src/stdlib/array.rs @@ -26,7 +26,7 @@ mod array { use crate::sliceable::{ saturate_index, PySliceableSequence, PySliceableSequenceMut, SequenceIndex, }; - use crate::slots::{AsBuffer, Comparable, Iterable, PyComparisonOp, PyIter}; + use crate::slots::{AsBuffer, Comparable, Iterable, PyComparisonOp, PyIter, SlotConstructor}; use crate::stdlib::array::wchar_t; use crate::{ IdProtocol, IntoPyObject, PyComparisonValue, PyIterable, PyObjectRef, PyRef, PyResult, @@ -612,23 +612,22 @@ mod array { } } - #[pyimpl(flags(BASETYPE), with(Comparable, AsBuffer, Iterable))] - impl PyArray { - fn read(&self) -> PyRwLockReadGuard<'_, ArrayContentType> { - self.array.read() - } + #[derive(FromArgs)] + pub struct ArrayNewArgs { + #[pyarg(positional)] + spec: PyStrRef, + #[pyarg(positional, optional)] + init: OptionalArg, + } - fn write(&self) -> PyRwLockWriteGuard<'_, ArrayContentType> { - self.array.write() - } + impl SlotConstructor for PyArray { + type Args = ArrayNewArgs; - #[pyslot] - fn tp_new( + fn py_new( cls: PyTypeRef, - spec: PyStrRef, - init: OptionalArg, + Self::Args { spec, init }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let spec = spec.as_str().chars().exactly_one().map_err(|_| { vm.new_type_error( "array() argument 1 must be a unicode character, not str".to_owned(), @@ -675,7 +674,18 @@ mod array { } let zelf = Self::from(array).into_ref_with_type(vm, cls)?; - Ok(zelf) + Ok(zelf.into_object()) + } + } + + #[pyimpl(flags(BASETYPE), with(Comparable, AsBuffer, Iterable, SlotConstructor))] + impl PyArray { + fn read(&self) -> PyRwLockReadGuard<'_, ArrayContentType> { + self.array.read() + } + + fn write(&self) -> PyRwLockWriteGuard<'_, ArrayContentType> { + self.array.write() } #[pyproperty] diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index 6a08e2910..86894c3ed 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -4,7 +4,9 @@ pub(crate) use _collections::make_module; mod _collections { use crate::common::lock::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; use crate::function::{FuncArgs, KwArgs, OptionalArg}; - use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable}; + use crate::slots::{ + Comparable, Hashable, Iterable, PyComparisonOp, PyIter, SlotConstructor, Unhashable, + }; use crate::vm::ReprGuard; use crate::VirtualMachine; use crate::{ @@ -78,8 +80,8 @@ mod _collections { #[pyimpl(flags(BASETYPE), with(Comparable, Hashable, Iterable))] impl PyDeque { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - PyDeque::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + PyDeque::default().into_pyresult_with_type(vm, cls) } #[pymethod(name = "__init__")] @@ -589,24 +591,14 @@ mod _collections { index: OptionalArg, } - #[pyimpl(with(PyIter))] - impl PyDequeIterator { - pub(crate) fn new(deque: PyDequeRef) -> Self { - PyDequeIterator { - position: AtomicCell::new(0), - status: AtomicCell::new(IterStatus::Active), - length: deque.len(), - deque, - } - } + impl SlotConstructor for PyDequeIterator { + type Args = (DequeIterArgs, KwArgs); - #[pyslot] - fn tp_new( + fn py_new( cls: PyTypeRef, - DequeIterArgs { deque, index }: DequeIterArgs, - _kwargs: KwArgs, + (DequeIterArgs { deque, index }, _kwargs): Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let len = deque.len(); let iter = PyDequeIterator::new(deque); if let OptionalArg::Present(index) = index { @@ -617,7 +609,19 @@ mod _collections { iter.status.store(Exhausted); } } - iter.into_ref_with_type(vm, cls) + iter.into_pyresult_with_type(vm, cls) + } + } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyDequeIterator { + pub(crate) fn new(deque: PyDequeRef) -> Self { + PyDequeIterator { + position: AtomicCell::new(0), + status: AtomicCell::new(IterStatus::Active), + length: deque.len(), + deque, + } } #[pymethod(magic)] @@ -681,23 +685,15 @@ mod _collections { } } - #[pyimpl(with(PyIter))] - impl PyReverseDequeIterator { - #[pymethod(magic)] - fn length_hint(&self) -> usize { - match self.status.load() { - Active => self.position.load(), - Exhausted => 0, - } - } + impl SlotConstructor for PyReverseDequeIterator { + type Args = (DequeIterArgs, KwArgs); - #[pyslot] - fn tp_new( + fn py_new( cls: PyTypeRef, - DequeIterArgs { deque, index }: DequeIterArgs, - _kwargs: KwArgs, + + (DequeIterArgs { deque, index }, _kwargs): Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let len = deque.len(); let iter = PyDeque::reversed(deque)?; if let OptionalArg::Present(index) = index { @@ -707,7 +703,18 @@ mod _collections { } iter.position.store(len.saturating_sub(index)); } - iter.into_ref_with_type(vm, cls) + iter.into_pyresult_with_type(vm, cls) + } + } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyReverseDequeIterator { + #[pymethod(magic)] + fn length_hint(&self) -> usize { + match self.status.load() { + Active => self.position.load(), + Exhausted => 0, + } } #[pymethod(magic)] diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 517696f2a..da73869fe 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -92,6 +92,7 @@ mod _io { use crate::common::rc::PyRc; use crate::exceptions::{self, IntoPyException, PyBaseExceptionRef}; use crate::function::{FuncArgs, OptionalArg, OptionalOption}; + use crate::slots::SlotConstructor; use crate::utils::Either; use crate::vm::{ReprGuard, VirtualMachine}; use crate::{ @@ -1667,8 +1668,8 @@ mod _io { #[pyimpl(with(BufferedMixin, BufferedReadable), flags(BASETYPE, HAS_DICT))] impl BufferedReader { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - Self::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + Self::default().into_pyresult_with_type(vm, cls) } } @@ -1721,8 +1722,8 @@ mod _io { #[pyimpl(with(BufferedMixin, BufferedWritable), flags(BASETYPE, HAS_DICT))] impl BufferedWriter { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - Self::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + Self::default().into_pyresult_with_type(vm, cls) } } @@ -1764,8 +1765,8 @@ mod _io { )] impl BufferedRandom { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - Self::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + Self::default().into_pyresult_with_type(vm, cls) } } @@ -1796,8 +1797,8 @@ mod _io { #[pyimpl(with(BufferedReadable, BufferedWritable), flags(BASETYPE, HAS_DICT))] impl BufferedRWPair { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - Self::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + Self::default().into_pyresult_with_type(vm, cls) } #[pymethod(magic)] fn init( @@ -2198,8 +2199,8 @@ mod _io { #[pyimpl(flags(BASETYPE))] impl TextIOWrapper { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - Self::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + Self::default().into_pyresult_with_type(vm, cls) } fn lock_opt( @@ -3044,14 +3045,6 @@ mod _io { } } - #[derive(FromArgs)] - struct StringIOArgs { - #[pyarg(any, default)] - #[allow(dead_code)] - // TODO: use this - newline: Newlines, - } - #[pyattr] #[pyclass(name = "StringIO", base = "_TextIOBase")] #[derive(Debug)] @@ -3068,23 +3061,26 @@ mod _io { } } - #[pyimpl(flags(BASETYPE, HAS_DICT), with(PyRef))] - impl StringIO { - fn buffer(&self, vm: &VirtualMachine) -> PyResult> { - if !self.closed.load() { - Ok(self.buffer.write()) - } else { - Err(io_closed_error(vm)) - } - } + #[derive(FromArgs)] + struct StringIONewArgs { + #[pyarg(positional, optional)] + object: OptionalOption, - #[pyslot] - fn tp_new( + // TODO: use this + #[pyarg(any, default)] + #[allow(dead_code)] + newline: Newlines, + } + + impl SlotConstructor for StringIO { + type Args = StringIONewArgs; + + #[allow(unused_variables)] + fn py_new( cls: PyTypeRef, - object: OptionalOption, - _args: StringIOArgs, + Self::Args { object, newline }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let raw_bytes = object .flatten() .map_or_else(Vec::new, |v| v.as_str().as_bytes().to_vec()); @@ -3093,7 +3089,18 @@ mod _io { buffer: PyRwLock::new(BufferedIO::new(Cursor::new(raw_bytes))), closed: AtomicCell::new(false), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) + } + } + + #[pyimpl(flags(BASETYPE, HAS_DICT), with(PyRef, SlotConstructor))] + impl StringIO { + fn buffer(&self, vm: &VirtualMachine) -> PyResult> { + if !self.closed.load() { + Ok(self.buffer.write()) + } else { + Err(io_closed_error(vm)) + } } #[pymethod] @@ -3211,22 +3218,10 @@ mod _io { } } - #[pyimpl(flags(BASETYPE, HAS_DICT), with(PyRef))] - impl BytesIO { - fn buffer(&self, vm: &VirtualMachine) -> PyResult> { - if !self.closed.load() { - Ok(self.buffer.write()) - } else { - Err(io_closed_error(vm)) - } - } + impl SlotConstructor for BytesIO { + type Args = OptionalArg>; - #[pyslot] - fn tp_new( - cls: PyTypeRef, - object: OptionalArg>, - vm: &VirtualMachine, - ) -> PyResult { + fn py_new(cls: PyTypeRef, object: Self::Args, vm: &VirtualMachine) -> PyResult { let raw_bytes = object .flatten() .map_or_else(Vec::new, |input| input.as_bytes().to_vec()); @@ -3236,7 +3231,18 @@ mod _io { closed: AtomicCell::new(false), exports: AtomicCell::new(0), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) + } + } + + #[pyimpl(flags(BASETYPE, HAS_DICT), with(PyRef, SlotConstructor))] + impl BytesIO { + fn buffer(&self, vm: &VirtualMachine) -> PyResult> { + if !self.closed.load() { + Ok(self.buffer.write()) + } else { + Err(io_closed_error(vm)) + } } #[pymethod] @@ -3844,8 +3850,6 @@ mod fileio { seekable: AtomicCell>, } - type FileIORef = PyRef; - impl PyValue for FileIO { fn class(_vm: &VirtualMachine) -> &PyTypeRef { Self::static_type() @@ -3867,14 +3871,14 @@ mod fileio { #[pyimpl(flags(BASETYPE, HAS_DICT))] impl FileIO { #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { FileIO { fd: AtomicCell::new(-1), closefd: AtomicCell::new(false), mode: AtomicCell::new(Mode::empty()), seekable: AtomicCell::new(None), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } #[pymethod(magic)] diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index 19679747c..ceda9364b 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -15,7 +15,7 @@ mod decl { use crate::common::rc::PyRc; use crate::function::{Args, FuncArgs, OptionalArg, OptionalOption}; use crate::iterator::{call_next, get_all, get_iter, get_next_object}; - use crate::slots::PyIter; + use crate::slots::{PyIter, SlotConstructor}; use crate::vm::VirtualMachine; use crate::{ IdProtocol, IntoPyObject, PyCallable, PyObjectRef, PyRef, PyResult, PyValue, PyWeakRef, @@ -40,13 +40,13 @@ mod decl { #[pyimpl(with(PyIter))] impl PyItertoolsChain { #[pyslot] - fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { PyItertoolsChain { iterables: args.args, cur_idx: AtomicCell::new(0), cached_iter: PyRwLock::new(None), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } #[pyclassmethod] @@ -117,15 +117,22 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsCompress { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct CompressNewArgs { + #[pyarg(positional)] + data: PyObjectRef, + #[pyarg(positional)] + selector: PyObjectRef, + } + + impl SlotConstructor for PyItertoolsCompress { + type Args = CompressNewArgs; + + fn py_new( cls: PyTypeRef, - data: PyObjectRef, - selector: PyObjectRef, + Self::Args { data, selector }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let data_iter = get_iter(vm, data)?; let selector_iter = get_iter(vm, selector)?; @@ -133,9 +140,13 @@ mod decl { data: data_iter, selector: selector_iter, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsCompress {} + impl PyIter for PyItertoolsCompress { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { loop { @@ -164,15 +175,23 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsCount { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct CountNewArgs { + #[pyarg(positional, optional)] + start: OptionalArg, + + #[pyarg(positional, optional)] + step: OptionalArg, + } + + impl SlotConstructor for PyItertoolsCount { + type Args = CountNewArgs; + + fn py_new( cls: PyTypeRef, - start: OptionalArg, - step: OptionalArg, + Self::Args { start, step }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let start = match start.into_option() { Some(int) => int.as_bigint().clone(), None => BigInt::zero(), @@ -186,9 +205,12 @@ mod decl { cur: PyRwLock::new(start), step, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsCount {} impl PyIter for PyItertoolsCount { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let mut cur = zelf.cur.write(); @@ -213,14 +235,10 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsCycle { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - iterable: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { + impl SlotConstructor for PyItertoolsCycle { + type Args = PyObjectRef; + + fn py_new(cls: PyTypeRef, iterable: Self::Args, vm: &VirtualMachine) -> PyResult { let iter = get_iter(vm, iterable)?; PyItertoolsCycle { @@ -228,9 +246,12 @@ mod decl { saved: PyRwLock::new(Vec::new()), index: AtomicCell::new(0), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsCycle {} impl PyIter for PyItertoolsCycle { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let item = if let Some(item) = get_next_object(vm, &zelf.iter)? { @@ -277,14 +298,14 @@ mod decl { times: OptionalArg, } - #[pyimpl(with(PyIter), flags(BASETYPE))] - impl PyItertoolsRepeat { - #[pyslot] - fn tp_new( + impl SlotConstructor for PyItertoolsRepeat { + type Args = PyRepeatNewArgs; + + fn py_new( cls: PyTypeRef, - PyRepeatNewArgs { object, times }: PyRepeatNewArgs, + Self::Args { object, times }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let times = match times.into_option() { Some(int) => { let val = int.as_bigint(); @@ -296,9 +317,12 @@ mod decl { } None => None, }; - PyItertoolsRepeat { object, times }.into_ref_with_type(vm, cls) + PyItertoolsRepeat { object, times }.into_pyresult_with_type(vm, cls) } + } + #[pyimpl(with(PyIter, SlotConstructor), flags(BASETYPE))] + impl PyItertoolsRepeat { #[pymethod(magic)] fn length_hint(&self, vm: &VirtualMachine) -> PyResult { match self.times { @@ -362,20 +386,30 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsStarmap { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct StarmapNewArgs { + #[pyarg(positional)] + function: PyObjectRef, + #[pyarg(positional)] + iterable: PyObjectRef, + } + + impl SlotConstructor for PyItertoolsStarmap { + type Args = StarmapNewArgs; + + fn py_new( cls: PyTypeRef, - function: PyObjectRef, - iterable: PyObjectRef, + Self::Args { function, iterable }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let iter = get_iter(vm, iterable)?; - PyItertoolsStarmap { function, iter }.into_ref_with_type(vm, cls) + PyItertoolsStarmap { function, iter }.into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsStarmap {} impl PyIter for PyItertoolsStarmap { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let obj = call_next(vm, &zelf.iter)?; @@ -400,15 +434,25 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsTakewhile { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct TakewhileNewArgs { + #[pyarg(positional)] + predicate: PyObjectRef, + #[pyarg(positional)] + iterable: PyObjectRef, + } + + impl SlotConstructor for PyItertoolsTakewhile { + type Args = TakewhileNewArgs; + + fn py_new( cls: PyTypeRef, - predicate: PyObjectRef, - iterable: PyObjectRef, + Self::Args { + predicate, + iterable, + }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let iter = get_iter(vm, iterable)?; PyItertoolsTakewhile { @@ -416,9 +460,12 @@ mod decl { iterable: iter, stop_flag: AtomicCell::new(false), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsTakewhile {} impl PyIter for PyItertoolsTakewhile { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { if zelf.stop_flag.load() { @@ -455,15 +502,25 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsDropwhile { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct DropwhileNewArgs { + #[pyarg(positional)] + predicate: PyCallable, + #[pyarg(positional)] + iterable: PyObjectRef, + } + + impl SlotConstructor for PyItertoolsDropwhile { + type Args = DropwhileNewArgs; + + fn py_new( cls: PyTypeRef, - predicate: PyCallable, - iterable: PyObjectRef, + Self::Args { + predicate, + iterable, + }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let iter = get_iter(vm, iterable)?; PyItertoolsDropwhile { @@ -471,9 +528,12 @@ mod decl { iterable: iter, start_flag: AtomicCell::new(false), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsDropwhile {} impl PyIter for PyItertoolsDropwhile { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let predicate = &zelf.predicate; @@ -551,10 +611,10 @@ mod decl { key: OptionalOption, } - #[pyimpl(with(PyIter))] - impl PyItertoolsGroupBy { - #[pyslot] - fn tp_new(cls: PyTypeRef, args: GroupByArgs, vm: &VirtualMachine) -> PyResult> { + impl SlotConstructor for PyItertoolsGroupBy { + type Args = GroupByArgs; + + fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { let iter = get_iter(vm, args.iterable)?; PyItertoolsGroupBy { @@ -567,9 +627,12 @@ mod decl { grouper: None, }), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } + } + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsGroupBy { pub(super) fn advance(&self, vm: &VirtualMachine) -> PyResult<(PyObjectRef, PyObjectRef)> { let new_value = call_next(vm, &self.iterable)?; let new_key = if let Some(ref kf) = self.key_func { @@ -709,7 +772,7 @@ mod decl { #[pyimpl(with(PyIter))] impl PyItertoolsIslice { #[pyslot] - fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { let (iter, start, stop, step) = match args.args.len() { 0 | 1 => { return Err(vm.new_type_error(format!( @@ -766,7 +829,7 @@ mod decl { stop, step, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } @@ -808,24 +871,37 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsFilterFalse { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct FilterFalseNewArgs { + #[pyarg(positional)] + predicate: PyObjectRef, + #[pyarg(positional)] + iterable: PyObjectRef, + } + + impl SlotConstructor for PyItertoolsFilterFalse { + type Args = FilterFalseNewArgs; + + fn py_new( cls: PyTypeRef, - predicate: PyObjectRef, - iterable: PyObjectRef, + Self::Args { + predicate, + iterable, + }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let iter = get_iter(vm, iterable)?; PyItertoolsFilterFalse { predicate, iterable: iter, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsFilterFalse {} impl PyIter for PyItertoolsFilterFalse { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let predicate = &zelf.predicate; @@ -871,14 +947,10 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsAccumulate { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - args: AccumulateArgs, - vm: &VirtualMachine, - ) -> PyResult> { + impl SlotConstructor for PyItertoolsAccumulate { + type Args = AccumulateArgs; + + fn py_new(cls: PyTypeRef, args: AccumulateArgs, vm: &VirtualMachine) -> PyResult { let iter = get_iter(vm, args.iterable)?; PyItertoolsAccumulate { @@ -887,9 +959,13 @@ mod decl { initial: args.initial.flatten(), acc_value: PyRwLock::new(None), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsAccumulate {} + impl PyIter for PyItertoolsAccumulate { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let iterable = &zelf.iterable; @@ -952,32 +1028,25 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsTee { - fn from_iter(iterable: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let class = PyItertoolsTee::class(vm); - let it = get_iter(vm, iterable)?; - if it.class().is(PyItertoolsTee::class(vm)) { - return vm.call_method(&it, "__copy__", ()); - } - Ok(PyItertoolsTee { - tee_data: PyItertoolsTeeData::new(it, vm)?, - index: AtomicCell::new(0), - } - .into_ref_with_type(vm, class.clone())? - .into_object()) - } + #[derive(FromArgs)] + struct TeeNewArgs { + #[pyarg(positional)] + iterable: PyObjectRef, + #[pyarg(positional, optional)] + n: OptionalArg, + } + + impl SlotConstructor for PyItertoolsTee { + type Args = TeeNewArgs; // TODO: make tee() a function, rename this class to itertools._tee and make // teedata a python class - #[pyslot] #[allow(clippy::new_ret_no_self)] - fn tp_new( + fn py_new( _cls: PyTypeRef, - iterable: PyObjectRef, - n: OptionalArg, + Self::Args { iterable, n }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let n = n.unwrap_or(2); let copyable = if iterable.class().has_attr("__copy__") { @@ -991,7 +1060,24 @@ mod decl { tee_vec.push(vm.call_method(©able, "__copy__", ())?); } - Ok(PyTupleRef::with_elements(tee_vec, &vm.ctx)) + Ok(PyTupleRef::with_elements(tee_vec, &vm.ctx).into_object()) + } + } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsTee { + fn from_iter(iterable: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let class = PyItertoolsTee::class(vm); + let it = get_iter(vm, iterable)?; + if it.class().is(PyItertoolsTee::class(vm)) { + return vm.call_method(&it, "__copy__", ()); + } + Ok(PyItertoolsTee { + tee_data: PyItertoolsTeeData::new(it, vm)?, + index: AtomicCell::new(0), + } + .into_ref_with_type(vm, class.clone())? + .into_object()) } #[pymethod(magic)] @@ -1034,17 +1120,11 @@ mod decl { repeat: OptionalArg, } - #[pyimpl(with(PyIter))] - impl PyItertoolsProduct { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - iterables: Args, - args: ProductArgs, - vm: &VirtualMachine, - ) -> PyResult> { - let repeat = args.repeat.unwrap_or(1); + impl SlotConstructor for PyItertoolsProduct { + type Args = (Args, ProductArgs); + fn py_new(cls: PyTypeRef, (iterables, args): Self::Args, vm: &VirtualMachine) -> PyResult { + let repeat = args.repeat.unwrap_or(1); let mut pools = Vec::new(); for arg in iterables.into_iter() { let it = get_iter(vm, arg)?; @@ -1065,9 +1145,12 @@ mod decl { cur: AtomicCell::new(l.wrapping_sub(1)), stop: AtomicCell::new(false), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } + } + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsProduct { fn update_idxs(&self, mut idxs: PyRwLockWriteGuard<'_, Vec>) { if idxs.len() == 0 { self.stop.store(true); @@ -1137,15 +1220,22 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsCombinations { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct CombinationsNewArgs { + #[pyarg(positional)] + iterable: PyObjectRef, + #[pyarg(positional)] + r: PyIntRef, + } + + impl SlotConstructor for PyItertoolsCombinations { + type Args = CombinationsNewArgs; + + fn py_new( cls: PyTypeRef, - iterable: PyObjectRef, - r: PyIntRef, + Self::Args { iterable, r }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let iter = get_iter(vm, iterable)?; let pool = get_all(vm, &iter)?; @@ -1163,9 +1253,12 @@ mod decl { r: AtomicCell::new(r), exhausted: AtomicCell::new(r > n), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsCombinations {} impl PyIter for PyItertoolsCombinations { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { // stop signal @@ -1232,15 +1325,14 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsCombinationsWithReplacement { - #[pyslot] - fn tp_new( + impl SlotConstructor for PyItertoolsCombinationsWithReplacement { + type Args = CombinationsNewArgs; + + fn py_new( cls: PyTypeRef, - iterable: PyObjectRef, - r: PyIntRef, + Self::Args { iterable, r }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let iter = get_iter(vm, iterable)?; let pool = get_all(vm, &iter)?; @@ -1258,9 +1350,13 @@ mod decl { r: AtomicCell::new(r), exhausted: AtomicCell::new(n == 0 && r > 0), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsCombinationsWithReplacement {} + impl PyIter for PyItertoolsCombinationsWithReplacement { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { // stop signal @@ -1324,15 +1420,22 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsPermutations { - #[pyslot] - fn tp_new( + #[derive(FromArgs)] + struct PermutationsNewArgs { + #[pyarg(positional)] + iterable: PyObjectRef, + #[pyarg(positional, optional)] + r: OptionalOption, + } + + impl SlotConstructor for PyItertoolsPermutations { + type Args = PermutationsNewArgs; + + fn py_new( cls: PyTypeRef, - iterable: PyObjectRef, - r: OptionalOption, + Self::Args { iterable, r }: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { let pool = vm.extract_elements(&iterable)?; let n = pool.len(); @@ -1361,9 +1464,12 @@ mod decl { r: AtomicCell::new(r), exhausted: AtomicCell::new(r > n), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsPermutations {} impl PyIter for PyItertoolsPermutations { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { // stop signal @@ -1431,6 +1537,30 @@ mod decl { } } + #[derive(FromArgs)] + struct ZipLongestArgs { + #[pyarg(named, optional)] + fillvalue: OptionalArg, + } + + impl SlotConstructor for PyItertoolsZipLongest { + type Args = (Args, ZipLongestArgs); + + fn py_new(cls: PyTypeRef, (iterables, args): Self::Args, vm: &VirtualMachine) -> PyResult { + let fillvalue = args.fillvalue.unwrap_or_none(vm); + let iterators = iterables + .into_iter() + .map(|iterable| get_iter(vm, iterable)) + .collect::, _>>()?; + + PyItertoolsZipLongest { + iterators, + fillvalue, + } + .into_pyresult_with_type(vm, cls) + } + } + #[pyattr] #[pyclass(name = "zip_longest")] #[derive(Debug)] @@ -1445,34 +1575,8 @@ mod decl { } } - #[derive(FromArgs)] - struct ZipLongestArgs { - #[pyarg(named, optional)] - fillvalue: OptionalArg, - } - - #[pyimpl(with(PyIter))] - impl PyItertoolsZipLongest { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - iterables: Args, - args: ZipLongestArgs, - vm: &VirtualMachine, - ) -> PyResult> { - let fillvalue = args.fillvalue.unwrap_or_none(vm); - let iterators = iterables - .into_iter() - .map(|iterable| get_iter(vm, iterable)) - .collect::, _>>()?; - - PyItertoolsZipLongest { - iterators, - fillvalue, - } - .into_ref_with_type(vm, cls) - } - } + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsZipLongest {} impl PyIter for PyItertoolsZipLongest { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { if zelf.iterators.is_empty() { @@ -1516,23 +1620,22 @@ mod decl { } } - #[pyimpl(with(PyIter))] - impl PyItertoolsPairwise { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - iterable: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { + impl SlotConstructor for PyItertoolsPairwise { + type Args = PyObjectRef; + + fn py_new(cls: PyTypeRef, iterable: Self::Args, vm: &VirtualMachine) -> PyResult { let iterator = get_iter(vm, iterable)?; PyItertoolsPairwise { iterator, old: PyRwLock::new(None), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } + + #[pyimpl(with(PyIter, SlotConstructor))] + impl PyItertoolsPairwise {} impl PyIter for PyItertoolsPairwise { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let old = match zelf.old.read().clone() { diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index d9665ef99..d0f821d04 100644 --- a/vm/src/stdlib/json.rs +++ b/vm/src/stdlib/json.rs @@ -9,7 +9,7 @@ mod _json { use crate::exceptions::PyBaseExceptionRef; use crate::function::{FuncArgs, OptionalArg}; use crate::iterator; - use crate::slots::Callable; + use crate::slots::{Callable, SlotConstructor}; use crate::VirtualMachine; use crate::{ IdProtocol, IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue, StaticType, TryFromObject, @@ -37,10 +37,10 @@ mod _json { } } - #[pyimpl(with(Callable))] - impl JsonScanner { - #[pyslot] - fn tp_new(cls: PyTypeRef, ctx: PyObjectRef, vm: &VirtualMachine) -> PyResult> { + impl SlotConstructor for JsonScanner { + type Args = PyObjectRef; + + fn py_new(cls: PyTypeRef, ctx: Self::Args, vm: &VirtualMachine) -> PyResult { let strict = pybool::boolval(vm, vm.get_attribute(ctx.clone(), "strict")?)?; let object_hook = vm.option_if_none(vm.get_attribute(ctx.clone(), "object_hook")?); let object_pairs_hook = @@ -69,9 +69,12 @@ mod _json { parse_constant, ctx, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } + } + #[pyimpl(with(Callable, SlotConstructor))] + impl JsonScanner { fn parse( &self, s: &str, diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 922a79aea..f46609dab 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -22,8 +22,8 @@ mod _operator { use crate::function::OptionalArg; use crate::iterator; use crate::pyobject::TypeProtocol; - use crate::slots::Callable; use crate::slots::PyComparisonOp::{Eq, Ge, Gt, Le, Lt, Ne}; + use crate::slots::{Callable, SlotConstructor}; use crate::utils::Either; use crate::vm::ReprGuard; use crate::IdProtocol; @@ -450,7 +450,7 @@ mod _operator { #[pyimpl(with(Callable))] impl PyAttrGetter { #[pyslot] - fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { let nattr = args.args.len(); // Check we get no keyword and at least one positional. if !args.kwargs.is_empty() { @@ -467,7 +467,7 @@ mod _operator { return Err(vm.new_type_error("attribute name must be a string".to_owned())); } } - PyAttrGetter { attrs }.into_ref_with_type(vm, cls) + PyAttrGetter { attrs }.into_pyresult_with_type(vm, cls) } #[pymethod(magic)] @@ -553,7 +553,7 @@ mod _operator { #[pyimpl(with(Callable))] impl PyItemGetter { #[pyslot] - fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // Check we get no keyword and at least one positional. if !args.kwargs.is_empty() { return Err(vm.new_type_error("itemgetter() takes no keyword arguments".to_owned())); @@ -561,7 +561,7 @@ mod _operator { if args.args.is_empty() { return Err(vm.new_type_error("itemgetter expected 1 argument, got 0.".to_owned())); } - PyItemGetter { items: args.args }.into_ref_with_type(vm, cls) + PyItemGetter { items: args.args }.into_pyresult_with_type(vm, cls) } #[pymethod(magic)] @@ -626,22 +626,20 @@ mod _operator { } } - #[pyimpl(with(Callable))] - impl PyMethodCaller { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - name: PyObjectRef, - args: FuncArgs, - vm: &VirtualMachine, - ) -> PyResult> { + impl SlotConstructor for PyMethodCaller { + type Args = (PyObjectRef, FuncArgs); + + fn py_new(cls: PyTypeRef, (name, args): Self::Args, vm: &VirtualMachine) -> PyResult { if let Ok(name) = name.try_into_ref(vm) { - PyMethodCaller { name, args }.into_ref_with_type(vm, cls) + PyMethodCaller { name, args }.into_pyresult_with_type(vm, cls) } else { Err(vm.new_type_error("method name must be a string".to_owned())) } } + } + #[pyimpl(with(Callable, SlotConstructor))] + impl PyMethodCaller { #[pymethod(magic)] fn repr(zelf: PyRef, vm: &VirtualMachine) -> PyResult { let fmt = if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) { diff --git a/vm/src/stdlib/pystruct.rs b/vm/src/stdlib/pystruct.rs index e33bdca20..3f1964880 100644 --- a/vm/src/stdlib/pystruct.rs +++ b/vm/src/stdlib/pystruct.rs @@ -26,7 +26,7 @@ pub(crate) mod _struct { use crate::byteslike::{ArgBytesLike, ArgMemoryBuffer}; use crate::exceptions::PyBaseExceptionRef; use crate::function::Args; - use crate::slots::PyIter; + use crate::slots::{PyIter, SlotConstructor}; use crate::stdlib::array::wchar_t; use crate::utils::Either; use crate::VirtualMachine; @@ -882,23 +882,22 @@ pub(crate) mod _struct { } } - #[pyimpl] - impl PyStruct { - #[pyslot] - fn tp_new( - cls: PyTypeRef, - fmt: Either, - vm: &VirtualMachine, - ) -> PyResult> { + impl SlotConstructor for PyStruct { + type Args = Either; + + fn py_new(cls: PyTypeRef, fmt: Self::Args, vm: &VirtualMachine) -> PyResult { let spec = FormatSpec::decode_and_parse(vm, &fmt)?; let fmt_str = match fmt { Either::A(s) => s, Either::B(b) => PyStr::from(std::str::from_utf8(b.as_bytes()).unwrap()) .into_ref_with_type(vm, vm.ctx.types.str_type.clone())?, }; - PyStruct { spec, fmt_str }.into_ref_with_type(vm, cls) + PyStruct { spec, fmt_str }.into_pyresult_with_type(vm, cls) } + } + #[pyimpl(with(SlotConstructor))] + impl PyStruct { #[pyproperty] fn format(&self) -> PyStrRef { self.fmt_str.clone() diff --git a/vm/src/stdlib/random.rs b/vm/src/stdlib/random.rs index 4eb9fddef..4f86456db 100644 --- a/vm/src/stdlib/random.rs +++ b/vm/src/stdlib/random.rs @@ -8,8 +8,9 @@ mod _random { use crate::builtins::pytype::PyTypeRef; use crate::common::lock::PyMutex; use crate::function::OptionalOption; + use crate::slots::SlotConstructor; use crate::VirtualMachine; - use crate::{PyObjectRef, PyRef, PyResult, PyValue, StaticType}; + use crate::{PyObjectRef, PyResult, PyValue, StaticType}; use num_bigint::{BigInt, Sign}; use num_traits::{Signed, Zero}; use rand::{rngs::StdRng, RngCore, SeedableRng}; @@ -66,21 +67,24 @@ mod _random { } } - #[pyimpl(flags(BASETYPE))] - impl PyRandom { - #[pyslot(new)] - fn new( + impl SlotConstructor for PyRandom { + type Args = OptionalOption; + + fn py_new( cls: PyTypeRef, // TODO: use x as the seed. - _x: OptionalOption, + _x: Self::Args, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { PyRandom { rng: PyMutex::default(), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } + } + #[pyimpl(flags(BASETYPE), with(SlotConstructor))] + impl PyRandom { #[pymethod] fn random(&self) -> f64 { let mut rng = self.rng.lock(); diff --git a/vm/src/stdlib/socket.rs b/vm/src/stdlib/socket.rs index bdf3ad4c3..c702f482d 100644 --- a/vm/src/stdlib/socket.rs +++ b/vm/src/stdlib/socket.rs @@ -191,8 +191,8 @@ impl PySocket { } #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { - Self::default().into_ref_with_type(vm, cls) + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { + Self::default().into_pyresult_with_type(vm, cls) } #[pymethod(magic)] diff --git a/vm/src/stdlib/ssl.rs b/vm/src/stdlib/ssl.rs index d5d10559d..433dbead7 100644 --- a/vm/src/stdlib/ssl.rs +++ b/vm/src/stdlib/ssl.rs @@ -12,6 +12,7 @@ use crate::{ StaticType, }; +use crate::slots::SlotConstructor; use crossbeam_utils::atomic::AtomicCell; use foreign_types_shared::{ForeignType, ForeignTypeRef}; use openssl::{ @@ -273,21 +274,10 @@ fn builder_as_ctx(x: &SslContextBuilder) -> &ssl::SslContextRef { unsafe { ssl::SslContextRef::from_ptr(x.as_ptr()) } } -#[pyimpl(flags(BASETYPE))] -impl PySslContext { - fn builder(&self) -> PyRwLockWriteGuard<'_, SslContextBuilder> { - self.ctx.write() - } - fn exec_ctx(&self, func: F) -> R - where - F: Fn(&ssl::SslContextRef) -> R, - { - let c = self.ctx.read(); - func(builder_as_ctx(&c)) - } +impl SlotConstructor for PySslContext { + type Args = i32; - #[pyslot] - fn tp_new(cls: PyTypeRef, proto_version: i32, vm: &VirtualMachine) -> PyResult> { + fn py_new(cls: PyTypeRef, proto_version: Self::Args, vm: &VirtualMachine) -> PyResult { let proto = SslVersion::try_from(proto_version) .map_err(|_| vm.new_value_error("invalid protocol version".to_owned()))?; let method = match proto { @@ -339,7 +329,21 @@ impl PySslContext { check_hostname: AtomicCell::new(check_hostname), protocol: proto, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) + } +} + +#[pyimpl(flags(BASETYPE), with(SlotConstructor))] +impl PySslContext { + fn builder(&self) -> PyRwLockWriteGuard<'_, SslContextBuilder> { + self.ctx.write() + } + fn exec_ctx(&self, func: F) -> R + where + F: Fn(&ssl::SslContextRef) -> R, + { + let c = self.ctx.read(); + func(builder_as_ctx(&c)) } #[pymethod] diff --git a/vm/src/stdlib/thread.rs b/vm/src/stdlib/thread.rs index 212c4d237..90272d853 100644 --- a/vm/src/stdlib/thread.rs +++ b/vm/src/stdlib/thread.rs @@ -169,11 +169,11 @@ impl fmt::Debug for PyRLock { #[pyimpl] impl PyRLock { #[pyslot] - fn tp_new(cls: PyTypeRef, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { PyRLock { mu: RawRMutex::INIT, } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } #[pymethod] @@ -321,11 +321,11 @@ impl PyLocal { } #[pyslot] - fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult> { + fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { PyLocal { data: ThreadLocal::new(), } - .into_ref_with_type(vm, cls) + .into_pyresult_with_type(vm, cls) } } diff --git a/vm/src/stdlib/time.rs b/vm/src/stdlib/time.rs index 12342964b..d2ff7722e 100644 --- a/vm/src/stdlib/time.rs +++ b/vm/src/stdlib/time.rs @@ -9,7 +9,7 @@ use chrono::{Datelike, Timelike}; use crate::builtins::pystr::PyStrRef; use crate::builtins::pytype::PyTypeRef; -use crate::function::OptionalArg; +use crate::function::{FuncArgs, OptionalArg}; use crate::utils::Either; use crate::vm::VirtualMachine; use crate::{PyClassImpl, PyObjectRef, PyResult, PyStructSequence, TryFromObject}; @@ -227,9 +227,10 @@ impl PyStructTime { } #[pyslot] - fn tp_new(_cls: PyTypeRef, seq: PyObjectRef, vm: &VirtualMachine) -> PyResult { + fn tp_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // cls is ignorable because this is not a basetype - Self::try_from_object(vm, seq) + let seq = args.bind(vm)?; + Ok(vm.new_pyobj(Self::try_from_object(vm, seq)?)) } }