Skip to content

Commit ed23eed

Browse files
authored
[ENH]: serde util for optional u128 (#4659)
## Description of changes Introduces a type module for serializing and deserializing optional u128. Serde doesn't natively support serializing and deserializing 128-bit integers because the maximum integer size in JSON is a 64-bit integer. This module solves this problem by serializing 128-bit integers into their hex string equivalents. ## Test plan - [x] Tests pass locally with `pytest` for python, `yarn test` for js, `cargo test` for rust ## Documentation Changes N/A
1 parent 3d65425 commit ed23eed

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

rust/types/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod tenant;
2323
mod validators;
2424
mod where_parsing;
2525

26+
pub mod optional_u128;
2627
pub mod regex;
2728

2829
// Re-export the types module, so that we can use it as a single import in other modules.

rust/types/src/optional_u128.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
pub mod optional_u128_as_hex {
2+
use serde::de::Error;
3+
use serde::{Deserialize, Deserializer, Serializer};
4+
5+
/// Serializes `Option<u128>` as lowercase hex string if Some, skips if None.
6+
pub fn serialize<S>(val: &Option<u128>, serializer: S) -> Result<S::Ok, S::Error>
7+
where
8+
S: Serializer,
9+
{
10+
match val {
11+
Some(v) => serializer.serialize_str(&format!("{:x}", v)),
12+
None => serializer.serialize_none(),
13+
}
14+
}
15+
16+
/// Deserializes a lowercase hex string into `Option<u128>`.
17+
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<u128>, D::Error>
18+
where
19+
D: Deserializer<'de>,
20+
{
21+
let opt: Option<String> = Option::deserialize(deserializer)?;
22+
match opt {
23+
Some(s) => {
24+
let val = u128::from_str_radix(&s, 16).map_err(D::Error::custom)?;
25+
Ok(Some(val))
26+
}
27+
None => Ok(None),
28+
}
29+
}
30+
}
31+
32+
#[cfg(test)]
33+
mod tests {
34+
use super::optional_u128_as_hex;
35+
use serde::{Deserialize, Serialize};
36+
37+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
38+
struct TestStruct {
39+
#[serde(
40+
with = "optional_u128_as_hex",
41+
default,
42+
skip_serializing_if = "Option::is_none"
43+
)]
44+
value: Option<u128>,
45+
}
46+
47+
#[test]
48+
fn test_serialize_some_u128() {
49+
let s = TestStruct { value: Some(255) };
50+
let json = serde_json::to_string(&s).unwrap();
51+
assert_eq!(json, r#"{"value":"ff"}"#);
52+
}
53+
54+
#[test]
55+
fn test_serialize_none() {
56+
let s = TestStruct { value: None };
57+
let json = serde_json::to_string(&s).unwrap();
58+
assert_eq!(json, r#"{}"#);
59+
}
60+
61+
#[test]
62+
fn test_deserialize_some_u128() {
63+
let json = r#"{"value":"ff"}"#;
64+
let s: TestStruct = serde_json::from_str(json).unwrap();
65+
assert_eq!(s, TestStruct { value: Some(255) });
66+
}
67+
68+
#[test]
69+
fn test_deserialize_none() {
70+
let json = r#"{}"#;
71+
let s: TestStruct = serde_json::from_str(json).unwrap();
72+
assert_eq!(s, TestStruct { value: None });
73+
}
74+
}

0 commit comments

Comments
 (0)