Skip to content

Commit

Permalink
doc: impl Serialize instead of using a derive
Browse files Browse the repository at this point in the history
`actual` and `expect` may not directly implement Serialize.
Instead, impl Serialize and use the AsNode trait to serialize.

I did consider having `actual`/`expect` instead be an Option<Node<'_>>
which _ought_ to allow for deriving Serialize, but the macro still
wanted to enforce a bound on the `A` & `E` parameters implementing
Serialize, even though that's not actually required.
  • Loading branch information
jgraettinger committed Nov 3, 2023
1 parent a79a319 commit 9e405ab
Showing 1 changed file with 27 additions and 8 deletions.
35 changes: 27 additions & 8 deletions crates/doc/src/diff.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use super::{AsNode, Field, Fields, Node};
use super::{AsNode, Field, Fields, Node, SerPolicy};
use itertools::{
EitherOrBoth::{Both, Left, Right},
Itertools,
};
use json::Location;
use serde::Serialize;

/// Diff an actual (observed) document against an expected document,
/// pushing all detected differences into a Vec. Object properties
Expand All @@ -20,20 +19,40 @@ pub fn diff<'a, 'e, A: AsNode, E: AsNode>(
}

/// Diff is a detected difference within a document.
#[derive(Serialize, Debug)]
#[derive(Debug)]
pub struct Diff<'a, 'e, A: AsNode, E: AsNode> {
/// JSON-Pointer location of the difference.
pub location: String,
/// Actual value at the document location.
#[serde(skip_serializing_if = "Option::is_none")]
pub actual: Option<&'a A>,
/// Expected value at the document location.
#[serde(skip_serializing_if = "Option::is_none")]
pub expect: Option<&'e E>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<&'static str>,
}

impl<'a, 'e, A: AsNode, E: AsNode> serde::Serialize for Diff<'a, 'e, A, E> {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeMap;

let mut map = s.serialize_map(None)?;
map.serialize_entry("location", &self.location)?;

if let Some(v) = self.actual {
map.serialize_entry("actual", &SerPolicy::debug().on(v))?;
}
if let Some(v) = self.expect {
map.serialize_entry("expect", &SerPolicy::debug().on(v))?;
}
if let Some(note) = self.note {
map.serialize_entry("note", note)?;
}
map.end()
}
}

impl<'a, 'e, A: AsNode, E: AsNode> Diff<'a, 'e, A, E> {
fn diff_inner(
actual: Option<&'a A>,
Expand Down Expand Up @@ -86,8 +105,8 @@ impl<'a, 'e, A: AsNode, E: AsNode> Diff<'a, 'e, A, E> {
if !f64_eq(actual_f64, expected_f64) {
out.push(Diff {
location: format!("{}", location.pointer_str()),
expect,
actual,
expect,
note: None,
});
}
Expand All @@ -100,8 +119,8 @@ impl<'a, 'e, A: AsNode, E: AsNode> Diff<'a, 'e, A, E> {
_ => {
out.push(Diff {
location: location.pointer_str().to_string(),
expect,
actual,
expect,
note: if actual.is_none() {
Some("missing in actual document")
} else {
Expand Down

0 comments on commit 9e405ab

Please sign in to comment.