Skip to content

Commit ce46786

Browse files
committed
fix large integer handling
1 parent 3dd7950 commit ce46786

2 files changed

Lines changed: 56 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## Unreleased
22

3+
- Support `u128` / `i128` integers.
4+
- Fix overflow error attempting to depythonize `u64` values greater than `i64::MAX` to types like `serde_json::Value`
35
- `depythonize()` now take a `&Bound` and is no longer depreciate
46
- `depythonize_object()` replace the old `depythonize()` and is depreciated
57
- `depythonize_bound()` is depreciated

src/de.rs

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,38 @@ impl<'py, 'bound> Depythonizer<'py, 'bound> {
7171
fn dict_access(&self) -> Result<PyMappingAccess<'py>> {
7272
PyMappingAccess::new(self.input.downcast()?)
7373
}
74+
75+
fn deserialize_any_int<'de, V>(&self, int: &Bound<'_, PyInt>, visitor: V) -> Result<V::Value>
76+
where
77+
V: de::Visitor<'de>,
78+
{
79+
if let Ok(x) = int.extract::<u128>() {
80+
if let Ok(x) = u8::try_from(x) {
81+
visitor.visit_u8(x)
82+
} else if let Ok(x) = u16::try_from(x) {
83+
visitor.visit_u16(x)
84+
} else if let Ok(x) = u32::try_from(x) {
85+
visitor.visit_u32(x)
86+
} else if let Ok(x) = u64::try_from(x) {
87+
visitor.visit_u64(x)
88+
} else {
89+
visitor.visit_u128(x)
90+
}
91+
} else {
92+
let x: i128 = int.extract()?;
93+
if let Ok(x) = i8::try_from(x) {
94+
visitor.visit_i8(x)
95+
} else if let Ok(x) = i16::try_from(x) {
96+
visitor.visit_i16(x)
97+
} else if let Ok(x) = i32::try_from(x) {
98+
visitor.visit_i32(x)
99+
} else if let Ok(x) = i64::try_from(x) {
100+
visitor.visit_i64(x)
101+
} else {
102+
visitor.visit_i128(x)
103+
}
104+
}
105+
}
74106
}
75107

76108
macro_rules! deserialize_type {
@@ -99,8 +131,8 @@ impl<'a, 'py, 'de, 'bound> de::Deserializer<'de> for &'a mut Depythonizer<'py, '
99131
self.deserialize_unit(visitor)
100132
} else if obj.is_instance_of::<PyBool>() {
101133
self.deserialize_bool(visitor)
102-
} else if obj.is_instance_of::<PyInt>() {
103-
self.deserialize_i64(visitor)
134+
} else if let Ok(x) = obj.downcast::<PyInt>() {
135+
self.deserialize_any_int(x, visitor)
104136
} else if obj.is_instance_of::<PyList>() || obj.is_instance_of::<PyTuple>() {
105137
self.deserialize_tuple(obj.len()?, visitor)
106138
} else if obj.is_instance_of::<PyDict>() {
@@ -151,10 +183,12 @@ impl<'a, 'py, 'de, 'bound> de::Deserializer<'de> for &'a mut Depythonizer<'py, '
151183
deserialize_type!(deserialize_i16 => visit_i16);
152184
deserialize_type!(deserialize_i32 => visit_i32);
153185
deserialize_type!(deserialize_i64 => visit_i64);
186+
deserialize_type!(deserialize_i128 => visit_i128);
154187
deserialize_type!(deserialize_u8 => visit_u8);
155188
deserialize_type!(deserialize_u16 => visit_u16);
156189
deserialize_type!(deserialize_u32 => visit_u32);
157190
deserialize_type!(deserialize_u64 => visit_u64);
191+
deserialize_type!(deserialize_u128 => visit_u128);
158192
deserialize_type!(deserialize_f32 => visit_f32);
159193
deserialize_type!(deserialize_f64 => visit_f64);
160194

@@ -459,7 +493,7 @@ mod test {
459493
use super::*;
460494
use crate::error::ErrorImpl;
461495
use maplit::hashmap;
462-
use pyo3::Python;
496+
use pyo3::{IntoPy, Python};
463497
use serde_json::{json, Value as JsonValue};
464498

465499
fn test_de<T>(code: &str, expected: &T, expected_json: &JsonValue)
@@ -749,4 +783,21 @@ mod test {
749783
let code = "{'name': 'SomeFoo', 'bar': {'value': 13, 'variant': {'Tuple': [-1.5, 8]}}}";
750784
test_de(code, &expected, &expected_json);
751785
}
786+
787+
#[test]
788+
fn test_int_limits() {
789+
Python::with_gil(|py| {
790+
// serde_json::Value supports u64 and i64 as maxiumum sizes
791+
let _: serde_json::Value = depythonize(&u64::MAX.into_py(py).into_bound(py)).unwrap();
792+
let _: serde_json::Value = depythonize(&u64::MIN.into_py(py).into_bound(py)).unwrap();
793+
let _: serde_json::Value = depythonize(&i64::MAX.into_py(py).into_bound(py)).unwrap();
794+
let _: serde_json::Value = depythonize(&i64::MIN.into_py(py).into_bound(py)).unwrap();
795+
796+
let _: u128 = depythonize(&u128::MAX.into_py(py).into_bound(py)).unwrap();
797+
let _: i128 = depythonize(&u128::MIN.into_py(py).into_bound(py)).unwrap();
798+
799+
let _: i128 = depythonize(&i128::MAX.into_py(py).into_bound(py)).unwrap();
800+
let _: i128 = depythonize(&i128::MIN.into_py(py).into_bound(py)).unwrap();
801+
});
802+
}
752803
}

0 commit comments

Comments
 (0)