Skip to content

Commit f357a95

Browse files
authored
Merge pull request #3107 from youknowone/try-to
try to types utility functions to PyObjectRef methods
2 parents d5272c9 + 09bc4d3 commit f357a95

20 files changed

+167
-164
lines changed

vm/src/builtins/complex.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ fn try_complex(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<(Compl
446446
if let Some(complex) = obj.payload_if_subclass::<PyComplex>(vm) {
447447
return Ok(Some((complex.value, true)));
448448
}
449-
if let Some(float) = float::try_float_opt(obj, vm)? {
449+
if let Some(float) = obj.try_to_f64(vm)? {
450450
return Ok(Some((Complex64::new(float, 0.0), false)));
451451
}
452452
Ok(None)

vm/src/builtins/filter.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use super::pybool;
21
use super::pytype::PyTypeRef;
32
use crate::iterator;
43
use crate::slots::{PyIter, SlotConstructor};
@@ -64,7 +63,7 @@ impl PyIter for PyFilter {
6463
// iteration
6564
vm.invoke(predicate, vec![next_obj.clone()])?
6665
};
67-
if pybool::boolval(vm, predicate_value)? {
66+
if predicate_value.try_to_bool(vm)? {
6867
return Ok(next_obj);
6968
}
7069
}

vm/src/builtins/float.rs

+29-27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{int, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyTypeRef};
1+
use super::{try_bigint_to_f64, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyTypeRef};
22
use crate::common::{float_ops, hash};
33
use crate::format::FormatSpec;
44
use crate::function::{OptionalArg, OptionalOption};
@@ -51,29 +51,31 @@ impl From<f64> for PyFloat {
5151
}
5252
}
5353

54-
pub fn try_float_opt(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<f64>> {
55-
if let Some(float) = obj.payload_if_exact::<PyFloat>(vm) {
56-
return Ok(Some(float.value));
57-
}
58-
if let Some(method) = vm.get_method(obj.clone(), "__float__") {
59-
let result = vm.invoke(&method?, ())?;
60-
// TODO: returning strict subclasses of float in __float__ is deprecated
61-
return match result.payload::<PyFloat>() {
62-
Some(float_obj) => Ok(Some(float_obj.value)),
63-
None => Err(vm.new_type_error(format!(
64-
"__float__ returned non-float (type '{}')",
65-
result.class().name()
66-
))),
67-
};
68-
}
69-
if let Some(r) = vm.to_index_opt(obj.clone()).transpose()? {
70-
return Ok(Some(int::to_float(r.as_bigint(), vm)?));
54+
impl PyObjectRef {
55+
pub fn try_to_f64(&self, vm: &VirtualMachine) -> PyResult<Option<f64>> {
56+
if let Some(float) = self.payload_if_exact::<PyFloat>(vm) {
57+
return Ok(Some(float.value));
58+
}
59+
if let Some(method) = vm.get_method(self.clone(), "__float__") {
60+
let result = vm.invoke(&method?, ())?;
61+
// TODO: returning strict subclasses of float in __float__ is deprecated
62+
return match result.payload::<PyFloat>() {
63+
Some(float_obj) => Ok(Some(float_obj.value)),
64+
None => Err(vm.new_type_error(format!(
65+
"__float__ returned non-float (type '{}')",
66+
result.class().name()
67+
))),
68+
};
69+
}
70+
if let Some(r) = vm.to_index_opt(self.clone()).transpose()? {
71+
return Ok(Some(try_bigint_to_f64(r.as_bigint(), vm)?));
72+
}
73+
Ok(None)
7174
}
72-
Ok(None)
7375
}
7476

7577
pub fn try_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
76-
try_float_opt(obj, vm)?.ok_or_else(|| {
78+
obj.try_to_f64(vm)?.ok_or_else(|| {
7779
vm.new_type_error(format!("must be real number, not {}", obj.class().name()))
7880
})
7981
}
@@ -82,7 +84,7 @@ pub(crate) fn to_op_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Op
8284
let v = if let Some(float) = obj.payload_if_subclass::<PyFloat>(vm) {
8385
Some(float.value)
8486
} else if let Some(int) = obj.payload_if_subclass::<PyInt>(vm) {
85-
Some(int::to_float(int.as_bigint(), vm)?)
87+
Some(try_bigint_to_f64(int.as_bigint(), vm)?)
8688
} else {
8789
None
8890
};
@@ -111,7 +113,7 @@ fn inner_mod(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult<f64> {
111113
.ok_or_else(|| vm.new_zero_division_error("float mod by zero".to_owned()))
112114
}
113115

114-
pub fn try_bigint(value: f64, vm: &VirtualMachine) -> PyResult<BigInt> {
116+
pub fn try_to_bigint(value: f64, vm: &VirtualMachine) -> PyResult<BigInt> {
115117
match value.to_bigint() {
116118
Some(int) => Ok(int),
117119
None => {
@@ -171,7 +173,7 @@ impl SlotConstructor for PyFloat {
171173
val
172174
};
173175

174-
if let Some(f) = try_float_opt(&val, vm)? {
176+
if let Some(f) = val.try_to_f64(vm)? {
175177
f
176178
} else if let Some(s) = val.payload_if_subclass::<PyStr>(vm) {
177179
float_ops::parse_str(s.as_str().trim()).ok_or_else(|| {
@@ -379,17 +381,17 @@ impl PyFloat {
379381

380382
#[pymethod(magic)]
381383
fn trunc(&self, vm: &VirtualMachine) -> PyResult<BigInt> {
382-
try_bigint(self.value, vm)
384+
try_to_bigint(self.value, vm)
383385
}
384386

385387
#[pymethod(magic)]
386388
fn floor(&self, vm: &VirtualMachine) -> PyResult<BigInt> {
387-
try_bigint(self.value.floor(), vm)
389+
try_to_bigint(self.value.floor(), vm)
388390
}
389391

390392
#[pymethod(magic)]
391393
fn ceil(&self, vm: &VirtualMachine) -> PyResult<BigInt> {
392-
try_bigint(self.value.ceil(), vm)
394+
try_to_bigint(self.value.ceil(), vm)
393395
}
394396

395397
#[pymethod(magic)]
@@ -417,7 +419,7 @@ impl PyFloat {
417419
} else {
418420
self.value.round()
419421
};
420-
let int = try_bigint(value, vm)?;
422+
let int = try_to_bigint(value, vm)?;
421423
vm.ctx.new_int(int)
422424
};
423425
Ok(value)

vm/src/builtins/int.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use super::{float, IntoPyBool, PyByteArray, PyBytes, PyStr, PyStrRef, PyTypeRef};
2+
use crate::bytesinner::PyBytesInner;
23
use crate::common::hash;
34
use crate::format::FormatSpec;
45
use crate::function::{OptionalArg, OptionalOption};
56
use crate::slots::{Comparable, Hashable, PyComparisonOp, SlotConstructor};
67
use crate::VirtualMachine;
7-
use crate::{bytesinner::PyBytesInner, byteslike::try_bytes_like};
88
use crate::{
99
try_value_from_borrowed_object, IdProtocol, IntoPyObject, IntoPyResult, PyArithmaticValue,
1010
PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
@@ -142,8 +142,8 @@ pub fn bigint_unsigned_mask(v: &BigInt) -> u32 {
142142

143143
fn inner_pow(int1: &BigInt, int2: &BigInt, vm: &VirtualMachine) -> PyResult {
144144
if int2.is_negative() {
145-
let v1 = to_float(int1, vm)?;
146-
let v2 = to_float(int2, vm)?;
145+
let v1 = try_to_float(int1, vm)?;
146+
let v2 = try_to_float(int2, vm)?;
147147
float::float_pow(v1, v2, vm).into_pyresult(vm)
148148
} else {
149149
Ok(if let Some(v2) = int2.to_u64() {
@@ -541,7 +541,7 @@ impl PyInt {
541541

542542
#[pymethod(magic)]
543543
fn float(&self, vm: &VirtualMachine) -> PyResult<f64> {
544-
to_float(&self.value, vm)
544+
try_to_float(&self.value, vm)
545545
}
546546

547547
#[pymethod(magic)]
@@ -914,7 +914,7 @@ pub(crate) fn get_value(obj: &PyObjectRef) -> &BigInt {
914914
&obj.payload::<PyInt>().unwrap().value
915915
}
916916

917-
pub fn to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult<f64> {
917+
pub fn try_to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult<f64> {
918918
i2f(int).ok_or_else(|| vm.new_overflow_error("int too large to convert to float".to_owned()))
919919
}
920920
// num-bigint now returns Some(inf) for to_f64() in some cases, so just keep that the same for now
@@ -939,7 +939,7 @@ pub(crate) fn try_int(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<BigInt
939939
if let Some(s) = obj.downcast_ref::<PyStr>() {
940940
return try_convert(obj, s.as_str().as_bytes(), vm);
941941
}
942-
if let Ok(r) = try_bytes_like(vm, obj, |x| try_convert(obj, x, vm)) {
942+
if let Ok(r) = obj.try_bytes_like(vm, |x| try_convert(obj, x, vm)) {
943943
return r;
944944
}
945945
// strict `int` check

vm/src/builtins/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub use classmethod::PyClassMethod;
1212
pub(crate) mod code;
1313
pub use code::PyCode;
1414
pub(crate) mod complex;
15-
pub use complex::PyComplex;
15+
pub use complex::{IntoPyComplex, PyComplex};
1616
pub(crate) mod coroutine;
1717
pub use coroutine::PyCoroutine;
1818
pub mod dict;
@@ -22,7 +22,7 @@ pub use enumerate::PyEnumerate;
2222
pub(crate) mod filter;
2323
pub use filter::PyFilter;
2424
pub(crate) mod float;
25-
pub use float::{PyFloat, PyFloatRef};
25+
pub use float::{IntoPyFloat, PyFloat, PyFloatRef};
2626
pub(crate) mod frame;
2727
pub(crate) mod function;
2828
pub use function::PyFunction;
@@ -65,7 +65,7 @@ pub use set::PySet;
6565
pub(crate) mod singletons;
6666
pub use singletons::{PyNone, PyNotImplemented};
6767
pub(crate) mod slice;
68-
pub use slice::PySlice;
68+
pub use slice::{PySlice, PySliceRef};
6969
pub(crate) mod staticmethod;
7070
pub use staticmethod::PyStaticMethod;
7171
pub(crate) mod traceback;
@@ -80,5 +80,8 @@ pub(crate) mod zip;
8080
pub use zip::PyZip;
8181
pub(crate) mod genericalias;
8282

83+
pub use float::try_to_bigint as try_f64_to_bigint;
84+
pub use int::try_to_float as try_bigint_to_f64;
85+
8386
mod make_module;
8487
pub use make_module::{ascii, make_module, print};

vm/src/builtins/object.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::dict::{PyDict, PyDictRef};
22
use super::list::PyList;
3-
use super::pybool;
43
use super::pystr::{PyStr, PyStrRef};
54
use super::pytype::PyTypeRef;
65
use crate::builtins::pytype::PyType;
@@ -77,7 +76,7 @@ impl PyBaseObject {
7776
.unwrap();
7877
let value = match cmp(zelf, other, PyComparisonOp::Eq, vm)? {
7978
Either::A(obj) => PyArithmaticValue::from_object(vm, obj)
80-
.map(|obj| pybool::boolval(vm, obj))
79+
.map(|obj| obj.try_to_bool(vm))
8180
.transpose()?,
8281
Either::B(value) => value,
8382
};

vm/src/builtins/pybool.rs

+40-38
Original file line numberDiff line numberDiff line change
@@ -29,49 +29,51 @@ impl TryFromBorrowedObject for bool {
2929
}
3030
}
3131

32-
/// Convert Python bool into Rust bool.
33-
pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
34-
if obj.is(&vm.ctx.true_value) {
35-
return Ok(true);
36-
}
37-
if obj.is(&vm.ctx.false_value) {
38-
return Ok(false);
39-
}
40-
let rs_bool = match vm.get_method(obj.clone(), "__bool__") {
41-
Some(method_or_err) => {
42-
// If descriptor returns Error, propagate it further
43-
let method = method_or_err?;
44-
let bool_obj = vm.invoke(&method, ())?;
45-
if !bool_obj.isinstance(&vm.ctx.types.bool_type) {
46-
return Err(vm.new_type_error(format!(
47-
"__bool__ should return bool, returned type {}",
48-
bool_obj.class().name()
49-
)));
50-
}
51-
52-
get_value(&bool_obj)
32+
impl PyObjectRef {
33+
/// Convert Python bool into Rust bool.
34+
pub fn try_to_bool(self, vm: &VirtualMachine) -> PyResult<bool> {
35+
if self.is(&vm.ctx.true_value) {
36+
return Ok(true);
37+
}
38+
if self.is(&vm.ctx.false_value) {
39+
return Ok(false);
5340
}
54-
None => match vm.get_method(obj, "__len__") {
41+
let rs_bool = match vm.get_method(self.clone(), "__bool__") {
5542
Some(method_or_err) => {
43+
// If descriptor returns Error, propagate it further
5644
let method = method_or_err?;
5745
let bool_obj = vm.invoke(&method, ())?;
58-
let int_obj = bool_obj.payload::<PyInt>().ok_or_else(|| {
59-
vm.new_type_error(format!(
60-
"'{}' object cannot be interpreted as an integer",
46+
if !bool_obj.isinstance(&vm.ctx.types.bool_type) {
47+
return Err(vm.new_type_error(format!(
48+
"__bool__ should return bool, returned type {}",
6149
bool_obj.class().name()
62-
))
63-
})?;
64-
65-
let len_val = int_obj.as_bigint();
66-
if len_val.sign() == Sign::Minus {
67-
return Err(vm.new_value_error("__len__() should return >= 0".to_owned()));
50+
)));
6851
}
69-
!len_val.is_zero()
52+
53+
get_value(&bool_obj)
7054
}
71-
None => true,
72-
},
73-
};
74-
Ok(rs_bool)
55+
None => match vm.get_method(self, "__len__") {
56+
Some(method_or_err) => {
57+
let method = method_or_err?;
58+
let bool_obj = vm.invoke(&method, ())?;
59+
let int_obj = bool_obj.payload::<PyInt>().ok_or_else(|| {
60+
vm.new_type_error(format!(
61+
"'{}' object cannot be interpreted as an integer",
62+
bool_obj.class().name()
63+
))
64+
})?;
65+
66+
let len_val = int_obj.as_bigint();
67+
if len_val.sign() == Sign::Minus {
68+
return Err(vm.new_value_error("__len__() should return >= 0".to_owned()));
69+
}
70+
!len_val.is_zero()
71+
}
72+
None => true,
73+
},
74+
};
75+
Ok(rs_bool)
76+
}
7577
}
7678

7779
/// bool(x) -> bool
@@ -105,7 +107,7 @@ impl SlotConstructor for PyBool {
105107
actual_type
106108
)));
107109
}
108-
let val = x.map_or(Ok(false), |val| boolval(vm, val))?;
110+
let val = x.map_or(Ok(false), |val| val.try_to_bool(vm))?;
109111
Ok(vm.ctx.new_bool(val))
110112
}
111113
}
@@ -202,7 +204,7 @@ impl IntoPyBool {
202204
impl TryFromObject for IntoPyBool {
203205
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
204206
Ok(IntoPyBool {
205-
value: boolval(vm, obj)?,
207+
value: obj.try_to_bool(vm)?,
206208
})
207209
}
208210
}

vm/src/bytesinner.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::builtins::bytes::{PyBytes, PyBytesRef};
44
use crate::builtins::int::{PyInt, PyIntRef};
55
use crate::builtins::pystr::{self, PyStr, PyStrRef};
66
use crate::builtins::PyTypeRef;
7-
use crate::byteslike::try_bytes_like;
87
use crate::cformat::CFormatBytes;
98
use crate::function::{OptionalArg, OptionalOption};
109
use crate::sliceable::PySliceableSequence;
@@ -320,10 +319,9 @@ impl PyBytesInner {
320319
// TODO: bytes can compare with any object implemented buffer protocol
321320
// but not memoryview, and not equal if compare with unicode str(PyStr)
322321
PyComparisonValue::from_option(
323-
try_bytes_like(vm, other, |other| {
324-
op.eval_ord(self.elements.as_slice().cmp(other))
325-
})
326-
.ok(),
322+
other
323+
.try_bytes_like(vm, |other| op.eval_ord(self.elements.as_slice().cmp(other)))
324+
.ok(),
327325
)
328326
}
329327

@@ -1238,7 +1236,7 @@ pub const fn is_py_ascii_whitespace(b: u8) -> bool {
12381236
}
12391237

12401238
pub fn bytes_from_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Vec<u8>> {
1241-
if let Ok(elements) = try_bytes_like(vm, obj, |bytes| bytes.to_vec()) {
1239+
if let Ok(elements) = obj.try_bytes_like(vm, |bytes| bytes.to_vec()) {
12421240
return Ok(elements);
12431241
}
12441242

0 commit comments

Comments
 (0)