From c4b80b3a2465912ef375c7114b2101f77ed1343d Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Mon, 18 Apr 2022 08:53:40 +0900 Subject: [PATCH 1/5] IntoObject::into_object() and PyValue::into_pyobject(vm) --- benches/microbenchmarks.rs | 4 +--- stdlib/src/array.rs | 6 +++--- stdlib/src/hashlib.rs | 2 +- vm/src/builtins/bytearray.rs | 12 ++++++------ vm/src/builtins/bytes.rs | 8 ++++---- vm/src/builtins/dict.rs | 10 +++++----- vm/src/builtins/frame.rs | 4 ++-- vm/src/builtins/function.rs | 6 +++--- vm/src/builtins/genericalias.rs | 5 ++++- vm/src/builtins/int.rs | 2 +- vm/src/builtins/iter.rs | 4 ++-- vm/src/builtins/list.rs | 11 +++++------ vm/src/builtins/memory.rs | 14 ++++++-------- vm/src/builtins/pystr.rs | 2 +- vm/src/builtins/pysuper.rs | 2 +- vm/src/builtins/pytype.rs | 6 +++--- vm/src/builtins/range.rs | 21 +++++++++++++-------- vm/src/builtins/set.rs | 6 +++--- vm/src/builtins/tuple.rs | 2 +- vm/src/builtins/weakref.rs | 6 +++--- vm/src/convert/into_object.rs | 12 ++++++++++++ vm/src/convert/mod.rs | 2 ++ vm/src/frame.rs | 10 +++++----- vm/src/function/argument.rs | 18 ++++++++---------- vm/src/lib.rs | 2 +- vm/src/macros.rs | 4 ++-- vm/src/protocol/buffer.rs | 10 +++++----- vm/src/protocol/iter.rs | 11 +++++------ vm/src/protocol/sequence.rs | 4 ++-- vm/src/pyobject.rs | 21 ++------------------- vm/src/pyobjectrc.rs | 14 +++++++------- vm/src/stdlib/builtins.rs | 11 +++++------ vm/src/stdlib/collections.rs | 2 +- vm/src/stdlib/io.rs | 4 ++-- vm/src/stdlib/sre.rs | 2 +- vm/src/stdlib/symtable.rs | 4 ++-- vm/src/stdlib/weakref.rs | 4 ++-- vm/src/utils.rs | 12 ++++++------ vm/src/vm_new.rs | 4 ++-- wasm/lib/src/browser_module.rs | 4 ++-- wasm/lib/src/js_module.rs | 13 ++++++------- 41 files changed, 148 insertions(+), 153 deletions(-) create mode 100644 vm/src/convert/into_object.rs diff --git a/benches/microbenchmarks.rs b/benches/microbenchmarks.rs index 6e6103ccf..eaf125a01 100644 --- a/benches/microbenchmarks.rs +++ b/benches/microbenchmarks.rs @@ -3,9 +3,7 @@ use criterion::{ Criterion, Throughput, }; use rustpython_compiler::Mode; -use rustpython_vm::{ - common::ascii, InitParameter, Interpreter, PyObjectWrap, PyResult, PySettings, -}; +use rustpython_vm::{common::ascii, InitParameter, Interpreter, PyResult, PySettings}; use std::{ ffi, fs, io, path::{Path, PathBuf}, diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 6542f68f0..5ff4a1c88 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -480,7 +480,7 @@ mod array { $f_swap(self) } fn to_object(self, vm: &VirtualMachine) -> PyObjectRef { - $f_to(self).into_object(vm) + $f_to(self).into_pyobject(vm) } } )*}; @@ -1117,7 +1117,7 @@ mod array { let typecode = vm.ctx.new_str(array.typecode_str()); let bytes = vm.ctx.new_bytes(array.get_bytes().to_vec()); let code = MachineFormatCode::from_typecode(array.typecode()).unwrap(); - let code = PyInt::from(u8::from(code)).into_object(vm); + let code = PyInt::from(u8::from(code)).into_pyobject(vm); let module = vm.import("array", None, 0)?; let func = module.get_attr("_array_reconstructor", vm)?; Ok(( @@ -1265,7 +1265,7 @@ mod array { position: AtomicUsize::new(0), array: zelf, } - .into_object(vm)) + .into_pyobject(vm)) } } diff --git a/stdlib/src/hashlib.rs b/stdlib/src/hashlib.rs index 06956a02d..52c98abd8 100644 --- a/stdlib/src/hashlib.rs +++ b/stdlib/src/hashlib.rs @@ -77,7 +77,7 @@ mod hashlib { #[pyslot] fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Ok(PyHasher::new("md5", HashWrapper::md5()).into_object(vm)) + Ok(PyHasher::new("md5", HashWrapper::md5()).into_pyobject(vm)) } #[pyproperty] diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 792e5cf6c..f8d912925 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -33,8 +33,8 @@ use crate::{ IterNextIterable, Iterable, PyComparisonOp, Unconstructible, Unhashable, }, utils::Either, - AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyObjectWrap, PyRef, PyResult, - PyValue, TryFromBorrowedObject, TryFromObject, VirtualMachine, + AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyRef, PyResult, PyValue, + TryFromBorrowedObject, TryFromObject, VirtualMachine, }; use bstr::ByteSlice; use std::{borrow::Cow, mem::size_of}; @@ -751,7 +751,7 @@ static BUFFER_METHODS: BufferMethods = BufferMethods { impl AsBuffer for PyByteArray { fn as_buffer(zelf: &PyObjectView, _vm: &VirtualMachine) -> PyResult { Ok(PyBuffer::new( - zelf.to_owned().into_object(), + zelf.to_owned().into(), BufferDescriptor::simple(zelf.len(), false), &BUFFER_METHODS, )) @@ -789,12 +789,12 @@ impl PyByteArray { Self::sequence_downcast(seq) .inner() .concat(other, vm) - .map(|x| PyByteArray::from(x).into_object(vm)) + .map(|x| PyByteArray::from(x).into_pyobject(vm)) }), repeat: Some(|seq, n, vm| { Self::sequence_downcast(seq) .mul(n as isize, vm) - .map(|x| x.into_object(vm)) + .map(|x| x.into_pyobject(vm)) }), item: Some(|seq, i, vm| { Self::sequence_downcast(seq) @@ -833,7 +833,7 @@ impl Iterable for PyByteArray { Ok(PyByteArrayIterator { internal: PyMutex::new(PositionIterInternal::new(zelf, 0)), } - .into_object(vm)) + .into_pyobject(vm)) } } diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 22b4ccc9d..1fcc21d6c 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -20,8 +20,8 @@ use crate::{ IterNextIterable, Iterable, PyComparisonOp, Unconstructible, }, utils::Either, - AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyObjectWrap, PyRef, PyResult, - PyValue, TryFromBorrowedObject, TryFromObject, VirtualMachine, + AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyRef, PyResult, PyValue, + TryFromBorrowedObject, TryFromObject, VirtualMachine, }; use bstr::ByteSlice; use std::{borrow::Cow, mem::size_of, ops::Deref}; @@ -567,7 +567,7 @@ static BUFFER_METHODS: BufferMethods = BufferMethods { impl AsBuffer for PyBytes { fn as_buffer(zelf: &PyObjectView, _vm: &VirtualMachine) -> PyResult { let buf = PyBuffer::new( - zelf.to_owned().into_object(), + zelf.to_owned().into(), BufferDescriptor::simple(zelf.len(), true), &BUFFER_METHODS, ); @@ -657,7 +657,7 @@ impl Iterable for PyBytes { Ok(PyBytesIterator { internal: PyMutex::new(PositionIterInternal::new(zelf, 0)), } - .into_object(vm)) + .into_pyobject(vm)) } } diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index b84e6736b..f8a0fa4b1 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -374,7 +374,7 @@ impl PyDict { if let Ok(other) = dicted { let other_cp = other.copy(); PyDict::merge_dict(&other_cp.entries, zelf, vm)?; - return Ok(other_cp.into_object(vm)); + return Ok(other_cp.into_pyobject(vm)); } Ok(vm.ctx.not_implemented()) } @@ -385,7 +385,7 @@ impl PyDict { if let Ok(other) = dicted { let self_cp = self.copy(); PyDict::merge_dict(&self_cp.entries, other, vm)?; - return Ok(self_cp.into_object(vm)); + return Ok(self_cp.into_pyobject(vm)); } Ok(vm.ctx.not_implemented()) } @@ -502,7 +502,7 @@ impl Unhashable for PyDict {} impl Iterable for PyDict { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - Ok(PyDictKeyIterator::new(zelf).into_object(vm)) + Ok(PyDictKeyIterator::new(zelf).into_pyobject(vm)) } } @@ -737,7 +737,7 @@ macro_rules! dict_view { impl Iterable for $name { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - Ok($iter_name::new(zelf.dict.clone()).into_object(vm)) + Ok($iter_name::new(zelf.dict.clone()).into_pyobject(vm)) } } @@ -1011,7 +1011,7 @@ trait ViewSetOps: DictView { } ref _set @ PySet => { let inner = Self::to_set(zelf.to_owned(), vm)?; - let zelf_set = PySet { inner }.into_object(vm); + let zelf_set = PySet { inner }.into_pyobject(vm); PySet::cmp(zelf_set.downcast_ref().unwrap(), other, op, vm) } _ => { diff --git a/vm/src/builtins/frame.rs b/vm/src/builtins/frame.rs index 91676c68b..74b151a96 100644 --- a/vm/src/builtins/frame.rs +++ b/vm/src/builtins/frame.rs @@ -7,7 +7,7 @@ use crate::{ frame::{Frame, FrameRef}, pyclass::PyClassImpl, types::{Constructor, Unconstructible}, - AsObject, PyContext, PyObjectRef, PyObjectWrap, PyRef, PyResult, VirtualMachine, + AsObject, PyContext, PyObjectRef, PyRef, PyResult, VirtualMachine, }; pub fn init(context: &PyContext) { @@ -46,7 +46,7 @@ impl FrameRef { #[pyproperty] fn f_locals(self, vm: &VirtualMachine) -> PyResult { - self.locals(vm).map(|x| x.into_object()) + self.locals(vm).map(Into::into) } #[pyproperty] diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index cde240ad3..c64a515f1 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -311,9 +311,9 @@ impl PyFunction { let is_gen = code.flags.contains(bytecode::CodeFlags::IS_GENERATOR); let is_coro = code.flags.contains(bytecode::CodeFlags::IS_COROUTINE); match (is_gen, is_coro) { - (true, false) => Ok(PyGenerator::new(frame, self.name()).into_object(vm)), - (false, true) => Ok(PyCoroutine::new(frame, self.name()).into_object(vm)), - (true, true) => Ok(PyAsyncGen::new(frame, self.name()).into_object(vm)), + (true, false) => Ok(PyGenerator::new(frame, self.name()).into_pyobject(vm)), + (false, true) => Ok(PyCoroutine::new(frame, self.name()).into_pyobject(vm)), + (true, true) => Ok(PyAsyncGen::new(frame, self.name()).into_pyobject(vm)), (false, false) => vm.run_frame_full(frame), } } diff --git a/vm/src/builtins/genericalias.rs b/vm/src/builtins/genericalias.rs index e3b81f8fc..6414161a1 100644 --- a/vm/src/builtins/genericalias.rs +++ b/vm/src/builtins/genericalias.rs @@ -142,7 +142,10 @@ impl PyGenericAlias { vm, )?; - Ok(PyGenericAlias::new(self.origin.clone(), new_args.to_pyobject(vm), vm).into_object(vm)) + Ok( + PyGenericAlias::new(self.origin.clone(), new_args.to_pyobject(vm), vm) + .into_pyobject(vm), + ) } #[pymethod(magic)] diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 07c19b85f..9690e6432 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -58,7 +58,7 @@ impl PyValue for PyInt { &vm.ctx.types.int_type } - fn into_object(self, vm: &VirtualMachine) -> PyObjectRef { + fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { vm.ctx.new_int(self.value).into() } diff --git a/vm/src/builtins/iter.rs b/vm/src/builtins/iter.rs index 47d255479..c2f529944 100644 --- a/vm/src/builtins/iter.rs +++ b/vm/src/builtins/iter.rs @@ -191,10 +191,10 @@ impl PySequenceIterator { if let IterStatus::Active(obj) = &internal.status { let seq = PySequence::with_methods(obj, self.seq_methods.clone()); seq.length(vm) - .map(|x| PyInt::from(x).into_object(vm)) + .map(|x| PyInt::from(x).into_pyobject(vm)) .unwrap_or_else(|_| vm.ctx.not_implemented()) } else { - PyInt::from(0).into_object(vm) + PyInt::from(0).into_pyobject(vm) } } diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index 7f3f22626..d3545d646 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -16,8 +16,7 @@ use crate::{ }, utils::collection_repr, vm::{ReprGuard, VirtualMachine}, - AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyObjectWrap, PyRef, PyResult, - PyValue, + AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyRef, PyResult, PyValue, }; use std::{borrow::Cow, fmt, ops::DerefMut}; @@ -412,12 +411,12 @@ impl PyList { concat: Some(|seq, other, vm| { Self::sequence_downcast(seq) .concat(other, vm) - .map(|x| x.into_object()) + .map(|x| x.into()) }), repeat: Some(|seq, n, vm| { Self::sequence_downcast(seq) .mul(n as isize, vm) - .map(|x| x.into_object()) + .map(|x| x.into()) }), item: Some(|seq, i, vm| { Self::sequence_downcast(seq) @@ -443,7 +442,7 @@ impl PyList { inplace_repeat: Some(|seq, n, vm| { let zelf = Self::sequence_downcast(seq); zelf.borrow_vec_mut().imul(vm, n as isize)?; - Ok(zelf.to_owned().into_object()) + Ok(zelf.to_owned().into()) }), }; } @@ -453,7 +452,7 @@ impl Iterable for PyList { Ok(PyListIterator { internal: PyMutex::new(PositionIterInternal::new(zelf, 0)), } - .into_object(vm)) + .into_pyobject(vm)) } } diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 6b4c64f78..bcc116cc4 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -19,8 +19,8 @@ use crate::{ sliceable::wrap_index, types::{AsBuffer, AsMapping, AsSequence, Comparable, Constructor, Hashable, PyComparisonOp}, utils::Either, - AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyObjectWrap, PyRef, PyResult, - PyValue, TryFromBorrowedObject, TryFromObject, VirtualMachine, + AsObject, PyContext, PyObject, PyObjectRef, PyObjectView, PyRef, PyResult, PyValue, + TryFromBorrowedObject, TryFromObject, VirtualMachine, }; use crossbeam_utils::atomic::AtomicCell; use itertools::Itertools; @@ -255,7 +255,7 @@ impl PyMemoryView { other.init_slice(slice, 0, vm)?; other.init_len(); - Ok(other.into_ref(vm).into_object()) + Ok(other.into_ref(vm).into()) } fn getitem_by_multi_idx(&self, indexes: &[isize], vm: &VirtualMachine) -> PyResult { @@ -270,7 +270,7 @@ impl PyMemoryView { if zelf.desc.ndim() == 0 { // 0-d memoryview can be referenced using mv[...] or mv[()] only if needle.is(&vm.ctx.ellipsis) { - return Ok(zelf.into_object()); + return Ok(zelf.into()); } if let Some(tuple) = needle.payload::() { if tuple.is_empty() { @@ -539,9 +539,7 @@ impl PyMemoryView { let mut v = Vec::with_capacity(shape); for _ in 0..shape { - let obj = self - ._to_list(bytes, index + suboffset, dim + 1, vm)? - .into_object(); + let obj = self._to_list(bytes, index + suboffset, dim + 1, vm)?.into(); v.push(obj); index += stride; } @@ -938,7 +936,7 @@ impl AsBuffer for PyMemoryView { Err(vm.new_value_error("operation forbidden on released memoryview object".to_owned())) } else { Ok(PyBuffer::new( - zelf.to_owned().into_object(), + zelf.to_owned().into(), zelf.desc.clone(), &BUFFER_METHODS, )) diff --git a/vm/src/builtins/pystr.rs b/vm/src/builtins/pystr.rs index b79a7b094..26f4a0f1f 100644 --- a/vm/src/builtins/pystr.rs +++ b/vm/src/builtins/pystr.rs @@ -1264,7 +1264,7 @@ impl Iterable for PyStr { Ok(PyStrIterator { internal: PyMutex::new((PositionIterInternal::new(zelf, 0), 0)), } - .into_object(vm)) + .into_pyobject(vm)) } } diff --git a/vm/src/builtins/pysuper.rs b/vm/src/builtins/pysuper.rs index 064a96ac2..ad7709c00 100644 --- a/vm/src/builtins/pysuper.rs +++ b/vm/src/builtins/pysuper.rs @@ -171,7 +171,7 @@ impl GetDescriptor for PySuper { } let zelf_class = zelf.as_object().class(); if zelf_class.is(&vm.ctx.types.super_type) { - Ok(PySuper::new(zelf.typ.clone(), obj, vm)?.into_object(vm)) + Ok(PySuper::new(zelf.typ.clone(), obj, vm)?.into_pyobject(vm)) } else { let obj = vm.unwrap_or_none(zelf.obj.clone().map(|(o, _)| o)); vm.invoke(&zelf.class(), (zelf.typ.clone(), obj)) diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/pytype.rs index a0eb3b3d2..2554a5787 100644 --- a/vm/src/builtins/pytype.rs +++ b/vm/src/builtins/pytype.rs @@ -477,19 +477,19 @@ impl PyType { let mut attributes = dict.to_attributes(); if let Some(f) = attributes.get_mut("__new__") { if f.class().is(&vm.ctx.types.function_type) { - *f = PyStaticMethod::from(f.clone()).into_object(vm); + *f = PyStaticMethod::from(f.clone()).into_pyobject(vm); } } if let Some(f) = attributes.get_mut("__init_subclass__") { if f.class().is(&vm.ctx.types.function_type) { - *f = PyClassMethod::from(f.clone()).into_object(vm); + *f = PyClassMethod::from(f.clone()).into_pyobject(vm); } } if let Some(f) = attributes.get_mut("__class_getitem__") { if f.class().is(&vm.ctx.types.function_type) { - *f = PyClassMethod::from(f.clone()).into_object(vm); + *f = PyClassMethod::from(f.clone()).into_pyobject(vm); } } diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 1e7936b18..d6a416152 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -242,7 +242,7 @@ impl PyRange { // always fit in a usize. length: length.to_usize().unwrap_or(0), } - .into_object(vm) + .into_pyobject(vm) } else { PyLongRangeIterator { index: AtomicCell::new(0), @@ -250,7 +250,7 @@ impl PyRange { step, length, } - .into_object(vm) + .into_pyobject(vm) }, ) } @@ -284,7 +284,7 @@ impl PyRange { } } else { iter_search( - self.clone().into_object(vm), + self.clone().into_pyobject(vm), needle, SearchType::Contains, vm, @@ -315,8 +315,13 @@ impl PyRange { // Fallback to iteration. Ok(BigInt::from_bytes_be( Sign::Plus, - &iter_search(self.clone().into_object(vm), needle, SearchType::Index, vm)? - .to_be_bytes(), + &iter_search( + self.clone().into_pyobject(vm), + needle, + SearchType::Index, + vm, + )? + .to_be_bytes(), )) } } @@ -332,7 +337,7 @@ impl PyRange { } else { // Dealing with classes who might compare equal with ints in their // __eq__, slow search. - iter_search(self.clone().into_object(vm), item, SearchType::Count, vm) + iter_search(self.clone().into_pyobject(vm), item, SearchType::Count, vm) } } @@ -493,7 +498,7 @@ impl Iterable for PyRange { // always fit in a usize. length: length.to_usize().unwrap_or(0), } - .into_object(vm)) + .into_pyobject(vm)) } else { Ok(PyLongRangeIterator { index: AtomicCell::new(0), @@ -501,7 +506,7 @@ impl Iterable for PyRange { step: step.clone(), length, } - .into_object(vm)) + .into_pyobject(vm)) } } } diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index 4413a5b4f..233f93766 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -338,7 +338,7 @@ impl PySetInner { &PyFrozenSet { inner: set.inner.copy(), } - .into_object(vm), + .into_pyobject(vm), vm, ) // If operation raised KeyError, report original set (set.remove) @@ -688,7 +688,7 @@ impl Unhashable for PySet {} impl Iterable for PySet { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - Ok(zelf.inner.iter().into_object(vm)) + Ok(zelf.inner.iter().into_pyobject(vm)) } } @@ -933,7 +933,7 @@ impl Comparable for PyFrozenSet { impl Iterable for PyFrozenSet { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - Ok(zelf.inner.iter().into_object(vm)) + Ok(zelf.inner.iter().into_pyobject(vm)) } } diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 6aa60d28e..c28320717 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -394,7 +394,7 @@ impl Iterable for PyTuple { Ok(PyTupleIterator { internal: PyMutex::new(PositionIterInternal::new(zelf, 0)), } - .into_object(vm)) + .into_pyobject(vm)) } } diff --git a/vm/src/builtins/weakref.rs b/vm/src/builtins/weakref.rs index 2425ec3f0..faef972c5 100644 --- a/vm/src/builtins/weakref.rs +++ b/vm/src/builtins/weakref.rs @@ -7,8 +7,7 @@ use crate::{ function::OptionalArg, pyclass::PyClassImpl, types::{Callable, Comparable, Constructor, Hashable, PyComparisonOp}, - AsObject, PyContext, PyObject, PyObjectRef, PyObjectWrap, PyRef, PyResult, PyValue, - VirtualMachine, + AsObject, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, VirtualMachine, }; pub use crate::pyobject::PyWeak; @@ -44,7 +43,8 @@ impl Constructor for PyWeak { vm: &VirtualMachine, ) -> PyResult { let weak = referent.downgrade_with_typ(callback.into_option(), cls, vm)?; - Ok(weak.into_object()) + let pyref_weak: PyRef = weak.into(); + Ok(pyref_weak.into()) } } diff --git a/vm/src/convert/into_object.rs b/vm/src/convert/into_object.rs new file mode 100644 index 000000000..655edae3e --- /dev/null +++ b/vm/src/convert/into_object.rs @@ -0,0 +1,12 @@ +use crate::PyObjectRef; + +pub trait IntoObject +where + Self: Into, +{ + fn into_object(self) -> PyObjectRef { + self.into() + } +} + +impl IntoObject for T where T: Into {} diff --git a/vm/src/convert/mod.rs b/vm/src/convert/mod.rs index a381d0c85..209b296f7 100644 --- a/vm/src/convert/mod.rs +++ b/vm/src/convert/mod.rs @@ -1,7 +1,9 @@ +mod into_object; mod to_pyobject; mod transmute_from; mod try_from; +pub use into_object::IntoObject; pub use to_pyobject::{ToPyException, ToPyObject, ToPyResult}; pub use transmute_from::TransmuteFromObject; pub use try_from::{TryFromBorrowedObject, TryFromObject}; diff --git a/vm/src/frame.rs b/vm/src/frame.rs index b023ea90b..99ad67c7d 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -8,7 +8,7 @@ use crate::{ PySlice, PyStr, PyStrRef, PyTraceback, PyTypeRef, }, bytecode, - convert::ToPyResult, + convert::{IntoObject, ToPyResult}, coroutine::Coro, exceptions::ExceptionCtor, function::{ArgMapping, FuncArgs}, @@ -16,8 +16,8 @@ use crate::{ scope::Scope, stdlib::builtins, types::PyComparisonOp, - AsObject, PyMethod, PyObject, PyObjectRef, PyObjectWrap, PyRef, PyResult, PyValue, - TryFromObject, VirtualMachine, + AsObject, PyMethod, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, + VirtualMachine, }; use indexmap::IndexMap; use itertools::Itertools; @@ -727,7 +727,7 @@ impl ExecutingFrame<'_> { bytecode::Instruction::YieldValue => { let value = self.pop_value(); let value = if self.code.flags.contains(bytecode::CodeFlags::IS_COROUTINE) { - PyAsyncGenWrappedValue(value).into_object(vm) + PyAsyncGenWrappedValue(value).into_pyobject(vm) } else { value }; @@ -1606,7 +1606,7 @@ impl ExecutingFrame<'_> { defaults, kw_only_defaults, ) - .into_object(vm); + .into_pyobject(vm); func_obj.set_attr("__doc__", vm.ctx.none(), vm)?; diff --git a/vm/src/function/argument.rs b/vm/src/function/argument.rs index 59693fff4..bc5190fac 100644 --- a/vm/src/function/argument.rs +++ b/vm/src/function/argument.rs @@ -3,8 +3,7 @@ use crate::{ builtins::{iter::PySequenceIterator, PyDict, PyDictRef}, convert::ToPyObject, protocol::{PyIter, PyIterIter, PyMapping, PyMappingMethods}, - AsObject, PyObject, PyObjectRef, PyObjectWrap, PyResult, PyValue, TryFromObject, - VirtualMachine, + AsObject, PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, VirtualMachine, }; use std::{borrow::Borrow, marker::PhantomData}; @@ -33,9 +32,9 @@ impl AsRef for ArgCallable { } } -impl PyObjectWrap for ArgCallable { - fn into_object(self) -> PyObjectRef { - self.obj +impl From for PyObjectRef { + fn from(value: ArgCallable) -> PyObjectRef { + value.obj } } @@ -70,7 +69,7 @@ impl ArgIterable { pub fn iter<'a>(&self, vm: &'a VirtualMachine) -> PyResult> { let iter = PyIter::new(match self.iterfn { Some(f) => f(self.iterable.clone(), vm)?, - None => PySequenceIterator::new(self.iterable.clone(), vm)?.into_object(vm), + None => PySequenceIterator::new(self.iterable.clone(), vm)?.into_pyobject(vm), }); iter.into_iter(vm) } @@ -130,10 +129,9 @@ impl AsRef for ArgMapping { } } -impl PyObjectWrap for ArgMapping { - #[inline(always)] - fn into_object(self) -> PyObjectRef { - self.obj +impl From for PyObjectRef { + fn from(value: ArgMapping) -> PyObjectRef { + value.obj } } diff --git a/vm/src/lib.rs b/vm/src/lib.rs index b1918ea28..862aba2f4 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -89,7 +89,7 @@ mod pyobject { pub use self::convert::{TryFromBorrowedObject, TryFromObject}; // pyobject items pub use self::pyobject::{ - AsObject, PyContext, PyMethod, PyObjectWrap, PyRefExact, PyResult, PyStructSequence, PyValue, + AsObject, PyContext, PyMethod, PyRefExact, PyResult, PyStructSequence, PyValue, }; // pyobjectrc items pub use self::pyobject::{PyObject, PyObjectRef, PyObjectView, PyObjectWeak, PyRef, PyWeakRef}; diff --git a/vm/src/macros.rs b/vm/src/macros.rs index d1a2a8ba5..99e691481 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -72,7 +72,7 @@ macro_rules! py_namespace { /// use rustpython_vm::{PyValue}; /// /// # rustpython_vm::Interpreter::default().enter(|vm| { -/// let obj = PyInt::from(0).into_object(vm); +/// let obj = PyInt::from(0).into_pyobject(vm); /// assert_eq!( /// "int", /// match_class!(match obj { @@ -96,7 +96,7 @@ macro_rules! py_namespace { /// use rustpython_vm::{ PyValue}; /// /// # rustpython_vm::Interpreter::default().enter(|vm| { -/// let obj = PyInt::from(0).into_object(vm); +/// let obj = PyInt::from(0).into_pyobject(vm); /// /// let int_value = match_class!(match obj { /// i @ PyInt => i.as_bigint().clone(), diff --git a/vm/src/protocol/buffer.rs b/vm/src/protocol/buffer.rs index 7a871beed..5040a03e1 100644 --- a/vm/src/protocol/buffer.rs +++ b/vm/src/protocol/buffer.rs @@ -9,8 +9,8 @@ use crate::{ pyobject::PyObjectPayload, sliceable::wrap_index, types::{Constructor, Unconstructible}, - AsObject, PyObject, PyObjectRef, PyObjectView, PyObjectWrap, PyRef, PyResult, PyValue, - TryFromBorrowedObject, VirtualMachine, + AsObject, PyObject, PyObjectRef, PyObjectView, PyRef, PyResult, PyValue, TryFromBorrowedObject, + VirtualMachine, }; use itertools::Itertools; use std::{borrow::Cow, fmt::Debug, ops::Range}; @@ -65,7 +65,7 @@ impl PyBuffer { pub fn from_byte_vector(bytes: Vec, vm: &VirtualMachine) -> Self { let bytes_len = bytes.len(); PyBuffer::new( - PyValue::into_object(VecBuffer::from(bytes), vm), + PyValue::into_pyobject(VecBuffer::from(bytes), vm), BufferDescriptor::simple(bytes_len, true), &VEC_BUFFER_METHODS, ) @@ -421,14 +421,14 @@ impl PyRef { pub fn into_pybuffer(self, readonly: bool) -> PyBuffer { let len = self.data.lock().len(); PyBuffer::new( - self.into_object(), + self.into(), BufferDescriptor::simple(len, readonly), &VEC_BUFFER_METHODS, ) } pub fn into_pybuffer_with_descriptor(self, desc: BufferDescriptor) -> PyBuffer { - PyBuffer::new(self.into_object(), desc, &VEC_BUFFER_METHODS) + PyBuffer::new(self.into(), desc, &VEC_BUFFER_METHODS) } } diff --git a/vm/src/protocol/iter.rs b/vm/src/protocol/iter.rs index d9b347249..5f137aabd 100644 --- a/vm/src/protocol/iter.rs +++ b/vm/src/protocol/iter.rs @@ -1,8 +1,7 @@ use crate::{ builtins::iter::PySequenceIterator, convert::{ToPyObject, ToPyResult}, - AsObject, PyObject, PyObjectRef, PyObjectWrap, PyResult, PyValue, TryFromObject, - VirtualMachine, + AsObject, PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, VirtualMachine, }; use std::borrow::Borrow; use std::ops::Deref; @@ -70,9 +69,9 @@ impl PyIter { } } -impl PyObjectWrap for PyIter { - fn into_object(self) -> PyObjectRef { - self.0 +impl From> for PyObjectRef { + fn from(value: PyIter) -> PyObjectRef { + value.0 } } @@ -134,7 +133,7 @@ impl TryFromObject for PyIter { ))) } } else if let Ok(seq_iter) = PySequenceIterator::new(iter_target.clone(), vm) { - Ok(Self(seq_iter.into_object(vm))) + Ok(Self(seq_iter.into_pyobject(vm))) } else { Err(vm.new_type_error(format!( "'{}' object is not iterable", diff --git a/vm/src/protocol/sequence.rs b/vm/src/protocol/sequence.rs index ca055d5c2..d48b86f81 100644 --- a/vm/src/protocol/sequence.rs +++ b/vm/src/protocol/sequence.rs @@ -229,7 +229,7 @@ impl PySequence<'_> { stop: stop.to_pyobject(vm), step: None, }; - mapping.subscript(&slice.into_object(vm), vm) + mapping.subscript(&slice.into_pyobject(vm), vm) } else { Err(vm.new_type_error(format!("'{}' object is unsliceable", self.obj.class()))) } @@ -249,7 +249,7 @@ impl PySequence<'_> { stop: stop.to_pyobject(vm), step: None, }; - f(&mapping, &slice.into_object(vm), value, vm) + f(&mapping, &slice.into_pyobject(vm), value, vm) } else { Err(vm.new_type_error(format!( "'{}' object doesn't support slice {}", diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index e127997ab..e3ce56451 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -526,7 +526,7 @@ where { #[inline(always)] fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { - PyValue::into_object(self, vm) + PyValue::into_pyobject(self, vm) } } @@ -564,7 +564,7 @@ pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static { fn class(vm: &VirtualMachine) -> &PyTypeRef; #[inline] - fn into_object(self, vm: &VirtualMachine) -> PyObjectRef { + fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { self.into_ref(vm).into() } @@ -685,23 +685,6 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { } } -pub trait PyObjectWrap -where - Self: AsObject, -{ - fn into_object(self) -> PyObjectRef; -} - -impl From for PyObjectRef -where - T: PyObjectWrap, -{ - #[inline(always)] - fn from(py_ref: T) -> Self { - py_ref.into_object() - } -} - #[derive(Debug)] pub enum PyMethod { Function { diff --git a/vm/src/pyobjectrc.rs b/vm/src/pyobjectrc.rs index a66fa1ef5..fbdbc784f 100644 --- a/vm/src/pyobjectrc.rs +++ b/vm/src/pyobjectrc.rs @@ -3,7 +3,7 @@ use crate::common::linked_list::{Link, LinkedList, Pointers}; use crate::common::lock::{PyMutex, PyMutexGuard, PyRwLock}; use crate::common::refcount::RefCount; use crate::{ - _pyobject::{AsObject, PyObjectPayload, PyObjectWrap, PyResult}, + _pyobject::{AsObject, PyObjectPayload, PyResult}, builtins::{PyBaseExceptionRef, PyDictRef, PyTypeRef}, vm::VirtualMachine, }; @@ -792,10 +792,10 @@ impl Borrow for PyObjectWeak { } } -impl PyObjectWrap for PyObjectWeak { +impl From for PyRef { #[inline(always)] - fn into_object(self) -> PyObjectRef { - self.weak.into_object() + fn from(value: PyObjectWeak) -> Self { + value.weak } } @@ -999,13 +999,13 @@ where } } -impl PyObjectWrap for PyRef +impl From> for PyObjectRef where T: PyObjectPayload, { #[inline] - fn into_object(self) -> PyObjectRef { - let me = ManuallyDrop::new(self); + fn from(value: PyRef) -> Self { + let me = ManuallyDrop::new(value); PyObjectRef { ptr: me.ptr.cast() } } } diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index a2ec71335..c13a82990 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -33,8 +33,7 @@ mod builtins { stdlib::sys, types::PyComparisonOp, utils::Either, - AsObject, PyObject, PyObjectRef, PyObjectWrap, PyRef, PyResult, PyValue, TryFromObject, - VirtualMachine, + AsObject, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine, }; use num_traits::{Signed, ToPrimitive, Zero}; @@ -433,8 +432,8 @@ mod builtins { } #[pyfunction] - fn locals(vm: &VirtualMachine) -> PyResult { - vm.current_locals().map(|x| x.into_object()) + fn locals(vm: &VirtualMachine) -> PyResult { + vm.current_locals() } fn min_or_max( @@ -690,7 +689,7 @@ mod builtins { })?; let len = obj.length(vm)?; let obj_iterator = PyReverseSequenceIterator::new(obj, len); - Ok(obj_iterator.into_object(vm)) + Ok(obj_iterator.into_pyobject(vm)) } } @@ -793,7 +792,7 @@ mod builtins { vm.new_type_error("vars() argument must have __dict__ attribute".to_owned()) }) } else { - Ok(vm.current_locals()?.into_object()) + Ok(vm.current_locals()?.into()) } } diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index 54912b2ce..0289d9a3d 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -571,7 +571,7 @@ mod _collections { impl Iterable for PyDeque { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - Ok(PyDequeIterator::new(zelf).into_object(vm)) + Ok(PyDequeIterator::new(zelf).into_pyobject(vm)) } } diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 92873bec6..1bf65dd2a 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -114,7 +114,7 @@ mod _io { types::{Constructor, Destructor, IterNext, Iterable}, utils::Either, vm::{ReprGuard, VirtualMachine}, - AsObject, PyContext, PyObject, PyObjectRef, PyObjectWrap, PyRef, PyResult, PyValue, + AsObject, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromBorrowedObject, TryFromObject, }; use bstr::ByteSlice; @@ -3313,7 +3313,7 @@ mod _io { fn getbuffer(self, vm: &VirtualMachine) -> PyResult { let len = self.buffer.read().cursor.get_ref().len(); let buffer = PyBuffer::new( - self.into_object(), + self.into(), BufferDescriptor::simple(len, false), &BYTES_IO_BUFFER_METHODS, ); diff --git a/vm/src/stdlib/sre.rs b/vm/src/stdlib/sre.rs index 63f17f27d..3a9b85bfd 100644 --- a/vm/src/stdlib/sre.rs +++ b/vm/src/stdlib/sre.rs @@ -484,7 +484,7 @@ mod _sre { /* get segment following last match */ sublist.push(slice_drive(&state.string, last_pos, state.end, vm)); - let list = PyList::from(sublist).into_object(vm); + let list = PyList::from(sublist).into_pyobject(vm); let join_type: PyObjectRef = if zelf.isbytes { vm.ctx.new_bytes(vec![]).into() diff --git a/vm/src/stdlib/symtable.rs b/vm/src/stdlib/symtable.rs index 390b24ac6..e847b0f05 100644 --- a/vm/src/stdlib/symtable.rs +++ b/vm/src/stdlib/symtable.rs @@ -143,7 +143,7 @@ mod symtable { .symtable .sub_tables .iter() - .map(|t| to_py_symbol_table(t.clone()).into_object(vm)) + .map(|t| to_py_symbol_table(t.clone()).into_pyobject(vm)) .collect(); Ok(children) } @@ -231,7 +231,7 @@ mod symtable { let namespaces = self .namespaces .iter() - .map(|table| to_py_symbol_table(table.clone()).into_object(vm)) + .map(|table| to_py_symbol_table(table.clone()).into_pyobject(vm)) .collect(); Ok(namespaces) } diff --git a/vm/src/stdlib/weakref.rs b/vm/src/stdlib/weakref.rs index e5eefddef..59620625d 100644 --- a/vm/src/stdlib/weakref.rs +++ b/vm/src/stdlib/weakref.rs @@ -9,7 +9,7 @@ pub(crate) use _weakref::make_module; #[pymodule] mod _weakref { use crate::builtins::{PyDictRef, PyTypeRef, PyWeak}; - use crate::{PyObjectRef, PyObjectWrap, PyResult, VirtualMachine}; + use crate::{PyObjectRef, PyRef, PyResult, VirtualMachine}; #[pyattr(name = "ref")] fn ref_(vm: &VirtualMachine) -> PyTypeRef { @@ -40,7 +40,7 @@ mod _weakref { #[pyfunction] fn getweakrefs(obj: PyObjectRef) -> Vec { match obj.get_weak_references() { - Some(v) => v.into_iter().map(|weak| weak.into_object()).collect(), + Some(v) => v.into_iter().map(|weak| PyRef::from(weak).into()).collect(), None => vec![], } } diff --git a/vm/src/utils.rs b/vm/src/utils.rs index 8ef67dec6..ca811be2c 100644 --- a/vm/src/utils.rs +++ b/vm/src/utils.rs @@ -1,7 +1,7 @@ use crate::{ builtins::{PyFloat, PyStr}, convert::{ToPyException, ToPyObject}, - AsObject, PyObject, PyObjectRef, PyObjectWrap, PyResult, TryFromObject, VirtualMachine, + AsObject, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, }; use num_traits::ToPrimitive; use std::borrow::Borrow; @@ -31,12 +31,12 @@ impl, B: AsRef> AsRef for Either { } } -impl PyObjectWrap for Either { +impl, B: Into> From> for PyObjectRef { #[inline(always)] - fn into_object(self) -> PyObjectRef { - match self { - Either::A(a) => a.into_object(), - Either::B(b) => b.into_object(), + fn from(value: Either) -> Self { + match value { + Either::A(a) => a.into(), + Either::B(b) => b.into(), } } } diff --git a/vm/src/vm_new.rs b/vm/src/vm_new.rs index 701cd52e6..6f03565d0 100644 --- a/vm/src/vm_new.rs +++ b/vm/src/vm_new.rs @@ -10,7 +10,7 @@ use crate::{ convert::ToPyObject, scope::Scope, vm::VirtualMachine, - AsObject, PyObject, PyObjectRef, PyObjectWrap, PyRef, PyValue, + AsObject, PyObject, PyObjectRef, PyRef, PyValue, }; /// Collection of object creation helpers @@ -44,7 +44,7 @@ impl VirtualMachine { .unwrap_or_else(|| self.ctx.none()), self, ); - module.into_object() + module.into() } pub fn new_scope_with_builtins(&self) -> Scope { diff --git a/wasm/lib/src/browser_module.rs b/wasm/lib/src/browser_module.rs index 2cb35bcc4..d73031b28 100644 --- a/wasm/lib/src/browser_module.rs +++ b/wasm/lib/src/browser_module.rs @@ -112,7 +112,7 @@ mod _browser { JsFuture::from(response_format.get_response(&response)?).await }; - Ok(PyPromise::from_future(future).into_object(vm)) + Ok(PyPromise::from_future(future).into_pyobject(vm)) } #[pyfunction] @@ -253,7 +253,7 @@ mod _browser { }) }; - Ok(PyPromise::from_future(future).into_object(vm)) + Ok(PyPromise::from_future(future).into_pyobject(vm)) } } diff --git a/wasm/lib/src/js_module.rs b/wasm/lib/src/js_module.rs index 0f908af28..a81281ae9 100644 --- a/wasm/lib/src/js_module.rs +++ b/wasm/lib/src/js_module.rs @@ -14,12 +14,11 @@ mod _js { use js_sys::{Array, Object, Promise, Reflect}; use rustpython_vm::{ builtins::{PyBaseExceptionRef, PyFloat, PyStrRef, PyTypeRef}, - convert::ToPyObject, + convert::{IntoObject, ToPyObject}, function::{ArgCallable, OptionalArg, OptionalOption, PosArgs}, protocol::PyIterReturn, types::{IterNext, IterNextIterable}, - PyObjectRef, PyObjectView, PyObjectWrap, PyRef, PyResult, PyValue, TryFromObject, - VirtualMachine, + PyObjectRef, PyObjectView, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine, }; use std::{cell, fmt, future}; use wasm_bindgen::{closure::Closure, prelude::*, JsCast}; @@ -322,11 +321,11 @@ mod _js { } }; stored_vm_from_wasm(&wasm_vm).interp.enter(move |vm| { - let mut pyargs = vec![PyJsValue::new(this).into_object(vm)]; + let mut pyargs = vec![PyJsValue::new(this).into_pyobject(vm)]; pyargs.extend( Vec::from(args) .into_iter() - .map(|arg| PyJsValue::new(arg).into_object(vm)), + .map(|arg| PyJsValue::new(arg).into_pyobject(vm)), ); let res = vm.invoke(&py_obj, pyargs); convert::pyresult_to_jsresult(vm, res) @@ -524,8 +523,8 @@ mod _js { vm.invoke( then, ( - on_fulfill.map(|c| c.into_object()), - on_reject.map(|c| c.into_object()), + on_fulfill.map(IntoObject::into_object), + on_reject.map(IntoObject::into_object), ), ), vm, From 860d7e1562437036b58c74eef17f2d107745b0af Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 19 Apr 2022 01:00:15 +0900 Subject: [PATCH 2/5] inline and cold --- vm/src/function/argument.rs | 7 +++++++ vm/src/protocol/mapping.rs | 4 ++++ vm/src/types/zoo.rs | 2 ++ 3 files changed, 13 insertions(+) diff --git a/vm/src/function/argument.rs b/vm/src/function/argument.rs index bc5190fac..2a4b5743e 100644 --- a/vm/src/function/argument.rs +++ b/vm/src/function/argument.rs @@ -13,6 +13,7 @@ pub struct ArgCallable { } impl ArgCallable { + #[inline(always)] pub fn invoke(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { vm.invoke(&self.obj, args) } @@ -33,6 +34,7 @@ impl AsRef for ArgCallable { } impl From for PyObjectRef { + #[inline(always)] fn from(value: ArgCallable) -> PyObjectRef { value.obj } @@ -103,6 +105,7 @@ pub struct ArgMapping { } impl ArgMapping { + #[inline(always)] pub fn from_dict_exact(dict: PyDictRef) -> Self { Self { obj: dict.into(), @@ -110,6 +113,7 @@ impl ArgMapping { } } + #[inline(always)] pub fn mapping(&self) -> PyMapping { PyMapping::with_methods(&self.obj, self.mapping_methods) } @@ -130,6 +134,7 @@ impl AsRef for ArgMapping { } impl From for PyObjectRef { + #[inline(always)] fn from(value: ArgMapping) -> PyObjectRef { value.obj } @@ -158,9 +163,11 @@ impl TryFromObject for ArgMapping { pub struct ArgSequence(Vec); impl ArgSequence { + #[inline(always)] pub fn into_vec(self) -> Vec { self.0 } + #[inline(always)] pub fn as_slice(&self) -> &[T] { &self.0 } diff --git a/vm/src/protocol/mapping.rs b/vm/src/protocol/mapping.rs index d78bda459..f8ec7437d 100644 --- a/vm/src/protocol/mapping.rs +++ b/vm/src/protocol/mapping.rs @@ -26,6 +26,7 @@ pub struct PyMapping<'a> { } impl<'a> From<&'a PyObject> for PyMapping<'a> { + #[inline(always)] fn from(obj: &'a PyObject) -> Self { Self { obj, @@ -35,12 +36,14 @@ impl<'a> From<&'a PyObject> for PyMapping<'a> { } impl AsRef for PyMapping<'_> { + #[inline(always)] fn as_ref(&self) -> &PyObject { self.obj } } impl<'a> PyMapping<'a> { + #[inline(always)] pub fn with_methods(obj: &'a PyObject, methods: PyMappingMethods) -> Self { Self { obj, @@ -60,6 +63,7 @@ impl<'a> PyMapping<'a> { impl PyMapping<'_> { // PyMapping::Check + #[inline] pub fn check(&self, vm: &VirtualMachine) -> bool { self.methods(vm).subscript.is_some() } diff --git a/vm/src/types/zoo.rs b/vm/src/types/zoo.rs index cef5e98a4..5ea301470 100644 --- a/vm/src/types/zoo.rs +++ b/vm/src/types/zoo.rs @@ -91,6 +91,7 @@ pub struct TypeZoo { } impl TypeZoo { + #[cold] pub(crate) fn init() -> Self { let (type_type, object_type, weakref_type) = crate::pyobject::init_type_hierarchy(); Self { @@ -179,6 +180,7 @@ impl TypeZoo { } /// Fill attributes of builtin types. + #[cold] pub(crate) fn extend(context: &PyContext) { pytype::init(context); object::init(context); From af84587543df5c4ed0c62457797e0193940ae7bf Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 19 Apr 2022 01:07:17 +0900 Subject: [PATCH 3/5] vm::function::{argument => protocol}.rs --- vm/src/function.rs | 4 ++-- vm/src/function/{argument.rs => protocol.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename vm/src/function/{argument.rs => protocol.rs} (100%) diff --git a/vm/src/function.rs b/vm/src/function.rs index a7c9eea28..266f7feaf 100644 --- a/vm/src/function.rs +++ b/vm/src/function.rs @@ -1,7 +1,7 @@ -mod argument; mod arithmetic; mod buffer; mod number; +mod protocol; use crate::{ builtins::{PyBaseExceptionRef, PyTupleRef, PyTypeRef}, @@ -13,10 +13,10 @@ use indexmap::IndexMap; use itertools::Itertools; use std::{marker::PhantomData, ops::RangeInclusive}; -pub use argument::{ArgCallable, ArgIterable, ArgMapping, ArgSequence}; pub use arithmetic::{PyArithmeticValue, PyComparisonValue}; pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike}; pub use number::{ArgIntoBool, ArgIntoComplex, ArgIntoFloat}; +pub use protocol::{ArgCallable, ArgIterable, ArgMapping, ArgSequence}; pub trait IntoFuncArgs: Sized { fn into_args(self, vm: &VirtualMachine) -> FuncArgs; diff --git a/vm/src/function/argument.rs b/vm/src/function/protocol.rs similarity index 100% rename from vm/src/function/argument.rs rename to vm/src/function/protocol.rs From abe3d6bc8ea0a1775f1866d7c14eb1a95cbbc50f Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 19 Apr 2022 01:19:16 +0900 Subject: [PATCH 4/5] vm/src/function/argument.rs --- vm/src/function.rs | 552 +----------------------------------- vm/src/function/argument.rs | 545 +++++++++++++++++++++++++++++++++++ 2 files changed, 553 insertions(+), 544 deletions(-) create mode 100644 vm/src/function/argument.rs diff --git a/vm/src/function.rs b/vm/src/function.rs index 266f7feaf..9ff8d0514 100644 --- a/vm/src/function.rs +++ b/vm/src/function.rs @@ -1,560 +1,24 @@ +mod argument; mod arithmetic; mod buffer; mod number; mod protocol; use crate::{ - builtins::{PyBaseExceptionRef, PyTupleRef, PyTypeRef}, - convert::{ToPyObject, ToPyResult}, - pyobject::PyThreadingConstraint, - AsObject, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine, + builtins::PyTupleRef, convert::ToPyResult, pyobject::PyThreadingConstraint, PyObject, + PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine, }; -use indexmap::IndexMap; -use itertools::Itertools; -use std::{marker::PhantomData, ops::RangeInclusive}; +use std::marker::PhantomData; +pub use argument::{ + ArgumentError, FromArgOptional, FromArgs, FuncArgs, IntoFuncArgs, KwArgs, OptionalArg, + OptionalOption, PosArgs, +}; pub use arithmetic::{PyArithmeticValue, PyComparisonValue}; pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike}; pub use number::{ArgIntoBool, ArgIntoComplex, ArgIntoFloat}; pub use protocol::{ArgCallable, ArgIterable, ArgMapping, ArgSequence}; -pub trait IntoFuncArgs: Sized { - fn into_args(self, vm: &VirtualMachine) -> FuncArgs; - fn into_method_args(self, obj: PyObjectRef, vm: &VirtualMachine) -> FuncArgs { - let mut args = self.into_args(vm); - args.prepend_arg(obj); - args - } -} - -impl IntoFuncArgs for T -where - T: Into, -{ - fn into_args(self, _vm: &VirtualMachine) -> FuncArgs { - self.into() - } -} - -// A tuple of values that each implement `ToPyObject` represents a sequence of -// arguments that can be bound and passed to a built-in function. -macro_rules! into_func_args_from_tuple { - ($(($n:tt, $T:ident)),*) => { - impl<$($T,)*> IntoFuncArgs for ($($T,)*) - where - $($T: ToPyObject,)* - { - #[inline] - fn into_args(self, vm: &VirtualMachine) -> FuncArgs { - let ($($n,)*) = self; - PosArgs::new(vec![$($n.to_pyobject(vm),)*]).into() - } - - #[inline] - fn into_method_args(self, obj: PyObjectRef, vm: &VirtualMachine) -> FuncArgs { - let ($($n,)*) = self; - PosArgs::new(vec![obj, $($n.to_pyobject(vm),)*]).into() - } - } - }; -} - -into_func_args_from_tuple!((v1, T1)); -into_func_args_from_tuple!((v1, T1), (v2, T2)); -into_func_args_from_tuple!((v1, T1), (v2, T2), (v3, T3)); -into_func_args_from_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4)); -into_func_args_from_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4), (v5, T5)); - -/// The `FuncArgs` struct is one of the most used structs then creating -/// a rust function that can be called from python. It holds both positional -/// arguments, as well as keyword arguments passed to the function. -#[derive(Debug, Default, Clone)] -pub struct FuncArgs { - pub args: Vec, - // sorted map, according to https://www.python.org/dev/peps/pep-0468/ - pub kwargs: IndexMap, -} - -/// Conversion from vector of python objects to function arguments. -impl From for FuncArgs -where - A: Into, -{ - fn from(args: A) -> Self { - FuncArgs { - args: args.into().into_vec(), - kwargs: IndexMap::new(), - } - } -} - -impl From for FuncArgs { - fn from(kwargs: KwArgs) -> Self { - FuncArgs { - args: Vec::new(), - kwargs: kwargs.0, - } - } -} - -impl FromArgs for FuncArgs { - fn from_args(_vm: &VirtualMachine, args: &mut FuncArgs) -> Result { - Ok(std::mem::take(args)) - } -} - -impl FuncArgs { - pub fn new(args: A, kwargs: K) -> Self - where - A: Into, - K: Into, - { - let PosArgs(args) = args.into(); - let KwArgs(kwargs) = kwargs.into(); - Self { args, kwargs } - } - - pub fn with_kwargs_names(mut args: A, kwarg_names: KW) -> Self - where - A: ExactSizeIterator, - KW: ExactSizeIterator, - { - // last `kwarg_names.len()` elements of args in order of appearance in the call signature - let total_argc = args.len(); - let kwargc = kwarg_names.len(); - let posargc = total_argc - kwargc; - - let posargs = args.by_ref().take(posargc).collect(); - - let kwargs = kwarg_names.zip_eq(args).collect::>(); - - FuncArgs { - args: posargs, - kwargs, - } - } - - pub fn prepend_arg(&mut self, item: PyObjectRef) { - self.args.reserve_exact(1); - self.args.insert(0, item) - } - - pub fn shift(&mut self) -> PyObjectRef { - self.args.remove(0) - } - - pub fn get_kwarg(&self, key: &str, default: PyObjectRef) -> PyObjectRef { - self.kwargs - .get(key) - .cloned() - .unwrap_or_else(|| default.clone()) - } - - pub fn get_optional_kwarg(&self, key: &str) -> Option { - self.kwargs.get(key).cloned() - } - - pub fn get_optional_kwarg_with_type( - &self, - key: &str, - ty: PyTypeRef, - vm: &VirtualMachine, - ) -> PyResult> { - match self.get_optional_kwarg(key) { - Some(kwarg) => { - if kwarg.fast_isinstance(&ty) { - Ok(Some(kwarg)) - } else { - let expected_ty_name = &ty.name(); - let kwarg_class = kwarg.class(); - let actual_ty_name = &kwarg_class.name(); - Err(vm.new_type_error(format!( - "argument of type {} is required for named parameter `{}` (got: {})", - expected_ty_name, key, actual_ty_name - ))) - } - } - None => Ok(None), - } - } - - pub fn take_positional(&mut self) -> Option { - if self.args.is_empty() { - None - } else { - Some(self.args.remove(0)) - } - } - - pub fn take_positional_keyword(&mut self, name: &str) -> Option { - self.take_positional().or_else(|| self.take_keyword(name)) - } - - pub fn take_keyword(&mut self, name: &str) -> Option { - self.kwargs.swap_remove(name) - } - - pub fn remaining_keywords(&mut self) -> impl Iterator + '_ { - self.kwargs.drain(..) - } - - /// Binds these arguments to their respective values. - /// - /// If there is an insufficient number of arguments, there are leftover - /// arguments after performing the binding, or if an argument is not of - /// the expected type, a TypeError is raised. - /// - /// If the given `FromArgs` includes any conversions, exceptions raised - /// during the conversion will halt the binding and return the error. - pub fn bind(mut self, vm: &VirtualMachine) -> PyResult { - let given_args = self.args.len(); - let bound = T::from_args(vm, &mut self) - .map_err(|e| e.into_exception(T::arity(), given_args, vm))?; - - if !self.args.is_empty() { - Err(vm.new_type_error(format!( - "Expected at most {} arguments ({} given)", - T::arity().end(), - given_args, - ))) - } else if let Some(err) = self.check_kwargs_empty(vm) { - Err(err) - } else { - Ok(bound) - } - } - - pub fn check_kwargs_empty(&self, vm: &VirtualMachine) -> Option { - self.kwargs - .keys() - .next() - .map(|k| vm.new_type_error(format!("Unexpected keyword argument {}", k))) - } -} - -/// An error encountered while binding arguments to the parameters of a Python -/// function call. -pub enum ArgumentError { - /// The call provided fewer positional arguments than the function requires. - TooFewArgs, - /// The call provided more positional arguments than the function accepts. - TooManyArgs, - /// The function doesn't accept a keyword argument with the given name. - InvalidKeywordArgument(String), - /// The function require a keyword argument with the given name, but one wasn't provided - RequiredKeywordArgument(String), - /// An exception was raised while binding arguments to the function - /// parameters. - Exception(PyBaseExceptionRef), -} - -impl From for ArgumentError { - fn from(ex: PyBaseExceptionRef) -> Self { - ArgumentError::Exception(ex) - } -} - -impl ArgumentError { - fn into_exception( - self, - arity: RangeInclusive, - num_given: usize, - vm: &VirtualMachine, - ) -> PyBaseExceptionRef { - match self { - ArgumentError::TooFewArgs => vm.new_type_error(format!( - "Expected at least {} arguments ({} given)", - arity.start(), - num_given - )), - ArgumentError::TooManyArgs => vm.new_type_error(format!( - "Expected at most {} arguments ({} given)", - arity.end(), - num_given - )), - ArgumentError::InvalidKeywordArgument(name) => { - vm.new_type_error(format!("{} is an invalid keyword argument", name)) - } - ArgumentError::RequiredKeywordArgument(name) => { - vm.new_type_error(format!("Required keyqord only argument {}", name)) - } - ArgumentError::Exception(ex) => ex, - } - } -} - -/// Implemented by any type that can be accepted as a parameter to a built-in -/// function. -/// -pub trait FromArgs: Sized { - /// The range of positional arguments permitted by the function signature. - /// - /// Returns an empty range if not applicable. - fn arity() -> RangeInclusive { - 0..=0 - } - - /// Extracts this item from the next argument(s). - fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result; -} - -pub trait FromArgOptional { - type Inner: TryFromObject; - fn from_inner(x: Self::Inner) -> Self; -} -impl FromArgOptional for OptionalArg { - type Inner = T; - fn from_inner(x: T) -> Self { - Self::Present(x) - } -} -impl FromArgOptional for T { - type Inner = Self; - fn from_inner(x: Self) -> Self { - x - } -} - -/// A map of keyword arguments to their values. -/// -/// A built-in function with a `KwArgs` parameter is analogous to a Python -/// function with `**kwargs`. All remaining keyword arguments are extracted -/// (and hence the function will permit an arbitrary number of them). -/// -/// `KwArgs` optionally accepts a generic type parameter to allow type checks -/// or conversions of each argument. -/// -/// Note: -/// -/// KwArgs is only for functions that accept arbitrary keyword arguments. For -/// functions that accept only *specific* named arguments, a rust struct with -/// an appropriate FromArgs implementation must be created. -#[derive(Clone)] -pub struct KwArgs(IndexMap); - -impl KwArgs { - pub fn new(map: IndexMap) -> Self { - KwArgs(map) - } - - pub fn pop_kwarg(&mut self, name: &str) -> Option { - self.0.remove(name) - } -} -impl FromIterator<(String, T)> for KwArgs { - fn from_iter>(iter: I) -> Self { - KwArgs(iter.into_iter().collect()) - } -} -impl Default for KwArgs { - fn default() -> Self { - KwArgs(IndexMap::new()) - } -} - -impl FromArgs for KwArgs -where - T: TryFromObject, -{ - fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { - let mut kwargs = IndexMap::new(); - for (name, value) in args.remaining_keywords() { - kwargs.insert(name, value.try_into_value(vm)?); - } - Ok(KwArgs(kwargs)) - } -} - -impl IntoIterator for KwArgs { - type Item = (String, T); - type IntoIter = indexmap::map::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -/// A list of positional argument values. -/// -/// A built-in function with a `PosArgs` parameter is analogous to a Python -/// function with `*args`. All remaining positional arguments are extracted -/// (and hence the function will permit an arbitrary number of them). -/// -/// `PosArgs` optionally accepts a generic type parameter to allow type checks -/// or conversions of each argument. -#[derive(Clone)] -pub struct PosArgs(Vec); - -impl PosArgs { - pub fn new(args: Vec) -> Self { - Self(args) - } - - pub fn into_vec(self) -> Vec { - self.0 - } - - pub fn iter(&self) -> std::slice::Iter { - self.0.iter() - } -} - -impl From> for PosArgs { - fn from(v: Vec) -> Self { - Self(v) - } -} - -impl From<()> for PosArgs { - fn from(_args: ()) -> Self { - Self(Vec::new()) - } -} - -impl AsRef<[T]> for PosArgs { - fn as_ref(&self) -> &[T] { - &self.0 - } -} - -impl PosArgs> { - pub fn into_tuple(self, vm: &VirtualMachine) -> PyTupleRef { - vm.ctx - .new_tuple(self.0.into_iter().map(Into::into).collect()) - } -} - -impl FromArgs for PosArgs -where - T: TryFromObject, -{ - fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { - let mut varargs = Vec::new(); - while let Some(value) = args.take_positional() { - varargs.push(value.try_into_value(vm)?); - } - Ok(PosArgs(varargs)) - } -} - -impl IntoIterator for PosArgs { - type Item = T; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl FromArgs for T -where - T: TryFromObject, -{ - fn arity() -> RangeInclusive { - 1..=1 - } - - fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { - let value = args.take_positional().ok_or(ArgumentError::TooFewArgs)?; - Ok(value.try_into_value(vm)?) - } -} - -/// An argument that may or may not be provided by the caller. -/// -/// This style of argument is not possible in pure Python. -#[derive(Debug, result_like::OptionLike, is_macro::Is)] -pub enum OptionalArg { - Present(T), - Missing, -} - -impl OptionalArg { - pub fn unwrap_or_none(self, vm: &VirtualMachine) -> PyObjectRef { - self.unwrap_or_else(|| vm.ctx.none()) - } -} - -pub type OptionalOption = OptionalArg>; - -impl OptionalOption { - #[inline] - pub fn flatten(self) -> Option { - match self { - OptionalArg::Present(Some(value)) => Some(value), - _ => None, - } - } -} - -impl FromArgs for OptionalArg -where - T: TryFromObject, -{ - fn arity() -> RangeInclusive { - 0..=1 - } - - fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { - let r = if let Some(value) = args.take_positional() { - OptionalArg::Present(value.try_into_value(vm)?) - } else { - OptionalArg::Missing - }; - Ok(r) - } -} - -// For functions that accept no arguments. Implemented explicitly instead of via -// macro below to avoid unused warnings. -impl FromArgs for () { - fn from_args(_vm: &VirtualMachine, _args: &mut FuncArgs) -> Result { - Ok(()) - } -} - -// A tuple of types that each implement `FromArgs` represents a sequence of -// arguments that can be bound and passed to a built-in function. -// -// Technically, a tuple can contain tuples, which can contain tuples, and so on, -// so this actually represents a tree of values to be bound from arguments, but -// in practice this is only used for the top-level parameters. -macro_rules! tuple_from_py_func_args { - ($($T:ident),+) => { - impl<$($T),+> FromArgs for ($($T,)+) - where - $($T: FromArgs),+ - { - fn arity() -> RangeInclusive { - let mut min = 0; - let mut max = 0; - $( - let (start, end) = $T::arity().into_inner(); - min += start; - max += end; - )+ - min..=max - } - - fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { - Ok(($($T::from_args(vm, args)?,)+)) - } - } - }; -} - -// Implement `FromArgs` for up to 7-tuples, allowing built-in functions to bind -// up to 7 top-level parameters (note that `PosArgs`, `KwArgs`, nested tuples, etc. -// count as 1, so this should actually be more than enough). -tuple_from_py_func_args!(A); -tuple_from_py_func_args!(A, B); -tuple_from_py_func_args!(A, B, C); -tuple_from_py_func_args!(A, B, C, D); -tuple_from_py_func_args!(A, B, C, D, E); -tuple_from_py_func_args!(A, B, C, D, E, F); -tuple_from_py_func_args!(A, B, C, D, E, F, G); -tuple_from_py_func_args!(A, B, C, D, E, F, G, H); - /// A built-in Python function. pub type PyNativeFunc = Box PyResult)>; diff --git a/vm/src/function/argument.rs b/vm/src/function/argument.rs new file mode 100644 index 000000000..b1ebe1155 --- /dev/null +++ b/vm/src/function/argument.rs @@ -0,0 +1,545 @@ +use crate::{ + builtins::{PyBaseExceptionRef, PyTupleRef, PyTypeRef}, + convert::ToPyObject, + AsObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine, +}; +use indexmap::IndexMap; +use itertools::Itertools; +use std::ops::RangeInclusive; + +pub trait IntoFuncArgs: Sized { + fn into_args(self, vm: &VirtualMachine) -> FuncArgs; + fn into_method_args(self, obj: PyObjectRef, vm: &VirtualMachine) -> FuncArgs { + let mut args = self.into_args(vm); + args.prepend_arg(obj); + args + } +} + +impl IntoFuncArgs for T +where + T: Into, +{ + fn into_args(self, _vm: &VirtualMachine) -> FuncArgs { + self.into() + } +} + +// A tuple of values that each implement `ToPyObject` represents a sequence of +// arguments that can be bound and passed to a built-in function. +macro_rules! into_func_args_from_tuple { + ($(($n:tt, $T:ident)),*) => { + impl<$($T,)*> IntoFuncArgs for ($($T,)*) + where + $($T: ToPyObject,)* + { + #[inline] + fn into_args(self, vm: &VirtualMachine) -> FuncArgs { + let ($($n,)*) = self; + PosArgs::new(vec![$($n.to_pyobject(vm),)*]).into() + } + + #[inline] + fn into_method_args(self, obj: PyObjectRef, vm: &VirtualMachine) -> FuncArgs { + let ($($n,)*) = self; + PosArgs::new(vec![obj, $($n.to_pyobject(vm),)*]).into() + } + } + }; +} + +into_func_args_from_tuple!((v1, T1)); +into_func_args_from_tuple!((v1, T1), (v2, T2)); +into_func_args_from_tuple!((v1, T1), (v2, T2), (v3, T3)); +into_func_args_from_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4)); +into_func_args_from_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4), (v5, T5)); + +/// The `FuncArgs` struct is one of the most used structs then creating +/// a rust function that can be called from python. It holds both positional +/// arguments, as well as keyword arguments passed to the function. +#[derive(Debug, Default, Clone)] +pub struct FuncArgs { + pub args: Vec, + // sorted map, according to https://www.python.org/dev/peps/pep-0468/ + pub kwargs: IndexMap, +} + +/// Conversion from vector of python objects to function arguments. +impl From for FuncArgs +where + A: Into, +{ + fn from(args: A) -> Self { + FuncArgs { + args: args.into().into_vec(), + kwargs: IndexMap::new(), + } + } +} + +impl From for FuncArgs { + fn from(kwargs: KwArgs) -> Self { + FuncArgs { + args: Vec::new(), + kwargs: kwargs.0, + } + } +} + +impl FromArgs for FuncArgs { + fn from_args(_vm: &VirtualMachine, args: &mut FuncArgs) -> Result { + Ok(std::mem::take(args)) + } +} + +impl FuncArgs { + pub fn new(args: A, kwargs: K) -> Self + where + A: Into, + K: Into, + { + let PosArgs(args) = args.into(); + let KwArgs(kwargs) = kwargs.into(); + Self { args, kwargs } + } + + pub fn with_kwargs_names(mut args: A, kwarg_names: KW) -> Self + where + A: ExactSizeIterator, + KW: ExactSizeIterator, + { + // last `kwarg_names.len()` elements of args in order of appearance in the call signature + let total_argc = args.len(); + let kwargc = kwarg_names.len(); + let posargc = total_argc - kwargc; + + let posargs = args.by_ref().take(posargc).collect(); + + let kwargs = kwarg_names.zip_eq(args).collect::>(); + + FuncArgs { + args: posargs, + kwargs, + } + } + + pub fn prepend_arg(&mut self, item: PyObjectRef) { + self.args.reserve_exact(1); + self.args.insert(0, item) + } + + pub fn shift(&mut self) -> PyObjectRef { + self.args.remove(0) + } + + pub fn get_kwarg(&self, key: &str, default: PyObjectRef) -> PyObjectRef { + self.kwargs + .get(key) + .cloned() + .unwrap_or_else(|| default.clone()) + } + + pub fn get_optional_kwarg(&self, key: &str) -> Option { + self.kwargs.get(key).cloned() + } + + pub fn get_optional_kwarg_with_type( + &self, + key: &str, + ty: PyTypeRef, + vm: &VirtualMachine, + ) -> PyResult> { + match self.get_optional_kwarg(key) { + Some(kwarg) => { + if kwarg.fast_isinstance(&ty) { + Ok(Some(kwarg)) + } else { + let expected_ty_name = &ty.name(); + let kwarg_class = kwarg.class(); + let actual_ty_name = &kwarg_class.name(); + Err(vm.new_type_error(format!( + "argument of type {} is required for named parameter `{}` (got: {})", + expected_ty_name, key, actual_ty_name + ))) + } + } + None => Ok(None), + } + } + + pub fn take_positional(&mut self) -> Option { + if self.args.is_empty() { + None + } else { + Some(self.args.remove(0)) + } + } + + pub fn take_positional_keyword(&mut self, name: &str) -> Option { + self.take_positional().or_else(|| self.take_keyword(name)) + } + + pub fn take_keyword(&mut self, name: &str) -> Option { + self.kwargs.swap_remove(name) + } + + pub fn remaining_keywords(&mut self) -> impl Iterator + '_ { + self.kwargs.drain(..) + } + + /// Binds these arguments to their respective values. + /// + /// If there is an insufficient number of arguments, there are leftover + /// arguments after performing the binding, or if an argument is not of + /// the expected type, a TypeError is raised. + /// + /// If the given `FromArgs` includes any conversions, exceptions raised + /// during the conversion will halt the binding and return the error. + pub fn bind(mut self, vm: &VirtualMachine) -> PyResult { + let given_args = self.args.len(); + let bound = T::from_args(vm, &mut self) + .map_err(|e| e.into_exception(T::arity(), given_args, vm))?; + + if !self.args.is_empty() { + Err(vm.new_type_error(format!( + "Expected at most {} arguments ({} given)", + T::arity().end(), + given_args, + ))) + } else if let Some(err) = self.check_kwargs_empty(vm) { + Err(err) + } else { + Ok(bound) + } + } + + pub fn check_kwargs_empty(&self, vm: &VirtualMachine) -> Option { + self.kwargs + .keys() + .next() + .map(|k| vm.new_type_error(format!("Unexpected keyword argument {}", k))) + } +} + +/// An error encountered while binding arguments to the parameters of a Python +/// function call. +pub enum ArgumentError { + /// The call provided fewer positional arguments than the function requires. + TooFewArgs, + /// The call provided more positional arguments than the function accepts. + TooManyArgs, + /// The function doesn't accept a keyword argument with the given name. + InvalidKeywordArgument(String), + /// The function require a keyword argument with the given name, but one wasn't provided + RequiredKeywordArgument(String), + /// An exception was raised while binding arguments to the function + /// parameters. + Exception(PyBaseExceptionRef), +} + +impl From for ArgumentError { + fn from(ex: PyBaseExceptionRef) -> Self { + ArgumentError::Exception(ex) + } +} + +impl ArgumentError { + fn into_exception( + self, + arity: RangeInclusive, + num_given: usize, + vm: &VirtualMachine, + ) -> PyBaseExceptionRef { + match self { + ArgumentError::TooFewArgs => vm.new_type_error(format!( + "Expected at least {} arguments ({} given)", + arity.start(), + num_given + )), + ArgumentError::TooManyArgs => vm.new_type_error(format!( + "Expected at most {} arguments ({} given)", + arity.end(), + num_given + )), + ArgumentError::InvalidKeywordArgument(name) => { + vm.new_type_error(format!("{} is an invalid keyword argument", name)) + } + ArgumentError::RequiredKeywordArgument(name) => { + vm.new_type_error(format!("Required keyqord only argument {}", name)) + } + ArgumentError::Exception(ex) => ex, + } + } +} + +/// Implemented by any type that can be accepted as a parameter to a built-in +/// function. +/// +pub trait FromArgs: Sized { + /// The range of positional arguments permitted by the function signature. + /// + /// Returns an empty range if not applicable. + fn arity() -> RangeInclusive { + 0..=0 + } + + /// Extracts this item from the next argument(s). + fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result; +} + +pub trait FromArgOptional { + type Inner: TryFromObject; + fn from_inner(x: Self::Inner) -> Self; +} +impl FromArgOptional for OptionalArg { + type Inner = T; + fn from_inner(x: T) -> Self { + Self::Present(x) + } +} +impl FromArgOptional for T { + type Inner = Self; + fn from_inner(x: Self) -> Self { + x + } +} + +/// A map of keyword arguments to their values. +/// +/// A built-in function with a `KwArgs` parameter is analogous to a Python +/// function with `**kwargs`. All remaining keyword arguments are extracted +/// (and hence the function will permit an arbitrary number of them). +/// +/// `KwArgs` optionally accepts a generic type parameter to allow type checks +/// or conversions of each argument. +/// +/// Note: +/// +/// KwArgs is only for functions that accept arbitrary keyword arguments. For +/// functions that accept only *specific* named arguments, a rust struct with +/// an appropriate FromArgs implementation must be created. +#[derive(Clone)] +pub struct KwArgs(IndexMap); + +impl KwArgs { + pub fn new(map: IndexMap) -> Self { + KwArgs(map) + } + + pub fn pop_kwarg(&mut self, name: &str) -> Option { + self.0.remove(name) + } +} +impl FromIterator<(String, T)> for KwArgs { + fn from_iter>(iter: I) -> Self { + KwArgs(iter.into_iter().collect()) + } +} +impl Default for KwArgs { + fn default() -> Self { + KwArgs(IndexMap::new()) + } +} + +impl FromArgs for KwArgs +where + T: TryFromObject, +{ + fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { + let mut kwargs = IndexMap::new(); + for (name, value) in args.remaining_keywords() { + kwargs.insert(name, value.try_into_value(vm)?); + } + Ok(KwArgs(kwargs)) + } +} + +impl IntoIterator for KwArgs { + type Item = (String, T); + type IntoIter = indexmap::map::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +/// A list of positional argument values. +/// +/// A built-in function with a `PosArgs` parameter is analogous to a Python +/// function with `*args`. All remaining positional arguments are extracted +/// (and hence the function will permit an arbitrary number of them). +/// +/// `PosArgs` optionally accepts a generic type parameter to allow type checks +/// or conversions of each argument. +#[derive(Clone)] +pub struct PosArgs(Vec); + +impl PosArgs { + pub fn new(args: Vec) -> Self { + Self(args) + } + + pub fn into_vec(self) -> Vec { + self.0 + } + + pub fn iter(&self) -> std::slice::Iter { + self.0.iter() + } +} + +impl From> for PosArgs { + fn from(v: Vec) -> Self { + Self(v) + } +} + +impl From<()> for PosArgs { + fn from(_args: ()) -> Self { + Self(Vec::new()) + } +} + +impl AsRef<[T]> for PosArgs { + fn as_ref(&self) -> &[T] { + &self.0 + } +} + +impl PosArgs> { + pub fn into_tuple(self, vm: &VirtualMachine) -> PyTupleRef { + vm.ctx + .new_tuple(self.0.into_iter().map(Into::into).collect()) + } +} + +impl FromArgs for PosArgs +where + T: TryFromObject, +{ + fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { + let mut varargs = Vec::new(); + while let Some(value) = args.take_positional() { + varargs.push(value.try_into_value(vm)?); + } + Ok(PosArgs(varargs)) + } +} + +impl IntoIterator for PosArgs { + type Item = T; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl FromArgs for T +where + T: TryFromObject, +{ + fn arity() -> RangeInclusive { + 1..=1 + } + + fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { + let value = args.take_positional().ok_or(ArgumentError::TooFewArgs)?; + Ok(value.try_into_value(vm)?) + } +} + +/// An argument that may or may not be provided by the caller. +/// +/// This style of argument is not possible in pure Python. +#[derive(Debug, result_like::OptionLike, is_macro::Is)] +pub enum OptionalArg { + Present(T), + Missing, +} + +impl OptionalArg { + pub fn unwrap_or_none(self, vm: &VirtualMachine) -> PyObjectRef { + self.unwrap_or_else(|| vm.ctx.none()) + } +} + +pub type OptionalOption = OptionalArg>; + +impl OptionalOption { + #[inline] + pub fn flatten(self) -> Option { + match self { + OptionalArg::Present(Some(value)) => Some(value), + _ => None, + } + } +} + +impl FromArgs for OptionalArg +where + T: TryFromObject, +{ + fn arity() -> RangeInclusive { + 0..=1 + } + + fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { + let r = if let Some(value) = args.take_positional() { + OptionalArg::Present(value.try_into_value(vm)?) + } else { + OptionalArg::Missing + }; + Ok(r) + } +} + +// For functions that accept no arguments. Implemented explicitly instead of via +// macro below to avoid unused warnings. +impl FromArgs for () { + fn from_args(_vm: &VirtualMachine, _args: &mut FuncArgs) -> Result { + Ok(()) + } +} + +// A tuple of types that each implement `FromArgs` represents a sequence of +// arguments that can be bound and passed to a built-in function. +// +// Technically, a tuple can contain tuples, which can contain tuples, and so on, +// so this actually represents a tree of values to be bound from arguments, but +// in practice this is only used for the top-level parameters. +macro_rules! tuple_from_py_func_args { + ($($T:ident),+) => { + impl<$($T),+> FromArgs for ($($T,)+) + where + $($T: FromArgs),+ + { + fn arity() -> RangeInclusive { + let mut min = 0; + let mut max = 0; + $( + let (start, end) = $T::arity().into_inner(); + min += start; + max += end; + )+ + min..=max + } + + fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result { + Ok(($($T::from_args(vm, args)?,)+)) + } + } + }; +} + +// Implement `FromArgs` for up to 7-tuples, allowing built-in functions to bind +// up to 7 top-level parameters (note that `PosArgs`, `KwArgs`, nested tuples, etc. +// count as 1, so this should actually be more than enough). +tuple_from_py_func_args!(A); +tuple_from_py_func_args!(A, B); +tuple_from_py_func_args!(A, B, C); +tuple_from_py_func_args!(A, B, C, D); +tuple_from_py_func_args!(A, B, C, D, E); +tuple_from_py_func_args!(A, B, C, D, E, F); +tuple_from_py_func_args!(A, B, C, D, E, F, G); +tuple_from_py_func_args!(A, B, C, D, E, F, G, H); From 554b2b9f48a50ac8fc70f9100673ea221b141da6 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 19 Apr 2022 01:25:36 +0900 Subject: [PATCH 5/5] vm/src/function/builtin.rs --- vm/src/{function.rs => function/builtin.rs} | 49 +------------------- vm/src/function/mod.rs | 50 +++++++++++++++++++++ 2 files changed, 52 insertions(+), 47 deletions(-) rename vm/src/{function.rs => function/builtin.rs} (76%) create mode 100644 vm/src/function/mod.rs diff --git a/vm/src/function.rs b/vm/src/function/builtin.rs similarity index 76% rename from vm/src/function.rs rename to vm/src/function/builtin.rs index 9ff8d0514..2ef026fbf 100644 --- a/vm/src/function.rs +++ b/vm/src/function/builtin.rs @@ -1,24 +1,9 @@ -mod argument; -mod arithmetic; -mod buffer; -mod number; -mod protocol; - +use super::{FromArgs, FuncArgs}; use crate::{ - builtins::PyTupleRef, convert::ToPyResult, pyobject::PyThreadingConstraint, PyObject, - PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine, + convert::ToPyResult, pyobject::PyThreadingConstraint, PyRef, PyResult, PyValue, VirtualMachine, }; use std::marker::PhantomData; -pub use argument::{ - ArgumentError, FromArgOptional, FromArgs, FuncArgs, IntoFuncArgs, KwArgs, OptionalArg, - OptionalOption, PosArgs, -}; -pub use arithmetic::{PyArithmeticValue, PyComparisonValue}; -pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike}; -pub use number::{ArgIntoBool, ArgIntoComplex, ArgIntoFloat}; -pub use protocol::{ArgCallable, ArgIterable, ArgMapping, ArgSequence}; - /// A built-in Python function. pub type PyNativeFunc = Box PyResult)>; @@ -155,36 +140,6 @@ into_py_native_func_tuple!( (v7, T7) ); -/// Tests that the predicate is True on a single value, or if the value is a tuple a tuple, then -/// test that any of the values contained within the tuples satisfies the predicate. Type parameter -/// T specifies the type that is expected, if the input value is not of that type or a tuple of -/// values of that type, then a TypeError is raised. -pub fn single_or_tuple_any( - obj: PyObjectRef, - predicate: &F, - message: &M, - vm: &VirtualMachine, -) -> PyResult -where - T: TryFromObject, - F: Fn(&T) -> PyResult, - M: Fn(&PyObject) -> String, -{ - match T::try_from_object(vm, obj.clone()) { - Ok(single) => (predicate)(&single), - Err(_) => { - let tuple = PyTupleRef::try_from_object(vm, obj.clone()) - .map_err(|_| vm.new_type_error((message)(&obj)))?; - for obj in tuple.as_slice().iter() { - if single_or_tuple_any(obj.clone(), predicate, message, vm)? { - return Ok(true); - } - } - Ok(false) - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/vm/src/function/mod.rs b/vm/src/function/mod.rs new file mode 100644 index 000000000..58e27e13d --- /dev/null +++ b/vm/src/function/mod.rs @@ -0,0 +1,50 @@ +mod argument; +mod arithmetic; +mod buffer; +mod builtin; +mod number; +mod protocol; + +pub use argument::{ + ArgumentError, FromArgOptional, FromArgs, FuncArgs, IntoFuncArgs, KwArgs, OptionalArg, + OptionalOption, PosArgs, +}; +pub use arithmetic::{PyArithmeticValue, PyComparisonValue}; +pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike}; +pub use builtin::{IntoPyNativeFunc, OwnedParam, PyNativeFunc, RefParam}; +pub use number::{ArgIntoBool, ArgIntoComplex, ArgIntoFloat}; +pub use protocol::{ArgCallable, ArgIterable, ArgMapping, ArgSequence}; + +use crate::{ + builtins::PyTupleRef, convert::TryFromObject, PyObject, PyObjectRef, PyResult, VirtualMachine, +}; + +/// Tests that the predicate is True on a single value, or if the value is a tuple a tuple, then +/// test that any of the values contained within the tuples satisfies the predicate. Type parameter +/// T specifies the type that is expected, if the input value is not of that type or a tuple of +/// values of that type, then a TypeError is raised. +pub fn single_or_tuple_any( + obj: PyObjectRef, + predicate: &F, + message: &M, + vm: &VirtualMachine, +) -> PyResult +where + T: TryFromObject, + F: Fn(&T) -> PyResult, + M: Fn(&PyObject) -> String, +{ + match T::try_from_object(vm, obj.clone()) { + Ok(single) => (predicate)(&single), + Err(_) => { + let tuple = PyTupleRef::try_from_object(vm, obj.clone()) + .map_err(|_| vm.new_type_error((message)(&obj)))?; + for obj in tuple.as_slice().iter() { + if single_or_tuple_any(obj.clone(), predicate, message, vm)? { + return Ok(true); + } + } + Ok(false) + } + } +}