diffo 0.2.0

Semantic diffing for Rust structs via serde
Documentation
use serde_value::Value;

/// Represents a change at a specific path in the diff.
///
/// # Examples
///
/// ```
/// use diffo::Change;
/// use serde_value::Value;
///
/// let added = Change::Added(Value::I64(42));
/// let removed = Change::Removed(Value::String("old".into()));
/// let modified = Change::Modified {
///     from: Value::I64(1),
///     to: Value::I64(2),
/// };
/// ```
#[derive(Debug, Clone, PartialEq)]
pub enum Change {
    /// Value was added (present in new, absent in old).
    Added(Value),

    /// Value was removed (present in old, absent in new).
    Removed(Value),

    /// Value was modified.
    Modified {
        /// The old value.
        from: Value,
        /// The new value.
        to: Value,
    },

    /// Collection was truncated in output due to size limits.
    Elided {
        /// Reason for elision.
        reason: String,
        /// Number of items that were elided.
        count: usize,
    },
}

impl Change {
    /// Returns true if this is an `Added` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// use diffo::Change;
    /// use serde_value::Value;
    ///
    /// let change = Change::Added(Value::I64(42));
    /// assert!(change.is_added());
    /// ```
    pub fn is_added(&self) -> bool {
        matches!(self, Change::Added(_))
    }

    /// Returns true if this is a `Removed` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// use diffo::Change;
    /// use serde_value::Value;
    ///
    /// let change = Change::Removed(Value::I64(42));
    /// assert!(change.is_removed());
    /// ```
    pub fn is_removed(&self) -> bool {
        matches!(self, Change::Removed(_))
    }

    /// Returns true if this is a `Modified` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// use diffo::Change;
    /// use serde_value::Value;
    ///
    /// let change = Change::Modified {
    ///     from: Value::I64(1),
    ///     to: Value::I64(2),
    /// };
    /// assert!(change.is_modified());
    /// ```
    pub fn is_modified(&self) -> bool {
        matches!(self, Change::Modified { .. })
    }

    /// Returns true if this is an `Elided` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// use diffo::Change;
    ///
    /// let change = Change::Elided {
    ///     reason: "too large".into(),
    ///     count: 1000,
    /// };
    /// assert!(change.is_elided());
    /// ```
    pub fn is_elided(&self) -> bool {
        matches!(self, Change::Elided { .. })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_is_added() {
        let change = Change::Added(Value::I64(42));
        assert!(change.is_added());
        assert!(!change.is_removed());
        assert!(!change.is_modified());
        assert!(!change.is_elided());
    }

    #[test]
    fn test_is_removed() {
        let change = Change::Removed(Value::String("test".into()));
        assert!(!change.is_added());
        assert!(change.is_removed());
        assert!(!change.is_modified());
        assert!(!change.is_elided());
    }

    #[test]
    fn test_is_modified() {
        let change = Change::Modified {
            from: Value::I64(1),
            to: Value::I64(2),
        };
        assert!(!change.is_added());
        assert!(!change.is_removed());
        assert!(change.is_modified());
        assert!(!change.is_elided());
    }

    #[test]
    fn test_is_elided() {
        let change = Change::Elided {
            reason: "test".into(),
            count: 100,
        };
        assert!(!change.is_added());
        assert!(!change.is_removed());
        assert!(!change.is_modified());
        assert!(change.is_elided());
    }

    #[test]
    fn test_clone() {
        let change = Change::Modified {
            from: Value::I64(1),
            to: Value::I64(2),
        };
        let cloned = change.clone();
        assert_eq!(change, cloned);
    }

    #[test]
    fn test_debug() {
        let change = Change::Added(Value::I64(42));
        let debug_str = format!("{:?}", change);
        assert!(debug_str.contains("Added"));
        assert!(debug_str.contains("42"));
    }
}