Skip to content

Commit

Permalink
deer: implement Deserialize for core::num (#2378)
Browse files Browse the repository at this point in the history
* chore: port from #1975

* test: `Wrapping` + `Saturating`

* Update core.rs

* fix: forgot cfg guard
  • Loading branch information
indietyp authored Apr 13, 2023
1 parent 3bf4fa1 commit e07a6cc
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 3 deletions.
2 changes: 1 addition & 1 deletion libs/deer/src/impls/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod floating;
mod integral;
mod marker;
mod mem;
mod non_zero;
mod num;
mod option;
mod string;
mod sync;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(nightly)]
use core::num::Saturating;
use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
};

use error_stack::{Report, ResultExt};
Expand Down Expand Up @@ -69,3 +71,20 @@ impl_nonzero![
NonZeroI128 <- i128,
NonZeroIsize <- isize,
];

impl<'de, T: Deserialize<'de>> Deserialize<'de> for Wrapping<T> {
type Reflection = T::Reflection;

fn deserialize<D: Deserializer<'de>>(de: D) -> error_stack::Result<Self, DeserializeError> {
T::deserialize(de).map(Self)
}
}

#[cfg(nightly)]
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Saturating<T> {
type Reflection = T::Reflection;

fn deserialize<D: Deserializer<'de>>(de: D) -> error_stack::Result<Self, DeserializeError> {
T::deserialize(de).map(Self)
}
}
1 change: 1 addition & 0 deletions libs/deer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
error_in_core,
error_generic_member_access,
integer_atomics,
saturating_int_impl,
sync_unsafe_cell,
exclusive_wrapper
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
// These values use the same logic as integral, but zero is an error!
#![cfg_attr(nightly, feature(saturating_int_impl))]

#[cfg(nightly)]
use core::num::Saturating;
use core::num::Wrapping;

use deer_desert::assert_tokens;
use proptest::prelude::*;

mod common;

Expand All @@ -9,8 +16,11 @@ use core::num::{

use deer::{Deserialize, Number};
use deer_desert::{assert_tokens_error, error, Token};
use serde::Serialize;
use serde_json::json;
use similar_asserts::assert_serde_eq;

// These values use the same logic as integral, but zero is an error!
macro_rules! test_zero {
($ty:ident) => {
paste::paste! {
Expand Down Expand Up @@ -106,3 +116,46 @@ fn usize_err_zero() {
&[Token::USize(0)],
);
}

#[cfg(not(miri))]
proptest! {
#[test]
fn wrapping_ok(value in any::<u8>()) {
let expected = Wrapping(value);

assert_tokens(&expected, &[Token::Number(Number::from(value))]);
}

#[cfg(nightly)]
#[test]
fn saturating_ok(value in any::<u8>()) {
let expected = Saturating(value);

assert_tokens(&expected, &[Token::Number(Number::from(value))]);
}
}

fn assert_json(lhs: impl Serialize, rhs: impl Serialize) {
let lhs = serde_json::to_value(lhs).expect("should be able to serialize lhs");
let rhs = serde_json::to_value(rhs).expect("should be able to serialize rhs");

assert_serde_eq!(lhs, rhs);
}

// test that the `Reflection` of all types are the same as their underlying type
#[test]
fn wrapping_reflection_same() {
let lhs = Wrapping::<u8>::reflection();
let rhs = u8::reflection();

assert_json(lhs, rhs);
}

#[cfg(nightly)]
#[test]
fn saturating_reflection_same() {
let lhs = Saturating::<u8>::reflection();
let rhs = u8::reflection();

assert_json(lhs, rhs);
}

0 comments on commit e07a6cc

Please sign in to comment.