Skip to content

Commit 2a2adb1

Browse files
authored
Merge pull request #1204 from dtolnay/u128
Add Number u128 conversions
2 parents 7e45e3d + d86703f commit 2a2adb1

File tree

2 files changed

+72
-14
lines changed

2 files changed

+72
-14
lines changed

src/number.rs

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -146,19 +146,6 @@ impl Number {
146146
self.n.parse().ok()
147147
}
148148

149-
/// If the `Number` is an integer, represent it as i128 if possible. Returns
150-
/// None otherwise.
151-
pub fn as_i128(&self) -> Option<i128> {
152-
#[cfg(not(feature = "arbitrary_precision"))]
153-
match self.n {
154-
N::PosInt(n) => Some(n as i128),
155-
N::NegInt(n) => Some(n as i128),
156-
N::Float(_) => None,
157-
}
158-
#[cfg(feature = "arbitrary_precision")]
159-
self.n.parse().ok()
160-
}
161-
162149
/// If the `Number` is an integer, represent it as u64 if possible. Returns
163150
/// None otherwise.
164151
pub fn as_u64(&self) -> Option<u64> {
@@ -211,6 +198,31 @@ impl Number {
211198
}
212199
}
213200

201+
/// If the `Number` is an integer, represent it as i128 if possible. Returns
202+
/// None otherwise.
203+
pub fn as_i128(&self) -> Option<i128> {
204+
#[cfg(not(feature = "arbitrary_precision"))]
205+
match self.n {
206+
N::PosInt(n) => Some(n as i128),
207+
N::NegInt(n) => Some(n as i128),
208+
N::Float(_) => None,
209+
}
210+
#[cfg(feature = "arbitrary_precision")]
211+
self.n.parse().ok()
212+
}
213+
214+
/// If the `Number` is an integer, represent it as u128 if possible. Returns
215+
/// None otherwise.
216+
pub fn as_u128(&self) -> Option<u128> {
217+
#[cfg(not(feature = "arbitrary_precision"))]
218+
match self.n {
219+
N::PosInt(n) => Some(n as u128),
220+
N::NegInt(_) | N::Float(_) => None,
221+
}
222+
#[cfg(feature = "arbitrary_precision")]
223+
self.n.parse().ok()
224+
}
225+
214226
/// Converts an `i128` to a `Number`. Numbers smaller than i64::MIN or
215227
/// larger than u64::MAX can only be represented in `Number` if serde_json's
216228
/// "arbitrary_precision" feature is enabled.
@@ -240,6 +252,33 @@ impl Number {
240252
Some(Number { n })
241253
}
242254

255+
/// Converts a `u128` to a `Number`. Numbers greater than u64::MAX can only
256+
/// be represented in `Number` if serde_json's "arbitrary_precision" feature
257+
/// is enabled.
258+
///
259+
/// ```
260+
/// # use serde_json::Number;
261+
/// #
262+
/// assert!(Number::from_u128(256).is_some());
263+
/// ```
264+
pub fn from_u128(i: u128) -> Option<Number> {
265+
let n = {
266+
#[cfg(not(feature = "arbitrary_precision"))]
267+
{
268+
if let Ok(u) = u64::try_from(i) {
269+
N::PosInt(u)
270+
} else {
271+
return None;
272+
}
273+
}
274+
#[cfg(feature = "arbitrary_precision")]
275+
{
276+
i.to_string()
277+
}
278+
};
279+
Some(Number { n })
280+
}
281+
243282
/// Returns the exact original JSON representation that this Number was
244283
/// parsed from.
245284
///
@@ -376,13 +415,22 @@ impl<'de> Deserialize<'de> for Number {
376415
where
377416
E: de::Error,
378417
{
379-
Number::from_i128(value).ok_or_else(|| de::Error::custom("not a JSON number"))
418+
Number::from_i128(value)
419+
.ok_or_else(|| de::Error::custom("JSON number out of range"))
380420
}
381421

382422
fn visit_u64<E>(self, value: u64) -> Result<Number, E> {
383423
Ok(value.into())
384424
}
385425

426+
fn visit_u128<E>(self, value: u128) -> Result<Number, E>
427+
where
428+
E: de::Error,
429+
{
430+
Number::from_u128(value)
431+
.ok_or_else(|| de::Error::custom("JSON number out of range"))
432+
}
433+
386434
fn visit_f64<E>(self, value: f64) -> Result<Number, E>
387435
where
388436
E: de::Error,
@@ -503,6 +551,8 @@ macro_rules! deserialize_any {
503551
return visitor.visit_u64(u);
504552
} else if let Some(i) = self.as_i64() {
505553
return visitor.visit_i64(i);
554+
} else if let Some(u) = self.as_u128() {
555+
return visitor.visit_u128(u);
506556
} else if let Some(i) = self.as_i128() {
507557
return visitor.visit_i128(i);
508558
} else if let Some(f) = self.as_f64() {

src/value/de.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ impl<'de> Deserialize<'de> for Value {
5757
Ok(Value::Number(value.into()))
5858
}
5959

60+
fn visit_u128<E>(self, value: u128) -> Result<Value, E>
61+
where
62+
E: serde::de::Error,
63+
{
64+
let de = serde::de::value::U128Deserializer::new(value);
65+
Number::deserialize(de).map(Value::Number)
66+
}
67+
6068
#[inline]
6169
fn visit_f64<E>(self, value: f64) -> Result<Value, E> {
6270
Ok(Number::from_f64(value).map_or(Value::Null, Value::Number))

0 commit comments

Comments
 (0)