Skip to content

Commit e0e0734

Browse files
authored
Merge pull request RustPython#617 from RustPython/joey/int-any
Convert int to Any payload
2 parents ac65215 + 488d9a5 commit e0e0734

File tree

6 files changed

+126
-94
lines changed

6 files changed

+126
-94
lines changed

vm/src/frame.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
extern crate rustpython_parser;
2-
3-
use self::rustpython_parser::ast;
41
use std::cell::RefCell;
52
use std::fmt;
63
use std::path::PathBuf;
4+
use std::rc::Rc;
5+
6+
use num_bigint::BigInt;
7+
8+
use rustpython_parser::ast;
79

810
use crate::builtins;
911
use crate::bytecode;
@@ -12,6 +14,7 @@ use crate::obj::objbool;
1214
use crate::obj::objcode;
1315
use crate::obj::objdict;
1416
use crate::obj::objdict::PyDict;
17+
use crate::obj::objint::PyInt;
1518
use crate::obj::objiter;
1619
use crate::obj::objlist;
1720
use crate::obj::objstr;
@@ -21,8 +24,6 @@ use crate::pyobject::{
2124
TypeProtocol,
2225
};
2326
use crate::vm::VirtualMachine;
24-
use num_bigint::BigInt;
25-
use std::rc::Rc;
2627

2728
/*
2829
* So a scope is a linked list of scopes.
@@ -287,12 +288,12 @@ impl Frame {
287288
let mut out: Vec<Option<BigInt>> = elements
288289
.into_iter()
289290
.map(|x| {
290-
if x.is(&vm.get_none()) {
291+
if x.is(&vm.ctx.none()) {
291292
None
292-
} else if let PyObjectPayload::Integer { ref value } = x.payload {
293-
Some(value.clone())
293+
} else if let Some(i) = x.payload::<PyInt>() {
294+
Some(i.value.clone())
294295
} else {
295-
panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x);
296+
panic!("Expect Int or None as BUILD_SLICE arguments")
296297
}
297298
})
298299
.collect();

vm/src/obj/objbool.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
use super::objdict::PyDict;
2-
use super::objfloat::PyFloat;
3-
use super::objstr::PyString;
4-
use super::objtype;
1+
use num_traits::Zero;
2+
53
use crate::pyobject::{
64
IntoPyObject, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
75
};
86
use crate::vm::VirtualMachine;
9-
use num_traits::Zero;
7+
8+
use super::objdict::PyDict;
9+
use super::objfloat::PyFloat;
10+
use super::objint::PyInt;
11+
use super::objstr::PyString;
12+
use super::objtype;
1013

1114
impl IntoPyObject for bool {
1215
fn into_pyobject(self, ctx: &PyContext) -> PyResult {
@@ -24,15 +27,17 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
2427
if let Some(dict) = obj.payload::<PyDict>() {
2528
return Ok(!dict.entries.borrow().is_empty());
2629
}
30+
if let Some(i) = obj.payload::<PyInt>() {
31+
return Ok(!i.value.is_zero());
32+
}
2733
let result = match obj.payload {
28-
PyObjectPayload::Integer { ref value } => !value.is_zero(),
2934
PyObjectPayload::Sequence { ref elements } => !elements.borrow().is_empty(),
3035
_ => {
3136
if let Ok(f) = vm.get_method(obj.clone(), "__bool__") {
3237
let bool_res = vm.invoke(f, PyFuncArgs::default())?;
33-
match bool_res.payload {
34-
PyObjectPayload::Integer { ref value } => !value.is_zero(),
35-
_ => return Err(vm.new_type_error(String::from("TypeError"))),
38+
match bool_res.payload::<PyInt>() {
39+
Some(i) => !i.value.is_zero(),
40+
None => return Err(vm.new_type_error(String::from("TypeError"))),
3641
}
3742
} else {
3843
true
@@ -66,11 +71,7 @@ pub fn not(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyResult {
6671

6772
// Retrieve inner int value:
6873
pub fn get_value(obj: &PyObjectRef) -> bool {
69-
if let PyObjectPayload::Integer { value } = &obj.payload {
70-
!value.is_zero()
71-
} else {
72-
panic!("Inner error getting inner boolean");
73-
}
74+
!obj.payload::<PyInt>().unwrap().value.is_zero()
7475
}
7576

7677
fn bool_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObjectRef> {

vm/src/obj/objint.rs

Lines changed: 72 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,85 @@
1-
use super::objfloat;
2-
use super::objstr;
3-
use super::objtype;
4-
use crate::format::FormatSpec;
5-
use crate::pyobject::{
6-
FromPyObjectRef, IntoPyObject, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef,
7-
PyResult, TryFromObject, TypeProtocol,
8-
};
9-
use crate::vm::VirtualMachine;
1+
use std::hash::{Hash, Hasher};
2+
103
use num_bigint::{BigInt, ToBigInt};
114
use num_integer::Integer;
125
use num_traits::{Pow, Signed, ToPrimitive, Zero};
13-
use std::hash::{Hash, Hasher};
146

15-
// This proxy allows for easy switching between types.
16-
type IntType = BigInt;
7+
use crate::format::FormatSpec;
8+
use crate::function::PyRef;
9+
use crate::pyobject::{
10+
FromPyObjectRef, IntoPyObject, PyContext, PyFuncArgs, PyObject, PyObjectPayload,
11+
PyObjectPayload2, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
12+
};
13+
use crate::vm::VirtualMachine;
1714

18-
pub type PyInt = BigInt;
15+
use super::objfloat;
16+
use super::objstr;
17+
use super::objtype;
1918

20-
impl IntoPyObject for PyInt {
21-
fn into_pyobject(self, ctx: &PyContext) -> PyResult {
22-
Ok(ctx.new_int(self))
23-
}
19+
#[derive(Debug)]
20+
pub struct PyInt {
21+
// TODO: shouldn't be public
22+
pub value: BigInt,
2423
}
2524

26-
// TODO: macro to impl for all primitive ints
25+
pub type PyIntRef = PyRef<PyInt>;
2726

28-
impl IntoPyObject for usize {
29-
fn into_pyobject(self, ctx: &PyContext) -> PyResult {
30-
Ok(ctx.new_int(self))
27+
impl PyInt {
28+
pub fn new<T: ToBigInt>(i: T) -> Self {
29+
PyInt {
30+
value: i.to_bigint().unwrap(),
31+
}
3132
}
3233
}
3334

34-
impl TryFromObject for usize {
35-
fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
36-
// FIXME: don't use get_value
37-
match get_value(&obj).to_usize() {
38-
Some(value) => Ok(value),
39-
None => Err(vm.new_overflow_error("Int value cannot fit into Rust usize".to_string())),
40-
}
35+
impl PyObjectPayload2 for PyInt {
36+
fn required_type(ctx: &PyContext) -> PyObjectRef {
37+
ctx.int_type()
4138
}
4239
}
4340

44-
impl TryFromObject for isize {
45-
fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
46-
// FIXME: don't use get_value
47-
match get_value(&obj).to_isize() {
48-
Some(value) => Ok(value),
49-
None => Err(vm.new_overflow_error("Int value cannot fit into Rust isize".to_string())),
41+
macro_rules! impl_into_pyobject_int {
42+
($($t:ty)*) => {$(
43+
impl IntoPyObject for $t {
44+
fn into_pyobject(self, ctx: &PyContext) -> PyResult {
45+
Ok(ctx.new_int(self))
46+
}
5047
}
51-
}
52-
}
48+
)*};
49+
}
50+
51+
impl_into_pyobject_int!(isize i8 i16 i32 i64 usize u8 u16 u32 u64) ;
52+
53+
macro_rules! impl_try_from_object_int {
54+
($(($t:ty, $to_prim:ident),)*) => {$(
55+
impl TryFromObject for $t {
56+
fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
57+
match PyRef::<PyInt>::try_from_object(vm, obj)?.value.$to_prim() {
58+
Some(value) => Ok(value),
59+
None => Err(
60+
vm.new_overflow_error(concat!(
61+
"Int value cannot fit into Rust ",
62+
stringify!($t)
63+
).to_string())
64+
),
65+
}
66+
}
67+
}
68+
)*};
69+
}
70+
71+
impl_try_from_object_int!(
72+
(isize, to_isize),
73+
(i8, to_i8),
74+
(i16, to_i16),
75+
(i32, to_i32),
76+
(i64, to_i64),
77+
(usize, to_usize),
78+
(u8, to_u8),
79+
(u16, to_u16),
80+
(u32, to_u32),
81+
(u64, to_u64),
82+
);
5383

5484
fn int_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5585
arg_check!(vm, args, required = [(int, Some(vm.ctx.int_type()))]);
@@ -77,13 +107,15 @@ fn int_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
77107
None => Zero::zero(),
78108
};
79109
Ok(PyObject::new(
80-
PyObjectPayload::Integer { value: val },
110+
PyObjectPayload::AnyRustValue {
111+
value: Box::new(PyInt::new(val)),
112+
},
81113
cls.clone(),
82114
))
83115
}
84116

85117
// Casting function:
86-
pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult<IntType> {
118+
pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult<BigInt> {
87119
let val = if objtype::isinstance(obj, &vm.ctx.int_type()) {
88120
get_value(obj)
89121
} else if objtype::isinstance(obj, &vm.ctx.float_type()) {
@@ -111,12 +143,8 @@ pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult
111143
}
112144

113145
// Retrieve inner int value:
114-
pub fn get_value(obj: &PyObjectRef) -> IntType {
115-
if let PyObjectPayload::Integer { value } = &obj.payload {
116-
value.clone()
117-
} else {
118-
panic!("Inner error getting int {:?}", obj);
119-
}
146+
pub fn get_value(obj: &PyObjectRef) -> BigInt {
147+
obj.payload::<PyInt>().unwrap().value.clone()
120148
}
121149

122150
impl FromPyObjectRef for BigInt {

vm/src/obj/objrange.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
use std::cell::Cell;
22
use std::ops::Mul;
33

4-
use super::objint;
5-
use super::objtype;
4+
use num_bigint::{BigInt, Sign};
5+
use num_integer::Integer;
6+
use num_traits::{One, Signed, ToPrimitive, Zero};
7+
68
use crate::pyobject::{
79
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
810
TypeProtocol,
911
};
1012
use crate::vm::VirtualMachine;
11-
use num_bigint::{BigInt, Sign};
12-
use num_integer::Integer;
13-
use num_traits::{One, Signed, ToPrimitive, Zero};
13+
14+
use super::objint::{self, PyInt};
15+
use super::objtype;
1416

1517
#[derive(Debug, Clone)]
1618
pub struct PyRange {
@@ -284,14 +286,15 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
284286

285287
let range = get_value(zelf);
286288

289+
if let Some(i) = subscript.payload::<PyInt>() {
290+
return if let Some(int) = range.get(i.value.clone()) {
291+
Ok(vm.ctx.new_int(int))
292+
} else {
293+
Err(vm.new_index_error("range object index out of range".to_string()))
294+
};
295+
}
296+
287297
match subscript.payload {
288-
PyObjectPayload::Integer { ref value } => {
289-
if let Some(int) = range.get(value) {
290-
Ok(vm.ctx.new_int(int))
291-
} else {
292-
Err(vm.new_index_error("range object index out of range".to_string()))
293-
}
294-
}
295298
PyObjectPayload::Slice {
296299
ref start,
297300
ref stop,

vm/src/obj/objsequence.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::marker::Sized;
33
use std::ops::{Deref, DerefMut, Range};
44

55
use super::objbool;
6-
use super::objint;
6+
use super::objint::{self, PyInt};
77
use crate::pyobject::{IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol};
88
use crate::vm::VirtualMachine;
99
use num_bigint::BigInt;
@@ -141,8 +141,8 @@ pub fn get_item(
141141
elements: &[PyObjectRef],
142142
subscript: PyObjectRef,
143143
) -> PyResult {
144-
match &subscript.payload {
145-
PyObjectPayload::Integer { value } => match value.to_i32() {
144+
if let Some(i) = subscript.payload::<PyInt>() {
145+
return match i.value.to_i32() {
146146
Some(value) => {
147147
if let Some(pos_index) = elements.to_vec().get_pos(value) {
148148
let obj = elements[pos_index].clone();
@@ -154,8 +154,9 @@ pub fn get_item(
154154
None => {
155155
Err(vm.new_index_error("cannot fit 'int' into an index-sized integer".to_string()))
156156
}
157-
},
158-
157+
};
158+
}
159+
match &subscript.payload {
159160
PyObjectPayload::Slice { .. } => Ok(PyObject::new(
160161
match &sequence.payload {
161162
PyObjectPayload::Sequence { .. } => PyObjectPayload::Sequence {

vm/src/pyobject.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::obj::objfloat::{self, PyFloat};
2626
use crate::obj::objframe;
2727
use crate::obj::objfunction;
2828
use crate::obj::objgenerator;
29-
use crate::obj::objint;
29+
use crate::obj::objint::{self, PyInt};
3030
use crate::obj::objiter;
3131
use crate::obj::objlist;
3232
use crate::obj::objmap;
@@ -247,12 +247,14 @@ impl PyContext {
247247
);
248248

249249
let true_value = PyObject::new(
250-
PyObjectPayload::Integer { value: One::one() },
250+
PyObjectPayload::AnyRustValue {
251+
value: Box::new(PyInt::new(BigInt::one())),
252+
},
251253
bool_type.clone(),
252254
);
253255
let false_value = PyObject::new(
254-
PyObjectPayload::Integer {
255-
value: Zero::zero(),
256+
PyObjectPayload::AnyRustValue {
257+
value: Box::new(PyInt::new(BigInt::zero())),
256258
},
257259
bool_type.clone(),
258260
);
@@ -485,8 +487,8 @@ impl PyContext {
485487

486488
pub fn new_int<T: ToBigInt>(&self, i: T) -> PyObjectRef {
487489
PyObject::new(
488-
PyObjectPayload::Integer {
489-
value: i.to_bigint().unwrap(),
490+
PyObjectPayload::AnyRustValue {
491+
value: Box::new(PyInt::new(i)),
490492
},
491493
self.int_type(),
492494
)
@@ -1465,9 +1467,6 @@ into_py_native_func_tuple!((a, A), (b, B), (c, C), (d, D), (e, E));
14651467
/// of rust data for a particular python object. Determine the python type
14661468
/// by using for example the `.typ()` method on a python object.
14671469
pub enum PyObjectPayload {
1468-
Integer {
1469-
value: BigInt,
1470-
},
14711470
Sequence {
14721471
elements: RefCell<Vec<PyObjectRef>>,
14731472
},
@@ -1542,7 +1541,6 @@ pub enum PyObjectPayload {
15421541
impl fmt::Debug for PyObjectPayload {
15431542
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15441543
match self {
1545-
PyObjectPayload::Integer { ref value } => write!(f, "int {}", value),
15461544
PyObjectPayload::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj),
15471545
PyObjectPayload::Sequence { .. } => write!(f, "list or tuple"),
15481546
PyObjectPayload::WeakRef { .. } => write!(f, "weakref"),

0 commit comments

Comments
 (0)