Repository: not-fl3/nanoserde (Rust)

Issue:
Implicit integer wrapping on deserialization causes wrong values
First, thanks a lot for this crate! I have used it for over a year in [godot-rust](https://github.com/godot-rust/gdext) and am very happy about the dependency-free tree and fast CI times. I wish more crates would follow such a lightweight approach 💪

Now we encountered an issue that caused a follow-up bug in our code.
Minimal reproducible example:
```rs
use nanoserde::DeJson;

#[derive(DeJson, Clone)]
pub struct EnumConstant {
    pub max: i32,
    pub zero: i32,
    pub min: i32,
}

#[test]
fn test() {
    let json = r#"{"max": 4294967295, "zero": 4294967296, "min": 4294967297}"#;
    let constant: EnumConstant = DeJson::deserialize_json(json).unwrap();
    assert_eq!(constant.max, -1);
    assert_eq!(constant.zero, 0);
    assert_eq!(constant.min, 1);
}
```

This test passes, but should not in my opinion. If a value is not representable in the target type, deserialization should fail. That's the only way I can know that my data model is inaccurate -- otherwise it's very easy to introduce silent logic errors.


Discussion:

Patch:
diff --git a/src/serde_json.rs b/src/serde_json.rs
index 014aea4..d59e7ad 100644
--- a/src/serde_json.rs
+++ b/src/serde_json.rs
@@ -714,9 +714,9 @@ impl_ser_de_json_unsigned!(u32, core::u32::MAX);
 impl_ser_de_json_unsigned!(u16, core::u16::MAX);
 impl_ser_de_json_unsigned!(u8, core::u8::MAX);
 impl_ser_de_json_signed!(i64, core::i64::MIN, core::i64::MAX);
-impl_ser_de_json_signed!(i32, core::i64::MIN, core::i64::MAX);
-impl_ser_de_json_signed!(i16, core::i64::MIN, core::i64::MAX);
-impl_ser_de_json_signed!(i8, core::i64::MIN, core::i8::MAX);
+impl_ser_de_json_signed!(i32, core::i32::MIN, core::i32::MAX);
+impl_ser_de_json_signed!(i16, core::i16::MIN, core::i16::MAX);
+impl_ser_de_json_signed!(i8, core::i8::MIN, core::i8::MAX);
 impl_ser_de_json_float!(f64);
 impl_ser_de_json_float!(f32);
 
diff --git a/src/serde_ron.rs b/src/serde_ron.rs
index 2263d63..ba7b049 100644
--- a/src/serde_ron.rs
+++ b/src/serde_ron.rs
@@ -754,9 +754,9 @@ impl_ser_de_ron_unsigned!(u32, core::u32::MAX);
 impl_ser_de_ron_unsigned!(u16, core::u16::MAX);
 impl_ser_de_ron_unsigned!(u8, core::u8::MAX);
 impl_ser_de_ron_signed!(i64, core::i64::MIN, core::i64::MAX);
-impl_ser_de_ron_signed!(i32, core::i64::MIN, core::i64::MAX);
-impl_ser_de_ron_signed!(i16, core::i64::MIN, core::i64::MAX);
-impl_ser_de_ron_signed!(i8, core::i64::MIN, core::i8::MAX);
+impl_ser_de_ron_signed!(i32, core::i32::MIN, core::i32::MAX);
+impl_ser_de_ron_signed!(i16, core::i16::MIN, core::i16::MAX);
+impl_ser_de_ron_signed!(i8, core::i8::MIN, core::i8::MAX);
 impl_ser_de_ron_float!(f64);
 impl_ser_de_ron_float!(f32);
 


Test patch:
diff --git a/tests/json.rs b/tests/json.rs
index d24e1c9..3558be9 100644
--- a/tests/json.rs
+++ b/tests/json.rs
@@ -842,3 +842,30 @@ fn array_leak_test() {
 
     assert!(TOGGLED_ON_DROP.load(std::sync::atomic::Ordering::SeqCst))
 }
+
+// https://github.com/not-fl3/nanoserde/issues/89
+#[test]
+fn test_deser_oversized_value() {
+    use nanoserde::DeJson;
+
+    #[derive(DeJson, Clone, PartialEq, Debug)]
+    pub struct EnumConstant {
+        value: i32,
+    }
+    let max_json = format!(r#"{{"value": {} }}"#, i32::MAX);
+    let wrap_json = format!(r#"{{"value": {} }}"#, i32::MAX as i64 + 1);
+    assert_eq!(
+        <EnumConstant as DeJson>::deserialize_json(&max_json).unwrap(),
+        EnumConstant { value: i32::MAX }
+    );
+    assert_eq!(
+        <EnumConstant as DeJson>::deserialize_json(&wrap_json)
+            .unwrap_err()
+            .msg,
+        format!(
+            "Value out of range {}>{} ",
+            (i32::MAX as i64 + 1).to_string(),
+            i32::MAX.to_string()
+        )
+    );
+}
diff --git a/tests/ron.rs b/tests/ron.rs
index 9806e04..c71ae6f 100644
--- a/tests/ron.rs
+++ b/tests/ron.rs
@@ -457,3 +457,31 @@ fn array_leak_test() {
 
     assert!(TOGGLED_ON_DROP.load(std::sync::atomic::Ordering::SeqCst))
 }
+
+// https://github.com/not-fl3/nanoserde/issues/89
+#[test]
+fn test_deser_oversized_value() {
+    use nanoserde::DeRon;
+
+    #[derive(DeRon, Clone, PartialEq, Debug)]
+    pub struct EnumConstant {
+        value: i32,
+    }
+
+    let max_ron = format!(r#"(value:{})"#, i32::MAX);
+    let wrap_ron = format!(r#"(value:{})"#, i32::MAX as i64 + 1);
+    assert_eq!(
+        <EnumConstant as DeRon>::deserialize_ron(&max_ron).unwrap(),
+        EnumConstant { value: i32::MAX }
+    );
+    assert_eq!(
+        <EnumConstant as DeRon>::deserialize_ron(&wrap_ron)
+            .unwrap_err()
+            .msg,
+        format!(
+            "Value out of range {}>{} ",
+            (i32::MAX as i64 + 1).to_string(),
+            i32::MAX.to_string()
+        )
+    );
+}