diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index e7b82eda1..f4f418bce 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -19,8 +19,9 @@ use crate::slots::{Comparable, Hashable, PyComparisonOp}; use crate::VirtualMachine; use crate::{bytesinner::PyBytesInner, byteslike::try_bytes_like}; use crate::{ - IdProtocol, IntoPyObject, IntoPyResult, PyArithmaticValue, PyClassImpl, PyComparisonValue, - PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, + try_value_from_borrowed_object, IdProtocol, IntoPyObject, IntoPyResult, PyArithmaticValue, + PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, + TryFromBorrowedObject, TypeProtocol, }; use rustpython_common::hash; @@ -101,10 +102,11 @@ where macro_rules! impl_try_from_object_int { ($(($t:ty, $to_prim:ident),)*) => {$( - impl TryFromObject for $t { - fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let int = PyIntRef::try_from_object(vm, obj)?; - try_to_primitive(&int.value, vm) + impl TryFromBorrowedObject for $t { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { + try_value_from_borrowed_object(vm, obj, |int: &PyInt| { + try_to_primitive(int.as_bigint(), vm) + }) } } )*}; diff --git a/vm/src/builtins/make_module.rs b/vm/src/builtins/make_module.rs index 51f80f041..0fcdfc47c 100644 --- a/vm/src/builtins/make_module.rs +++ b/vm/src/builtins/make_module.rs @@ -13,7 +13,7 @@ mod decl { use crate::builtins::code::PyCodeRef; use crate::builtins::dict::PyDictRef; use crate::builtins::function::{PyCellRef, PyFunctionRef}; - use crate::builtins::int::PyIntRef; + use crate::builtins::int::{self, PyIntRef}; use crate::builtins::iter::{PyCallableIterator, PySequenceIterator}; use crate::builtins::list::{PyList, SortOptions}; use crate::builtins::pybool::IntoPyBool; @@ -161,7 +161,7 @@ mod decl { let flags = args .flags - .map_or(Ok(0), |v| i32::try_from_object(vm, v.into_object()))?; + .map_or(Ok(0), |v| int::try_to_primitive(v.as_bigint(), vm))?; if (flags & ast::PY_COMPILE_FLAG_AST_ONLY).is_zero() { #[cfg(not(feature = "rustpython-compiler"))] diff --git a/vm/src/builtins/pybool.rs b/vm/src/builtins/pybool.rs index 81e8a01f4..6c5821c0b 100644 --- a/vm/src/builtins/pybool.rs +++ b/vm/src/builtins/pybool.rs @@ -6,8 +6,8 @@ use super::pystr::PyStrRef; use crate::function::OptionalArg; use crate::vm::VirtualMachine; use crate::{ - IdProtocol, IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyResult, TryFromObject, - TypeProtocol, + IdProtocol, IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyResult, TryFromBorrowedObject, + TryFromObject, TypeProtocol, }; impl IntoPyObject for bool { @@ -16,10 +16,10 @@ impl IntoPyObject for bool { } } -impl TryFromObject for bool { - fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { +impl TryFromBorrowedObject for bool { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { if obj.isinstance(&vm.ctx.types.int_type) { - Ok(get_value(&obj)) + Ok(get_value(obj)) } else { Err(vm.new_type_error(format!("Expected type bool, not {}", obj.class().name))) } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index dae5a3e60..9467ef572 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -408,6 +408,28 @@ impl Default for PyContext { } } +pub(crate) fn try_value_from_borrowed_object( + vm: &VirtualMachine, + obj: &PyObjectRef, + f: F, +) -> PyResult +where + T: PyValue, + F: Fn(&T) -> PyResult, +{ + let class = T::class(vm); + let special; + let py_ref = if obj.isinstance(class) { + obj.downcast_ref() + .ok_or_else(|| pyref_payload_error(vm, class, obj))? + } else { + special = T::special_retrieve(vm, obj) + .unwrap_or_else(|| Err(pyref_type_error(vm, class, obj)))?; + &special + }; + f(py_ref) +} + impl TryFromObject for PyRef where T: PyValue, @@ -435,7 +457,8 @@ fn pyref_payload_error( &*obj.borrow().class().name, )) } -fn pyref_type_error( + +pub(crate) fn pyref_type_error( vm: &VirtualMachine, class: &PyTypeRef, obj: impl std::borrow::Borrow, diff --git a/vm/src/stdlib/codecs.rs b/vm/src/stdlib/codecs.rs index 1a2b7f4e6..45f730af2 100644 --- a/vm/src/stdlib/codecs.rs +++ b/vm/src/stdlib/codecs.rs @@ -11,7 +11,7 @@ mod _codecs { use crate::exceptions::PyBaseExceptionRef; use crate::function::FuncArgs; use crate::VirtualMachine; - use crate::{IdProtocol, PyObjectRef, PyResult, TryFromObject}; + use crate::{IdProtocol, PyObjectRef, PyResult, TryFromBorrowedObject}; #[pyfunction] fn register(search_function: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { @@ -156,7 +156,7 @@ mod _codecs { .ok_or_else(tuple_err)? .clone(); let restart = - isize::try_from_object(vm, restart.clone()).map_err(|_| tuple_err())?; + isize::try_from_borrowed_object(vm, restart).map_err(|_| tuple_err())?; let restart = if restart < 0 { // will still be out of bounds if it underflows ¯\_(ツ)_/¯ data.len().wrapping_sub(restart.unsigned_abs()) diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 02a1cce2f..ce3ec191c 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -30,7 +30,7 @@ use crate::utils::Either; use crate::vm::{ReprGuard, VirtualMachine}; use crate::{ IntoPyObject, ItemProtocol, PyObjectRef, PyRef, PyResult, PyStructSequence, PyValue, - StaticType, TryFromObject, TypeProtocol, + StaticType, TryFromBorrowedObject, TryFromObject, TypeProtocol, }; #[cfg(unix)] @@ -1654,7 +1654,7 @@ mod _os { #[pyfunction] fn truncate(path: PyObjectRef, length: Offset, vm: &VirtualMachine) -> PyResult<()> { - if let Ok(fd) = i32::try_from_object(vm, path.clone()) { + if let Ok(fd) = i32::try_from_borrowed_object(vm, &path) { return ftruncate(fd, length, vm); } let path = PyPathLike::try_from_object(vm, path)?; @@ -2867,7 +2867,7 @@ mod posix { "Each file_actions element must be a non-empty tuple".to_owned(), ) })?; - let id = i32::try_from_object(vm, id.clone())?; + let id = i32::try_from_borrowed_object(vm, id)?; let id = PosixSpawnFileActionIdentifier::try_from(id).map_err(|_| { vm.new_type_error("Unknown file_actions identifier".to_owned()) })?; diff --git a/vm/src/stdlib/resource.rs b/vm/src/stdlib/resource.rs index 8a4628ccb..dffee993f 100644 --- a/vm/src/stdlib/resource.rs +++ b/vm/src/stdlib/resource.rs @@ -5,7 +5,7 @@ mod resource { use super::super::os; use crate::exceptions::IntoPyException; use crate::VirtualMachine; - use crate::{IntoPyObject, PyObjectRef, PyResult, PyStructSequence, TryFromObject}; + use crate::{IntoPyObject, PyObjectRef, PyResult, PyStructSequence, TryFromBorrowedObject}; use std::{io, mem}; cfg_if::cfg_if! { @@ -111,9 +111,9 @@ mod resource { } struct Limits(libc::rlimit); - impl TryFromObject for Limits { - fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let seq = vm.extract_elements::(&obj)?; + impl TryFromBorrowedObject for Limits { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { + let seq = vm.extract_elements::(obj)?; match *seq { [cur, max] => Ok(Self(libc::rlimit { rlim_cur: cur & RLIM_INFINITY, diff --git a/vm/src/stdlib/select.rs b/vm/src/stdlib/select.rs index b6e81710d..c77587a6a 100644 --- a/vm/src/stdlib/select.rs +++ b/vm/src/stdlib/select.rs @@ -1,5 +1,5 @@ use crate::vm::VirtualMachine; -use crate::{PyObjectRef, PyResult, TryFromObject}; +use crate::{PyObjectRef, PyResult, TryFromBorrowedObject, TryFromObject}; use std::{io, mem}; pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef { @@ -72,7 +72,7 @@ struct Selectable { impl TryFromObject for Selectable { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let fno = RawFd::try_from_object(vm, obj.clone()).or_else(|_| { + let fno = RawFd::try_from_borrowed_object(vm, &obj).or_else(|_| { let meth = vm.get_method_or_type_error(obj.clone(), "fileno", || { "select arg must be an int or object with a fileno() method".to_owned() })?; diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs index d1b8eb8c2..609baf886 100644 --- a/vm/src/stdlib/signal.rs +++ b/vm/src/stdlib/signal.rs @@ -1,6 +1,6 @@ use crate::exceptions::IntoPyException; use crate::vm::{VirtualMachine, NSIG}; -use crate::{PyObjectRef, PyResult, TryFromObject}; +use crate::{PyObjectRef, PyResult, TryFromBorrowedObject}; use std::sync::atomic::{self, AtomicBool, Ordering}; @@ -81,7 +81,7 @@ fn _signal_signal( .as_deref() .ok_or_else(|| vm.new_value_error("signal only works in main thread".to_owned()))?; - let sig_handler = match usize::try_from_object(vm, handler.clone()).ok() { + let sig_handler = match usize::try_from_borrowed_object(vm, &handler).ok() { Some(SIG_DFL) => SIG_DFL, Some(SIG_IGN) => SIG_IGN, None if vm.is_callable(&handler) => run_signal as libc::sighandler_t, diff --git a/vm/src/stdlib/socket.rs b/vm/src/stdlib/socket.rs index f35e9fc85..bdf3ad4c3 100644 --- a/vm/src/stdlib/socket.rs +++ b/vm/src/stdlib/socket.rs @@ -21,8 +21,8 @@ use crate::function::{FuncArgs, OptionalArg, OptionalOption}; use crate::utils::Either; use crate::VirtualMachine; use crate::{ - IntoPyObject, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, StaticType, TryFromObject, - TypeProtocol, + IntoPyObject, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, StaticType, + TryFromBorrowedObject, TryFromObject, TypeProtocol, }; #[cfg(unix)] @@ -970,7 +970,7 @@ impl TryFromObject for Address { impl Address { fn from_tuple(tuple: &[PyObjectRef], vm: &VirtualMachine) -> PyResult { let host = PyStrRef::try_from_object(vm, tuple[0].clone())?; - let port = i32::try_from_object(vm, tuple[1].clone())?; + let port = i32::try_from_borrowed_object(vm, &tuple[1])?; let port = port .to_u16() .ok_or_else(|| vm.new_overflow_error("port must be 0-65535.".to_owned()))?; @@ -980,12 +980,12 @@ impl Address { let addr = Address::from_tuple(tuple, vm)?; let flowinfo = tuple .get(2) - .map(|obj| u32::try_from_object(vm, obj.clone())) + .map(|obj| u32::try_from_borrowed_object(vm, obj)) .transpose()? .unwrap_or(0); let scopeid = tuple .get(3) - .map(|obj| u32::try_from_object(vm, obj.clone())) + .map(|obj| u32::try_from_borrowed_object(vm, obj)) .transpose()? .unwrap_or(0); if flowinfo > 0xfffff {