Skip to content

Commit 833d95f

Browse files
authored
deer: implement Deserialize for core::cmp (#2385)
* chore: move from #1875 * feat: impl `Ordering` * test: `core::cmp` * test: reflection same for `Reverse` * fix: miri
1 parent 0e8e24f commit 833d95f

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

libs/deer/src/impls/core.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod array;
22
mod atomic;
33
mod bool;
4+
mod cmp;
45
mod floating;
56
mod integral;
67
mod non_zero;

libs/deer/src/impls/core/cmp.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use core::cmp::{Ordering, Reverse};
2+
3+
use error_stack::{Report, Result, ResultExt};
4+
5+
use crate::{
6+
error::{
7+
DeserializeError, ExpectedVariant, ReceivedVariant, UnknownVariantError, Variant,
8+
VisitorError,
9+
},
10+
Deserialize, Deserializer, Document, Reflection, Schema, Visitor,
11+
};
12+
13+
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Reverse<T> {
14+
type Reflection = T::Reflection;
15+
16+
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, DeserializeError> {
17+
T::deserialize(de).map(Reverse)
18+
}
19+
}
20+
21+
struct OrderingVisitor;
22+
23+
impl<'de> Visitor<'de> for OrderingVisitor {
24+
type Value = Ordering;
25+
26+
fn expecting(&self) -> Document {
27+
Ordering::reflection()
28+
}
29+
30+
fn visit_str(self, v: &str) -> Result<Self::Value, VisitorError> {
31+
match v {
32+
"Less" => Ok(Ordering::Less),
33+
"Equal" => Ok(Ordering::Equal),
34+
"Greater" => Ok(Ordering::Greater),
35+
_ => Err(Report::new(UnknownVariantError.into_error())
36+
.attach(ReceivedVariant::new(v))
37+
.attach(ExpectedVariant::new("Less"))
38+
.attach(ExpectedVariant::new("Equal"))
39+
.attach(ExpectedVariant::new("Greater"))
40+
.change_context(VisitorError)),
41+
}
42+
}
43+
44+
fn visit_bytes(self, v: &[u8]) -> Result<Self::Value, VisitorError> {
45+
match v {
46+
b"Less" => Ok(Ordering::Less),
47+
b"Equal" => Ok(Ordering::Equal),
48+
b"Greater" => Ok(Ordering::Greater),
49+
_ => {
50+
let mut error = Report::new(UnknownVariantError.into_error())
51+
.attach(ExpectedVariant::new("Less"))
52+
.attach(ExpectedVariant::new("Equal"))
53+
.attach(ExpectedVariant::new("Greater"));
54+
55+
if let Ok(received) = core::str::from_utf8(v) {
56+
error = error.attach(ReceivedVariant::new(received));
57+
}
58+
59+
Err(error.change_context(VisitorError))
60+
}
61+
}
62+
}
63+
}
64+
65+
impl Reflection for Ordering {
66+
fn schema(_: &mut Document) -> Schema {
67+
Schema::new("string").with("oneOf", ["Less", "Equal", "Greater"])
68+
}
69+
}
70+
71+
// we can directly call `deserialize_str` because we only have identifier with no data
72+
impl<'de> Deserialize<'de> for Ordering {
73+
type Reflection = Self;
74+
75+
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, DeserializeError> {
76+
de.deserialize_str(OrderingVisitor)
77+
.change_context(DeserializeError)
78+
}
79+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use core::cmp::{Ordering, Reverse};
2+
3+
use deer::Deserialize;
4+
use deer_desert::{assert_tokens, Token};
5+
use proptest::prelude::*;
6+
use serde::Serialize;
7+
use similar_asserts::assert_serde_eq;
8+
9+
#[cfg(not(miri))]
10+
proptest! {
11+
#[test]
12+
fn reverse_ok(value in any::<u8>()) {
13+
assert_tokens(&Reverse(value), &[Token::Number(value.into())]);
14+
}
15+
}
16+
17+
#[test]
18+
fn ordering_less_ok() {
19+
assert_tokens(&Ordering::Less, &[Token::String("Less")]);
20+
}
21+
22+
#[test]
23+
fn ordering_equal_ok() {
24+
assert_tokens(&Ordering::Equal, &[Token::String("Equal")]);
25+
}
26+
27+
#[test]
28+
fn ordering_greater_ok() {
29+
assert_tokens(&Ordering::Greater, &[Token::String("Greater")]);
30+
}
31+
32+
fn assert_json(lhs: impl Serialize, rhs: impl Serialize) {
33+
let lhs = serde_json::to_value(lhs).expect("should be able to serialize lhs");
34+
let rhs = serde_json::to_value(rhs).expect("should be able to serialize rhs");
35+
36+
assert_serde_eq!(lhs, rhs);
37+
}
38+
39+
// test that the `Reflection` of all types are the same as their underlying type
40+
#[test]
41+
fn reverse_reflection_same() {
42+
let lhs = Reverse::<u8>::reflection();
43+
let rhs = u8::reflection();
44+
45+
assert_json(lhs, rhs);
46+
}

0 commit comments

Comments
 (0)