mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
Merge pull request #3635 from youknowone/into-object
distinguish IntoObject::into_object() and PyValue::into_pyobject(vm)
This commit is contained in:
@@ -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},
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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<Self>, _vm: &VirtualMachine) -> PyResult<PyBuffer> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Self>, _vm: &VirtualMachine) -> PyResult<PyBuffer> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Self>, 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<Self>, 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)
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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::<PyTuple>() {
|
||||
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,
|
||||
))
|
||||
|
||||
@@ -1264,7 +1264,7 @@ impl Iterable for PyStr {
|
||||
Ok(PyStrIterator {
|
||||
internal: PyMutex::new((PositionIterInternal::new(zelf, 0), 0)),
|
||||
}
|
||||
.into_object(vm))
|
||||
.into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Self>, 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<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(zelf.inner.iter().into_object(vm))
|
||||
Ok(zelf.inner.iter().into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -394,7 +394,7 @@ impl Iterable for PyTuple {
|
||||
Ok(PyTupleIterator {
|
||||
internal: PyMutex::new(PositionIterInternal::new(zelf, 0)),
|
||||
}
|
||||
.into_object(vm))
|
||||
.into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PyWeak> = weak.into();
|
||||
Ok(pyref_weak.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
vm/src/convert/into_object.rs
Normal file
12
vm/src/convert/into_object.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
use crate::PyObjectRef;
|
||||
|
||||
pub trait IntoObject
|
||||
where
|
||||
Self: Into<PyObjectRef>,
|
||||
{
|
||||
fn into_object(self) -> PyObjectRef {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoObject for T where T: Into<PyObjectRef> {}
|
||||
@@ -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};
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -1,738 +0,0 @@
|
||||
mod argument;
|
||||
mod arithmetic;
|
||||
mod buffer;
|
||||
mod number;
|
||||
|
||||
use crate::{
|
||||
builtins::{PyBaseExceptionRef, PyTupleRef, PyTypeRef},
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
pyobject::PyThreadingConstraint,
|
||||
AsObject, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine,
|
||||
};
|
||||
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 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<T> IntoFuncArgs for T
|
||||
where
|
||||
T: Into<FuncArgs>,
|
||||
{
|
||||
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<PyObjectRef>,
|
||||
// sorted map, according to https://www.python.org/dev/peps/pep-0468/
|
||||
pub kwargs: IndexMap<String, PyObjectRef>,
|
||||
}
|
||||
|
||||
/// Conversion from vector of python objects to function arguments.
|
||||
impl<A> From<A> for FuncArgs
|
||||
where
|
||||
A: Into<PosArgs>,
|
||||
{
|
||||
fn from(args: A) -> Self {
|
||||
FuncArgs {
|
||||
args: args.into().into_vec(),
|
||||
kwargs: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KwArgs> 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<Self, ArgumentError> {
|
||||
Ok(std::mem::take(args))
|
||||
}
|
||||
}
|
||||
|
||||
impl FuncArgs {
|
||||
pub fn new<A, K>(args: A, kwargs: K) -> Self
|
||||
where
|
||||
A: Into<PosArgs>,
|
||||
K: Into<KwArgs>,
|
||||
{
|
||||
let PosArgs(args) = args.into();
|
||||
let KwArgs(kwargs) = kwargs.into();
|
||||
Self { args, kwargs }
|
||||
}
|
||||
|
||||
pub fn with_kwargs_names<A, KW>(mut args: A, kwarg_names: KW) -> Self
|
||||
where
|
||||
A: ExactSizeIterator<Item = PyObjectRef>,
|
||||
KW: ExactSizeIterator<Item = String>,
|
||||
{
|
||||
// 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::<IndexMap<_, _>>();
|
||||
|
||||
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<PyObjectRef> {
|
||||
self.kwargs.get(key).cloned()
|
||||
}
|
||||
|
||||
pub fn get_optional_kwarg_with_type(
|
||||
&self,
|
||||
key: &str,
|
||||
ty: PyTypeRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
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<PyObjectRef> {
|
||||
if self.args.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.args.remove(0))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_positional_keyword(&mut self, name: &str) -> Option<PyObjectRef> {
|
||||
self.take_positional().or_else(|| self.take_keyword(name))
|
||||
}
|
||||
|
||||
pub fn take_keyword(&mut self, name: &str) -> Option<PyObjectRef> {
|
||||
self.kwargs.swap_remove(name)
|
||||
}
|
||||
|
||||
pub fn remaining_keywords(&mut self) -> impl Iterator<Item = (String, PyObjectRef)> + '_ {
|
||||
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<T: FromArgs>(mut self, vm: &VirtualMachine) -> PyResult<T> {
|
||||
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<PyBaseExceptionRef> {
|
||||
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<PyBaseExceptionRef> for ArgumentError {
|
||||
fn from(ex: PyBaseExceptionRef) -> Self {
|
||||
ArgumentError::Exception(ex)
|
||||
}
|
||||
}
|
||||
|
||||
impl ArgumentError {
|
||||
fn into_exception(
|
||||
self,
|
||||
arity: RangeInclusive<usize>,
|
||||
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<usize> {
|
||||
0..=0
|
||||
}
|
||||
|
||||
/// Extracts this item from the next argument(s).
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError>;
|
||||
}
|
||||
|
||||
pub trait FromArgOptional {
|
||||
type Inner: TryFromObject;
|
||||
fn from_inner(x: Self::Inner) -> Self;
|
||||
}
|
||||
impl<T: TryFromObject> FromArgOptional for OptionalArg<T> {
|
||||
type Inner = T;
|
||||
fn from_inner(x: T) -> Self {
|
||||
Self::Present(x)
|
||||
}
|
||||
}
|
||||
impl<T: TryFromObject> 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<T = PyObjectRef>(IndexMap<String, T>);
|
||||
|
||||
impl<T> KwArgs<T> {
|
||||
pub fn new(map: IndexMap<String, T>) -> Self {
|
||||
KwArgs(map)
|
||||
}
|
||||
|
||||
pub fn pop_kwarg(&mut self, name: &str) -> Option<T> {
|
||||
self.0.remove(name)
|
||||
}
|
||||
}
|
||||
impl<T> FromIterator<(String, T)> for KwArgs<T> {
|
||||
fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Self {
|
||||
KwArgs(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
impl<T> Default for KwArgs<T> {
|
||||
fn default() -> Self {
|
||||
KwArgs(IndexMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for KwArgs<T>
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
let mut kwargs = IndexMap::new();
|
||||
for (name, value) in args.remaining_keywords() {
|
||||
kwargs.insert(name, value.try_into_value(vm)?);
|
||||
}
|
||||
Ok(KwArgs(kwargs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for KwArgs<T> {
|
||||
type Item = (String, T);
|
||||
type IntoIter = indexmap::map::IntoIter<String, T>;
|
||||
|
||||
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<T = PyObjectRef>(Vec<T>);
|
||||
|
||||
impl<T> PosArgs<T> {
|
||||
pub fn new(args: Vec<T>) -> Self {
|
||||
Self(args)
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<T> {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<T>> for PosArgs<T> {
|
||||
fn from(v: Vec<T>) -> Self {
|
||||
Self(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for PosArgs<PyObjectRef> {
|
||||
fn from(_args: ()) -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<[T]> for PosArgs<T> {
|
||||
fn as_ref(&self) -> &[T] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyValue> PosArgs<PyRef<T>> {
|
||||
pub fn into_tuple(self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
vm.ctx
|
||||
.new_tuple(self.0.into_iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for PosArgs<T>
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
let mut varargs = Vec::new();
|
||||
while let Some(value) = args.take_positional() {
|
||||
varargs.push(value.try_into_value(vm)?);
|
||||
}
|
||||
Ok(PosArgs(varargs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for PosArgs<T> {
|
||||
type Item = T;
|
||||
type IntoIter = std::vec::IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for T
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn arity() -> RangeInclusive<usize> {
|
||||
1..=1
|
||||
}
|
||||
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
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<T = PyObjectRef> {
|
||||
Present(T),
|
||||
Missing,
|
||||
}
|
||||
|
||||
impl OptionalArg<PyObjectRef> {
|
||||
pub fn unwrap_or_none(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.unwrap_or_else(|| vm.ctx.none())
|
||||
}
|
||||
}
|
||||
|
||||
pub type OptionalOption<T = PyObjectRef> = OptionalArg<Option<T>>;
|
||||
|
||||
impl<T> OptionalOption<T> {
|
||||
#[inline]
|
||||
pub fn flatten(self) -> Option<T> {
|
||||
match self {
|
||||
OptionalArg::Present(Some(value)) => Some(value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for OptionalArg<T>
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn arity() -> RangeInclusive<usize> {
|
||||
0..=1
|
||||
}
|
||||
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
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<Self, ArgumentError> {
|
||||
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<usize> {
|
||||
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<Self, ArgumentError> {
|
||||
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<py_dyn_fn!(dyn Fn(&VirtualMachine, FuncArgs) -> PyResult)>;
|
||||
|
||||
/// Implemented by types that are or can generate built-in functions.
|
||||
///
|
||||
/// This trait is implemented by any function that matches the pattern:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// Fn([&self,] [T where T: FromArgs, ...] [, vm: &VirtualMachine])
|
||||
/// ```
|
||||
///
|
||||
/// For example, anything from `Fn()` to `Fn(vm: &VirtualMachine) -> u32` to
|
||||
/// `Fn(PyIntRef, PyIntRef) -> String` to
|
||||
/// `Fn(&self, PyStrRef, FooOptions, vm: &VirtualMachine) -> PyResult<PyInt>`
|
||||
/// is `IntoPyNativeFunc`. If you do want a really general function signature, e.g.
|
||||
/// to forward the args to another function, you can define a function like
|
||||
/// `Fn(FuncArgs [, &VirtualMachine]) -> ...`
|
||||
///
|
||||
/// Note that the `Kind` type parameter is meaningless and should be considered
|
||||
/// an implementation detail; if you need to use `IntoPyNativeFunc` as a trait bound
|
||||
/// just pass an unconstrained generic type, e.g.
|
||||
/// `fn foo<F, FKind>(f: F) where F: IntoPyNativeFunc<FKind>`
|
||||
pub trait IntoPyNativeFunc<Kind>: Sized + PyThreadingConstraint + 'static {
|
||||
fn call(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult;
|
||||
/// `IntoPyNativeFunc::into_func()` generates a PyNativeFunc that performs the
|
||||
/// appropriate type and arity checking, any requested conversions, and then if
|
||||
/// successful calls the function with the extracted parameters.
|
||||
fn into_func(self) -> PyNativeFunc {
|
||||
Box::new(move |vm: &VirtualMachine, args| self.call(vm, args))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: once higher-rank trait bounds are stabilized, remove the `Kind` type
|
||||
// parameter and impl for F where F: for<T, R, VM> PyNativeFuncInternal<T, R, VM>
|
||||
impl<F, T, R, VM> IntoPyNativeFunc<(T, R, VM)> for F
|
||||
where
|
||||
F: PyNativeFuncInternal<T, R, VM>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn call(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
self.call_(vm, args)
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
use super::*;
|
||||
pub trait PyNativeFuncInternal<T, R, VM>: Sized + PyThreadingConstraint + 'static {
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult;
|
||||
}
|
||||
}
|
||||
use sealed::PyNativeFuncInternal;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct OwnedParam<T>(PhantomData<T>);
|
||||
#[doc(hidden)]
|
||||
pub struct RefParam<T>(PhantomData<T>);
|
||||
|
||||
// This is the "magic" that allows rust functions of varying signatures to
|
||||
// generate native python functions.
|
||||
//
|
||||
// Note that this could be done without a macro - it is simply to avoid repetition.
|
||||
macro_rules! into_py_native_func_tuple {
|
||||
($(($n:tt, $T:ident)),*) => {
|
||||
impl<F, $($T,)* R> PyNativeFuncInternal<($(OwnedParam<$T>,)*), R, VirtualMachine> for F
|
||||
where
|
||||
F: Fn($($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let ($($n,)*) = args.bind::<($($T,)*)>(vm)?;
|
||||
|
||||
(self)($($n,)* vm).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S, $($T,)* R> PyNativeFuncInternal<(RefParam<S>, $(OwnedParam<$T>,)*), R, VirtualMachine> for F
|
||||
where
|
||||
F: Fn(&S, $($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
|
||||
S: PyValue,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let (zelf, $($n,)*) = args.bind::<(PyRef<S>, $($T,)*)>(vm)?;
|
||||
|
||||
(self)(&zelf, $($n,)* vm).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, $($T,)* R> PyNativeFuncInternal<($(OwnedParam<$T>,)*), R, ()> for F
|
||||
where
|
||||
F: Fn($($T,)*) -> R + PyThreadingConstraint + 'static,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let ($($n,)*) = args.bind::<($($T,)*)>(vm)?;
|
||||
|
||||
(self)($($n,)*).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S, $($T,)* R> PyNativeFuncInternal<(RefParam<S>, $(OwnedParam<$T>,)*), R, ()> for F
|
||||
where
|
||||
F: Fn(&S, $($T,)*) -> R + PyThreadingConstraint + 'static,
|
||||
S: PyValue,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let (zelf, $($n,)*) = args.bind::<(PyRef<S>, $($T,)*)>(vm)?;
|
||||
|
||||
(self)(&zelf, $($n,)*).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
into_py_native_func_tuple!();
|
||||
into_py_native_func_tuple!((v1, T1));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4), (v5, T5));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4), (v5, T5), (v6, T6));
|
||||
into_py_native_func_tuple!(
|
||||
(v1, T1),
|
||||
(v2, T2),
|
||||
(v3, T3),
|
||||
(v4, T4),
|
||||
(v5, T5),
|
||||
(v6, T6),
|
||||
(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<T, F, M>(
|
||||
obj: PyObjectRef,
|
||||
predicate: &F,
|
||||
message: &M,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<bool>
|
||||
where
|
||||
T: TryFromObject,
|
||||
F: Fn(&T) -> PyResult<bool>,
|
||||
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::*;
|
||||
|
||||
#[test]
|
||||
fn test_intonativefunc_noalloc() {
|
||||
let check_zst = |f: PyNativeFunc| assert_eq!(std::mem::size_of_val(f.as_ref()), 0);
|
||||
fn py_func(_b: bool, _vm: &crate::VirtualMachine) -> i32 {
|
||||
1
|
||||
}
|
||||
check_zst(py_func.into_func());
|
||||
let empty_closure = || "foo".to_owned();
|
||||
check_zst(empty_closure.into_func());
|
||||
}
|
||||
}
|
||||
@@ -1,175 +1,545 @@
|
||||
use super::IntoFuncArgs;
|
||||
use crate::{
|
||||
builtins::{iter::PySequenceIterator, PyDict, PyDictRef},
|
||||
builtins::{PyBaseExceptionRef, PyTupleRef, PyTypeRef},
|
||||
convert::ToPyObject,
|
||||
protocol::{PyIter, PyIterIter, PyMapping, PyMappingMethods},
|
||||
AsObject, PyObject, PyObjectRef, PyObjectWrap, PyResult, PyValue, TryFromObject,
|
||||
VirtualMachine,
|
||||
AsObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine,
|
||||
};
|
||||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArgCallable {
|
||||
obj: PyObjectRef,
|
||||
}
|
||||
|
||||
impl ArgCallable {
|
||||
pub fn invoke(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
vm.invoke(&self.obj, args)
|
||||
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 Borrow<PyObject> for ArgCallable {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &PyObject {
|
||||
&self.obj
|
||||
impl<T> IntoFuncArgs for T
|
||||
where
|
||||
T: Into<FuncArgs>,
|
||||
{
|
||||
fn into_args(self, _vm: &VirtualMachine) -> FuncArgs {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<PyObject> for ArgCallable {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl PyObjectWrap for ArgCallable {
|
||||
fn into_object(self) -> PyObjectRef {
|
||||
self.obj
|
||||
}
|
||||
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<PyObjectRef>,
|
||||
// sorted map, according to https://www.python.org/dev/peps/pep-0468/
|
||||
pub kwargs: IndexMap<String, PyObjectRef>,
|
||||
}
|
||||
|
||||
impl TryFromObject for ArgCallable {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
if vm.is_callable(&obj) {
|
||||
Ok(ArgCallable { obj })
|
||||
} else {
|
||||
Err(vm.new_type_error(format!("'{}' object is not callable", obj.class().name())))
|
||||
/// Conversion from vector of python objects to function arguments.
|
||||
impl<A> From<A> for FuncArgs
|
||||
where
|
||||
A: Into<PosArgs>,
|
||||
{
|
||||
fn from(args: A) -> Self {
|
||||
FuncArgs {
|
||||
args: args.into().into_vec(),
|
||||
kwargs: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterable Python object.
|
||||
///
|
||||
/// `ArgIterable` implements `FromArgs` so that a built-in function can accept
|
||||
/// an object that is required to conform to the Python iterator protocol.
|
||||
///
|
||||
/// ArgIterable can optionally perform type checking and conversions on iterated
|
||||
/// objects using a generic type parameter that implements `TryFromObject`.
|
||||
pub struct ArgIterable<T = PyObjectRef> {
|
||||
iterable: PyObjectRef,
|
||||
iterfn: Option<crate::types::IterFunc>,
|
||||
_item: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> ArgIterable<T> {
|
||||
/// Returns an iterator over this sequence of objects.
|
||||
///
|
||||
/// This operation may fail if an exception is raised while invoking the
|
||||
/// `__iter__` method of the iterable object.
|
||||
pub fn iter<'a>(&self, vm: &'a VirtualMachine) -> PyResult<PyIterIter<'a, T>> {
|
||||
let iter = PyIter::new(match self.iterfn {
|
||||
Some(f) => f(self.iterable.clone(), vm)?,
|
||||
None => PySequenceIterator::new(self.iterable.clone(), vm)?.into_object(vm),
|
||||
});
|
||||
iter.into_iter(vm)
|
||||
impl From<KwArgs> for FuncArgs {
|
||||
fn from(kwargs: KwArgs) -> Self {
|
||||
FuncArgs {
|
||||
args: Vec::new(),
|
||||
kwargs: kwargs.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryFromObject for ArgIterable<T>
|
||||
impl FromArgs for FuncArgs {
|
||||
fn from_args(_vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
Ok(std::mem::take(args))
|
||||
}
|
||||
}
|
||||
|
||||
impl FuncArgs {
|
||||
pub fn new<A, K>(args: A, kwargs: K) -> Self
|
||||
where
|
||||
A: Into<PosArgs>,
|
||||
K: Into<KwArgs>,
|
||||
{
|
||||
let PosArgs(args) = args.into();
|
||||
let KwArgs(kwargs) = kwargs.into();
|
||||
Self { args, kwargs }
|
||||
}
|
||||
|
||||
pub fn with_kwargs_names<A, KW>(mut args: A, kwarg_names: KW) -> Self
|
||||
where
|
||||
A: ExactSizeIterator<Item = PyObjectRef>,
|
||||
KW: ExactSizeIterator<Item = String>,
|
||||
{
|
||||
// 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::<IndexMap<_, _>>();
|
||||
|
||||
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<PyObjectRef> {
|
||||
self.kwargs.get(key).cloned()
|
||||
}
|
||||
|
||||
pub fn get_optional_kwarg_with_type(
|
||||
&self,
|
||||
key: &str,
|
||||
ty: PyTypeRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
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<PyObjectRef> {
|
||||
if self.args.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.args.remove(0))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_positional_keyword(&mut self, name: &str) -> Option<PyObjectRef> {
|
||||
self.take_positional().or_else(|| self.take_keyword(name))
|
||||
}
|
||||
|
||||
pub fn take_keyword(&mut self, name: &str) -> Option<PyObjectRef> {
|
||||
self.kwargs.swap_remove(name)
|
||||
}
|
||||
|
||||
pub fn remaining_keywords(&mut self) -> impl Iterator<Item = (String, PyObjectRef)> + '_ {
|
||||
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<T: FromArgs>(mut self, vm: &VirtualMachine) -> PyResult<T> {
|
||||
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<PyBaseExceptionRef> {
|
||||
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<PyBaseExceptionRef> for ArgumentError {
|
||||
fn from(ex: PyBaseExceptionRef) -> Self {
|
||||
ArgumentError::Exception(ex)
|
||||
}
|
||||
}
|
||||
|
||||
impl ArgumentError {
|
||||
fn into_exception(
|
||||
self,
|
||||
arity: RangeInclusive<usize>,
|
||||
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<usize> {
|
||||
0..=0
|
||||
}
|
||||
|
||||
/// Extracts this item from the next argument(s).
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError>;
|
||||
}
|
||||
|
||||
pub trait FromArgOptional {
|
||||
type Inner: TryFromObject;
|
||||
fn from_inner(x: Self::Inner) -> Self;
|
||||
}
|
||||
impl<T: TryFromObject> FromArgOptional for OptionalArg<T> {
|
||||
type Inner = T;
|
||||
fn from_inner(x: T) -> Self {
|
||||
Self::Present(x)
|
||||
}
|
||||
}
|
||||
impl<T: TryFromObject> 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<T = PyObjectRef>(IndexMap<String, T>);
|
||||
|
||||
impl<T> KwArgs<T> {
|
||||
pub fn new(map: IndexMap<String, T>) -> Self {
|
||||
KwArgs(map)
|
||||
}
|
||||
|
||||
pub fn pop_kwarg(&mut self, name: &str) -> Option<T> {
|
||||
self.0.remove(name)
|
||||
}
|
||||
}
|
||||
impl<T> FromIterator<(String, T)> for KwArgs<T> {
|
||||
fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Self {
|
||||
KwArgs(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
impl<T> Default for KwArgs<T> {
|
||||
fn default() -> Self {
|
||||
KwArgs(IndexMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for KwArgs<T>
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let iterfn;
|
||||
{
|
||||
let cls = obj.class();
|
||||
iterfn = cls.mro_find_map(|x| x.slots.iter.load());
|
||||
if iterfn.is_none() && !cls.has_attr("__getitem__") {
|
||||
return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name())));
|
||||
}
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
let mut kwargs = IndexMap::new();
|
||||
for (name, value) in args.remaining_keywords() {
|
||||
kwargs.insert(name, value.try_into_value(vm)?);
|
||||
}
|
||||
Ok(Self {
|
||||
iterable: obj,
|
||||
iterfn,
|
||||
_item: PhantomData,
|
||||
})
|
||||
Ok(KwArgs(kwargs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for KwArgs<T> {
|
||||
type Item = (String, T);
|
||||
type IntoIter = indexmap::map::IntoIter<String, T>;
|
||||
|
||||
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 ArgMapping {
|
||||
obj: PyObjectRef,
|
||||
mapping_methods: PyMappingMethods,
|
||||
}
|
||||
pub struct PosArgs<T = PyObjectRef>(Vec<T>);
|
||||
|
||||
impl ArgMapping {
|
||||
pub fn from_dict_exact(dict: PyDictRef) -> Self {
|
||||
Self {
|
||||
obj: dict.into(),
|
||||
mapping_methods: PyDict::MAPPING_METHODS,
|
||||
}
|
||||
impl<T> PosArgs<T> {
|
||||
pub fn new(args: Vec<T>) -> Self {
|
||||
Self(args)
|
||||
}
|
||||
|
||||
pub fn mapping(&self) -> PyMapping {
|
||||
PyMapping::with_methods(&self.obj, self.mapping_methods)
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<PyObject> for ArgMapping {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<PyObject> for ArgMapping {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl PyObjectWrap for ArgMapping {
|
||||
#[inline(always)]
|
||||
fn into_object(self) -> PyObjectRef {
|
||||
self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPyObject for ArgMapping {
|
||||
#[inline(always)]
|
||||
fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for ArgMapping {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let mapping = PyMapping::try_protocol(&obj, vm)?;
|
||||
let mapping_methods = *mapping.methods(vm);
|
||||
Ok(Self {
|
||||
obj,
|
||||
mapping_methods,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// this is not strictly related to PySequence protocol.
|
||||
#[derive(Clone)]
|
||||
pub struct ArgSequence<T = PyObjectRef>(Vec<T>);
|
||||
|
||||
impl<T> ArgSequence<T> {
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
self.0
|
||||
}
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<T> {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<T>> for PosArgs<T> {
|
||||
fn from(v: Vec<T>) -> Self {
|
||||
Self(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for PosArgs<PyObjectRef> {
|
||||
fn from(_args: ()) -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<[T]> for PosArgs<T> {
|
||||
fn as_ref(&self) -> &[T] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryFromObject> TryFromObject for ArgSequence<T> {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
obj.try_to_value(vm).map(Self)
|
||||
impl<T: PyValue> PosArgs<PyRef<T>> {
|
||||
pub fn into_tuple(self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
vm.ctx
|
||||
.new_tuple(self.0.into_iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for PosArgs<T>
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
let mut varargs = Vec::new();
|
||||
while let Some(value) = args.take_positional() {
|
||||
varargs.push(value.try_into_value(vm)?);
|
||||
}
|
||||
Ok(PosArgs(varargs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for PosArgs<T> {
|
||||
type Item = T;
|
||||
type IntoIter = std::vec::IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for T
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn arity() -> RangeInclusive<usize> {
|
||||
1..=1
|
||||
}
|
||||
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
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<T = PyObjectRef> {
|
||||
Present(T),
|
||||
Missing,
|
||||
}
|
||||
|
||||
impl OptionalArg<PyObjectRef> {
|
||||
pub fn unwrap_or_none(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.unwrap_or_else(|| vm.ctx.none())
|
||||
}
|
||||
}
|
||||
|
||||
pub type OptionalOption<T = PyObjectRef> = OptionalArg<Option<T>>;
|
||||
|
||||
impl<T> OptionalOption<T> {
|
||||
#[inline]
|
||||
pub fn flatten(self) -> Option<T> {
|
||||
match self {
|
||||
OptionalArg::Present(Some(value)) => Some(value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for OptionalArg<T>
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn arity() -> RangeInclusive<usize> {
|
||||
0..=1
|
||||
}
|
||||
|
||||
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
|
||||
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<Self, ArgumentError> {
|
||||
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<usize> {
|
||||
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<Self, ArgumentError> {
|
||||
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);
|
||||
|
||||
157
vm/src/function/builtin.rs
Normal file
157
vm/src/function/builtin.rs
Normal file
@@ -0,0 +1,157 @@
|
||||
use super::{FromArgs, FuncArgs};
|
||||
use crate::{
|
||||
convert::ToPyResult, pyobject::PyThreadingConstraint, PyRef, PyResult, PyValue, VirtualMachine,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A built-in Python function.
|
||||
pub type PyNativeFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine, FuncArgs) -> PyResult)>;
|
||||
|
||||
/// Implemented by types that are or can generate built-in functions.
|
||||
///
|
||||
/// This trait is implemented by any function that matches the pattern:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// Fn([&self,] [T where T: FromArgs, ...] [, vm: &VirtualMachine])
|
||||
/// ```
|
||||
///
|
||||
/// For example, anything from `Fn()` to `Fn(vm: &VirtualMachine) -> u32` to
|
||||
/// `Fn(PyIntRef, PyIntRef) -> String` to
|
||||
/// `Fn(&self, PyStrRef, FooOptions, vm: &VirtualMachine) -> PyResult<PyInt>`
|
||||
/// is `IntoPyNativeFunc`. If you do want a really general function signature, e.g.
|
||||
/// to forward the args to another function, you can define a function like
|
||||
/// `Fn(FuncArgs [, &VirtualMachine]) -> ...`
|
||||
///
|
||||
/// Note that the `Kind` type parameter is meaningless and should be considered
|
||||
/// an implementation detail; if you need to use `IntoPyNativeFunc` as a trait bound
|
||||
/// just pass an unconstrained generic type, e.g.
|
||||
/// `fn foo<F, FKind>(f: F) where F: IntoPyNativeFunc<FKind>`
|
||||
pub trait IntoPyNativeFunc<Kind>: Sized + PyThreadingConstraint + 'static {
|
||||
fn call(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult;
|
||||
/// `IntoPyNativeFunc::into_func()` generates a PyNativeFunc that performs the
|
||||
/// appropriate type and arity checking, any requested conversions, and then if
|
||||
/// successful calls the function with the extracted parameters.
|
||||
fn into_func(self) -> PyNativeFunc {
|
||||
Box::new(move |vm: &VirtualMachine, args| self.call(vm, args))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: once higher-rank trait bounds are stabilized, remove the `Kind` type
|
||||
// parameter and impl for F where F: for<T, R, VM> PyNativeFuncInternal<T, R, VM>
|
||||
impl<F, T, R, VM> IntoPyNativeFunc<(T, R, VM)> for F
|
||||
where
|
||||
F: PyNativeFuncInternal<T, R, VM>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn call(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
self.call_(vm, args)
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
use super::*;
|
||||
pub trait PyNativeFuncInternal<T, R, VM>: Sized + PyThreadingConstraint + 'static {
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult;
|
||||
}
|
||||
}
|
||||
use sealed::PyNativeFuncInternal;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct OwnedParam<T>(PhantomData<T>);
|
||||
#[doc(hidden)]
|
||||
pub struct RefParam<T>(PhantomData<T>);
|
||||
|
||||
// This is the "magic" that allows rust functions of varying signatures to
|
||||
// generate native python functions.
|
||||
//
|
||||
// Note that this could be done without a macro - it is simply to avoid repetition.
|
||||
macro_rules! into_py_native_func_tuple {
|
||||
($(($n:tt, $T:ident)),*) => {
|
||||
impl<F, $($T,)* R> PyNativeFuncInternal<($(OwnedParam<$T>,)*), R, VirtualMachine> for F
|
||||
where
|
||||
F: Fn($($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let ($($n,)*) = args.bind::<($($T,)*)>(vm)?;
|
||||
|
||||
(self)($($n,)* vm).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S, $($T,)* R> PyNativeFuncInternal<(RefParam<S>, $(OwnedParam<$T>,)*), R, VirtualMachine> for F
|
||||
where
|
||||
F: Fn(&S, $($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
|
||||
S: PyValue,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let (zelf, $($n,)*) = args.bind::<(PyRef<S>, $($T,)*)>(vm)?;
|
||||
|
||||
(self)(&zelf, $($n,)* vm).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, $($T,)* R> PyNativeFuncInternal<($(OwnedParam<$T>,)*), R, ()> for F
|
||||
where
|
||||
F: Fn($($T,)*) -> R + PyThreadingConstraint + 'static,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let ($($n,)*) = args.bind::<($($T,)*)>(vm)?;
|
||||
|
||||
(self)($($n,)*).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S, $($T,)* R> PyNativeFuncInternal<(RefParam<S>, $(OwnedParam<$T>,)*), R, ()> for F
|
||||
where
|
||||
F: Fn(&S, $($T,)*) -> R + PyThreadingConstraint + 'static,
|
||||
S: PyValue,
|
||||
$($T: FromArgs,)*
|
||||
R: ToPyResult,
|
||||
{
|
||||
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
let (zelf, $($n,)*) = args.bind::<(PyRef<S>, $($T,)*)>(vm)?;
|
||||
|
||||
(self)(&zelf, $($n,)*).to_pyresult(vm)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
into_py_native_func_tuple!();
|
||||
into_py_native_func_tuple!((v1, T1));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4), (v5, T5));
|
||||
into_py_native_func_tuple!((v1, T1), (v2, T2), (v3, T3), (v4, T4), (v5, T5), (v6, T6));
|
||||
into_py_native_func_tuple!(
|
||||
(v1, T1),
|
||||
(v2, T2),
|
||||
(v3, T3),
|
||||
(v4, T4),
|
||||
(v5, T5),
|
||||
(v6, T6),
|
||||
(v7, T7)
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_intonativefunc_noalloc() {
|
||||
let check_zst = |f: PyNativeFunc| assert_eq!(std::mem::size_of_val(f.as_ref()), 0);
|
||||
fn py_func(_b: bool, _vm: &crate::VirtualMachine) -> i32 {
|
||||
1
|
||||
}
|
||||
check_zst(py_func.into_func());
|
||||
let empty_closure = || "foo".to_owned();
|
||||
check_zst(empty_closure.into_func());
|
||||
}
|
||||
}
|
||||
50
vm/src/function/mod.rs
Normal file
50
vm/src/function/mod.rs
Normal file
@@ -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<T, F, M>(
|
||||
obj: PyObjectRef,
|
||||
predicate: &F,
|
||||
message: &M,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<bool>
|
||||
where
|
||||
T: TryFromObject,
|
||||
F: Fn(&T) -> PyResult<bool>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
180
vm/src/function/protocol.rs
Normal file
180
vm/src/function/protocol.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
use super::IntoFuncArgs;
|
||||
use crate::{
|
||||
builtins::{iter::PySequenceIterator, PyDict, PyDictRef},
|
||||
convert::ToPyObject,
|
||||
protocol::{PyIter, PyIterIter, PyMapping, PyMappingMethods},
|
||||
AsObject, PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, VirtualMachine,
|
||||
};
|
||||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArgCallable {
|
||||
obj: PyObjectRef,
|
||||
}
|
||||
|
||||
impl ArgCallable {
|
||||
#[inline(always)]
|
||||
pub fn invoke(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
vm.invoke(&self.obj, args)
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<PyObject> for ArgCallable {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<PyObject> for ArgCallable {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ArgCallable> for PyObjectRef {
|
||||
#[inline(always)]
|
||||
fn from(value: ArgCallable) -> PyObjectRef {
|
||||
value.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for ArgCallable {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
if vm.is_callable(&obj) {
|
||||
Ok(ArgCallable { obj })
|
||||
} else {
|
||||
Err(vm.new_type_error(format!("'{}' object is not callable", obj.class().name())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterable Python object.
|
||||
///
|
||||
/// `ArgIterable` implements `FromArgs` so that a built-in function can accept
|
||||
/// an object that is required to conform to the Python iterator protocol.
|
||||
///
|
||||
/// ArgIterable can optionally perform type checking and conversions on iterated
|
||||
/// objects using a generic type parameter that implements `TryFromObject`.
|
||||
pub struct ArgIterable<T = PyObjectRef> {
|
||||
iterable: PyObjectRef,
|
||||
iterfn: Option<crate::types::IterFunc>,
|
||||
_item: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> ArgIterable<T> {
|
||||
/// Returns an iterator over this sequence of objects.
|
||||
///
|
||||
/// This operation may fail if an exception is raised while invoking the
|
||||
/// `__iter__` method of the iterable object.
|
||||
pub fn iter<'a>(&self, vm: &'a VirtualMachine) -> PyResult<PyIterIter<'a, T>> {
|
||||
let iter = PyIter::new(match self.iterfn {
|
||||
Some(f) => f(self.iterable.clone(), vm)?,
|
||||
None => PySequenceIterator::new(self.iterable.clone(), vm)?.into_pyobject(vm),
|
||||
});
|
||||
iter.into_iter(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryFromObject for ArgIterable<T>
|
||||
where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let iterfn;
|
||||
{
|
||||
let cls = obj.class();
|
||||
iterfn = cls.mro_find_map(|x| x.slots.iter.load());
|
||||
if iterfn.is_none() && !cls.has_attr("__getitem__") {
|
||||
return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name())));
|
||||
}
|
||||
}
|
||||
Ok(Self {
|
||||
iterable: obj,
|
||||
iterfn,
|
||||
_item: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ArgMapping {
|
||||
obj: PyObjectRef,
|
||||
mapping_methods: PyMappingMethods,
|
||||
}
|
||||
|
||||
impl ArgMapping {
|
||||
#[inline(always)]
|
||||
pub fn from_dict_exact(dict: PyDictRef) -> Self {
|
||||
Self {
|
||||
obj: dict.into(),
|
||||
mapping_methods: PyDict::MAPPING_METHODS,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mapping(&self) -> PyMapping {
|
||||
PyMapping::with_methods(&self.obj, self.mapping_methods)
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<PyObject> for ArgMapping {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<PyObject> for ArgMapping {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &PyObject {
|
||||
&self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ArgMapping> for PyObjectRef {
|
||||
#[inline(always)]
|
||||
fn from(value: ArgMapping) -> PyObjectRef {
|
||||
value.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPyObject for ArgMapping {
|
||||
#[inline(always)]
|
||||
fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for ArgMapping {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let mapping = PyMapping::try_protocol(&obj, vm)?;
|
||||
let mapping_methods = *mapping.methods(vm);
|
||||
Ok(Self {
|
||||
obj,
|
||||
mapping_methods,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// this is not strictly related to PySequence protocol.
|
||||
#[derive(Clone)]
|
||||
pub struct ArgSequence<T = PyObjectRef>(Vec<T>);
|
||||
|
||||
impl<T> ArgSequence<T> {
|
||||
#[inline(always)]
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
self.0
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryFromObject> TryFromObject for ArgSequence<T> {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
obj.try_to_value(vm).map(Self)
|
||||
}
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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<u8>, 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<VecBuffer> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PyObjectRef> {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyObjectWrap for PyIter<PyObjectRef> {
|
||||
fn into_object(self) -> PyObjectRef {
|
||||
self.0
|
||||
impl From<PyIter<PyObjectRef>> for PyObjectRef {
|
||||
fn from(value: PyIter<PyObjectRef>) -> PyObjectRef {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +133,7 @@ impl TryFromObject for PyIter<PyObjectRef> {
|
||||
)))
|
||||
}
|
||||
} 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",
|
||||
|
||||
@@ -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<PyObject> 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()
|
||||
}
|
||||
|
||||
@@ -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 {}",
|
||||
|
||||
@@ -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<T> From<T> for PyObjectRef
|
||||
where
|
||||
T: PyObjectWrap,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn from(py_ref: T) -> Self {
|
||||
py_ref.into_object()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PyMethod {
|
||||
Function {
|
||||
|
||||
@@ -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<PyObject> for PyObjectWeak {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyObjectWrap for PyObjectWeak {
|
||||
impl From<PyObjectWeak> for PyRef<PyWeak> {
|
||||
#[inline(always)]
|
||||
fn into_object(self) -> PyObjectRef {
|
||||
self.weak.into_object()
|
||||
fn from(value: PyObjectWeak) -> Self {
|
||||
value.weak
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,13 +999,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyObjectWrap for PyRef<T>
|
||||
impl<T> From<PyRef<T>> for PyObjectRef
|
||||
where
|
||||
T: PyObjectPayload,
|
||||
{
|
||||
#[inline]
|
||||
fn into_object(self) -> PyObjectRef {
|
||||
let me = ManuallyDrop::new(self);
|
||||
fn from(value: PyRef<T>) -> Self {
|
||||
let me = ManuallyDrop::new(value);
|
||||
PyObjectRef { ptr: me.ptr.cast() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ArgMapping> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -571,7 +571,7 @@ mod _collections {
|
||||
|
||||
impl Iterable for PyDeque {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyDequeIterator::new(zelf).into_object(vm))
|
||||
Ok(PyDequeIterator::new(zelf).into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PyMemoryView> {
|
||||
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,
|
||||
);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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<PyObjectRef> {
|
||||
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![],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<A: AsRef<PyObject>, B: AsRef<PyObject>> AsRef<PyObject> for Either<A, B> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: PyObjectWrap, B: PyObjectWrap> PyObjectWrap for Either<A, B> {
|
||||
impl<A: Into<PyObjectRef>, B: Into<PyObjectRef>> From<Either<A, B>> 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<A, B>) -> Self {
|
||||
match value {
|
||||
Either::A(a) => a.into(),
|
||||
Either::B(b) => b.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user