Skip to main content

Diff

Trait Diff 

Source
pub trait Diff: Sized {
    type Delta: Clone + Serialize + DeserializeOwned + Send + Sync;

    // Required methods
    fn diff(old: &Self, new: &Self) -> Self::Delta;
    fn apply(base: &Self, delta: &Self::Delta) -> Self;
}
Available on crate features delta-checkpoint and graph only.
Expand description

Trait for types that can compute and apply incremental diffs.

Implementors define an associated Delta type representing the difference between two instances. The trait guarantees a round-trip property:

For any states s1 and s2, Diff::apply(&s1, &Diff::diff(&s1, &s2)) == s2.

§Example

use adk_graph::delta::Diff;
use serde::{Serialize, Deserialize};

#[derive(Clone, Debug, PartialEq)]
struct Counter(u64);

#[derive(Clone, Debug, Serialize, Deserialize)]
struct CounterDelta(i64);

impl Diff for Counter {
    type Delta = CounterDelta;

    fn diff(old: &Self, new: &Self) -> Self::Delta {
        CounterDelta(new.0 as i64 - old.0 as i64)
    }

    fn apply(base: &Self, delta: &Self::Delta) -> Self {
        Counter((base.0 as i64 + delta.0) as u64)
    }
}

let s1 = Counter(5);
let s2 = Counter(12);
let delta = Counter::diff(&s1, &s2);
assert_eq!(Counter::apply(&s1, &delta), s2);

Required Associated Types§

Source

type Delta: Clone + Serialize + DeserializeOwned + Send + Sync

The delta representation capturing the difference between two states.

Must be serializable for checkpoint storage and sendable across async boundaries.

Required Methods§

Source

fn diff(old: &Self, new: &Self) -> Self::Delta

Compute the delta that transforms old into new.

The returned delta, when applied to old via Diff::apply, must reproduce new exactly.

Source

fn apply(base: &Self, delta: &Self::Delta) -> Self

Apply a delta to a base state, producing the resulting state.

This is the inverse of Diff::diff: applying the delta produced by diff(old, new) to old yields new.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl Diff for HashMap<String, Value>

Source§

fn diff( old: &HashMap<String, Value>, new: &HashMap<String, Value>, ) -> <HashMap<String, Value> as Diff>::Delta

Compute the delta between two HashMap<String, Value> instances.

Classifies each key into one of three categories:

  • added: present in new but absent from old
  • removed: present in old but absent from new
  • modified: present in both but with different values
§Example
use adk_graph::delta::Diff;
use serde_json::{Value, json};
use std::collections::HashMap;

let old: HashMap<String, Value> = [
    ("x".to_string(), json!("hello")),
    ("y".to_string(), json!(42)),
].into_iter().collect();

let new: HashMap<String, Value> = [
    ("x".to_string(), json!("world")),
    ("z".to_string(), json!(true)),
].into_iter().collect();

let delta = <HashMap<String, Value> as Diff>::diff(&old, &new);
assert!(delta.added.contains_key("z"));
assert!(delta.removed.contains(&"y".to_string()));
assert!(delta.modified.contains_key("x"));
Source§

fn apply( base: &HashMap<String, Value>, delta: &<HashMap<String, Value> as Diff>::Delta, ) -> HashMap<String, Value>

Apply a delta to a base HashMap<String, Value>, producing the resulting map.

Operations are applied in order: remove keys, insert added keys, update modified keys.

§Example
use adk_graph::delta::Diff;
use serde_json::{Value, json};
use std::collections::HashMap;

let old: HashMap<String, Value> = [
    ("a".to_string(), json!(1)),
    ("b".to_string(), json!(2)),
].into_iter().collect();

let new: HashMap<String, Value> = [
    ("a".to_string(), json!(1)),
    ("c".to_string(), json!(3)),
].into_iter().collect();

let delta = <HashMap<String, Value> as Diff>::diff(&old, &new);
assert_eq!(<HashMap<String, Value> as Diff>::apply(&old, &delta), new);
Source§

type Delta = MapDelta

Source§

impl Diff for String

Source§

fn diff(old: &String, new: &String) -> <String as Diff>::Delta

Compute the delta between two strings using character-level diffing.

Uses similar::TextDiff::from_chars() to compute the minimal set of edit operations that transform old into new.

§Example
use adk_graph::delta::{Diff, StringOp};

let old = "abcdef".to_string();
let new = "abXYef".to_string();

let delta = <String as Diff>::diff(&old, &new);
// The delta contains: Equal("ab"), Delete(2), Insert("XY"), Equal("ef")
assert_eq!(<String as Diff>::apply(&old, &delta), new);
Source§

fn apply(base: &String, delta: &<String as Diff>::Delta) -> String

Apply a delta to a base string, producing the resulting string.

Replays the edit operations in order:

  • Equal(s): advance past s.len() characters in the base (copy them)
  • Delete(n): skip n characters in the base
  • Insert(s): append s to the result
§Example
use adk_graph::delta::Diff;

let old = "hello world".to_string();
let new = "hello rust".to_string();
let delta = <String as Diff>::diff(&old, &new);
assert_eq!(<String as Diff>::apply(&old, &delta), new);
Source§

type Delta = StringDelta

Source§

impl Diff for Vec<Value>

Source§

fn diff(old: &Vec<Value>, new: &Vec<Value>) -> <Vec<Value> as Diff>::Delta

Compute the delta between two Vec<Value> instances.

If new is a strict extension of old (i.e., old is a prefix of new), the delta captures only the appended items and the start index. Otherwise, the delta stores the full new vec as a replacement.

§Example
use adk_graph::delta::Diff;
use serde_json::{Value, json};

// Append case
let old = vec![json!("a"), json!("b")];
let new = vec![json!("a"), json!("b"), json!("c")];
let delta = <Vec<Value> as Diff>::diff(&old, &new);
assert!(!delta.full_replacement);

// Modification case (full replacement)
let old = vec![json!(1), json!(2)];
let new = vec![json!(1), json!(99)];
let delta = <Vec<Value> as Diff>::diff(&old, &new);
assert!(delta.full_replacement);
Source§

fn apply(base: &Vec<Value>, delta: &<Vec<Value> as Diff>::Delta) -> Vec<Value>

Apply a delta to a base Vec<Value>, producing the resulting vec.

If the delta is a full replacement, the base is ignored and the delta’s items are returned directly. Otherwise, the base is truncated to start_index and the delta’s items are appended.

§Example
use adk_graph::delta::Diff;
use serde_json::{Value, json};

let old = vec![json!(1), json!(2)];
let new = vec![json!(1), json!(2), json!(3)];
let delta = <Vec<Value> as Diff>::diff(&old, &new);
assert_eq!(<Vec<Value> as Diff>::apply(&old, &delta), new);
Source§

type Delta = VecDelta

Implementors§