diffo 0.2.0

Semantic diffing for Rust structs via serde
Documentation
use super::Formatter;
use crate::{Change, Diff, FormatError};
use serde_json::json;

/// JSON formatter for machine-readable output.
#[derive(Debug)]
pub struct JsonFormatter {
    pretty: bool,
}

impl JsonFormatter {
    /// Create a new JSON formatter.
    pub fn new() -> Self {
        Self { pretty: false }
    }

    /// Enable pretty printing.
    pub fn pretty(mut self) -> Self {
        self.pretty = true;
        self
    }
}

impl Default for JsonFormatter {
    fn default() -> Self {
        Self::new()
    }
}

impl Formatter for JsonFormatter {
    fn format(&self, diff: &Diff) -> Result<String, FormatError> {
        let mut output = serde_json::Map::new();

        for (path, change) in diff.changes() {
            let change_obj = match change {
                Change::Added(val) => json!({
                    "type": "added",
                    "value": val,
                }),
                Change::Removed(val) => json!({
                    "type": "removed",
                    "value": val,
                }),
                Change::Modified { from, to } => json!({
                    "type": "modified",
                    "from": from,
                    "to": to,
                }),
                Change::Elided { reason, count } => json!({
                    "type": "elided",
                    "reason": reason,
                    "count": count,
                }),
            };

            output.insert(path.to_string(), change_obj);
        }

        if self.pretty {
            serde_json::to_string_pretty(&output).map_err(FormatError::Json)
        } else {
            serde_json::to_string(&output).map_err(FormatError::Json)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Path;
    use serde_value::Value;

    #[test]
    fn test_json_format() {
        let mut diff = Diff::new();
        diff.insert(Path::root().field("x"), Change::Added(Value::I64(42)));

        let formatter = JsonFormatter::new();
        let output = formatter.format(&diff).unwrap();
        assert!(output.contains("\"type\":\"added\""));
    }
}