Skip to content

Commit

Permalink
deer: implement Deserialize for core::cmp (#2385)
Browse files Browse the repository at this point in the history
* chore: move from #1875

* feat: impl `Ordering`

* test: `core::cmp`

* test: reflection same for `Reverse`

* fix: miri
  • Loading branch information
indietyp authored Apr 13, 2023
1 parent 0e8e24f commit 833d95f
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 0 deletions.
1 change: 1 addition & 0 deletions libs/deer/src/impls/core.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod array;
mod atomic;
mod bool;
mod cmp;
mod floating;
mod integral;
mod non_zero;
Expand Down
79 changes: 79 additions & 0 deletions libs/deer/src/impls/core/cmp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use core::cmp::{Ordering, Reverse};

use error_stack::{Report, Result, ResultExt};

use crate::{
error::{
DeserializeError, ExpectedVariant, ReceivedVariant, UnknownVariantError, Variant,
VisitorError,
},
Deserialize, Deserializer, Document, Reflection, Schema, Visitor,
};

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

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

struct OrderingVisitor;

impl<'de> Visitor<'de> for OrderingVisitor {
type Value = Ordering;

fn expecting(&self) -> Document {
Ordering::reflection()
}

fn visit_str(self, v: &str) -> Result<Self::Value, VisitorError> {
match v {
"Less" => Ok(Ordering::Less),
"Equal" => Ok(Ordering::Equal),
"Greater" => Ok(Ordering::Greater),
_ => Err(Report::new(UnknownVariantError.into_error())
.attach(ReceivedVariant::new(v))
.attach(ExpectedVariant::new("Less"))
.attach(ExpectedVariant::new("Equal"))
.attach(ExpectedVariant::new("Greater"))
.change_context(VisitorError)),
}
}

fn visit_bytes(self, v: &[u8]) -> Result<Self::Value, VisitorError> {
match v {
b"Less" => Ok(Ordering::Less),
b"Equal" => Ok(Ordering::Equal),
b"Greater" => Ok(Ordering::Greater),
_ => {
let mut error = Report::new(UnknownVariantError.into_error())
.attach(ExpectedVariant::new("Less"))
.attach(ExpectedVariant::new("Equal"))
.attach(ExpectedVariant::new("Greater"));

if let Ok(received) = core::str::from_utf8(v) {
error = error.attach(ReceivedVariant::new(received));
}

Err(error.change_context(VisitorError))
}
}
}
}

impl Reflection for Ordering {
fn schema(_: &mut Document) -> Schema {
Schema::new("string").with("oneOf", ["Less", "Equal", "Greater"])
}
}

// we can directly call `deserialize_str` because we only have identifier with no data
impl<'de> Deserialize<'de> for Ordering {
type Reflection = Self;

fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, DeserializeError> {
de.deserialize_str(OrderingVisitor)
.change_context(DeserializeError)
}
}
46 changes: 46 additions & 0 deletions libs/deer/tests/test_impls_core_cmp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use core::cmp::{Ordering, Reverse};

use deer::Deserialize;
use deer_desert::{assert_tokens, Token};
use proptest::prelude::*;
use serde::Serialize;
use similar_asserts::assert_serde_eq;

#[cfg(not(miri))]
proptest! {
#[test]
fn reverse_ok(value in any::<u8>()) {
assert_tokens(&Reverse(value), &[Token::Number(value.into())]);
}
}

#[test]
fn ordering_less_ok() {
assert_tokens(&Ordering::Less, &[Token::String("Less")]);
}

#[test]
fn ordering_equal_ok() {
assert_tokens(&Ordering::Equal, &[Token::String("Equal")]);
}

#[test]
fn ordering_greater_ok() {
assert_tokens(&Ordering::Greater, &[Token::String("Greater")]);
}

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 reverse_reflection_same() {
let lhs = Reverse::<u8>::reflection();
let rhs = u8::reflection();

assert_json(lhs, rhs);
}

0 comments on commit 833d95f

Please sign in to comment.