daft-derive 0.1.8

Derive macro for daft
Documentation
use daft::{Diffable, Leaf};
use std::collections::{BTreeMap, BTreeSet};
use uuid::Uuid;

#[derive(Debug, Eq, PartialEq, Diffable)]
enum SomeEnum {
    A,
    B,
    C(u32),
}

#[derive(Debug, Eq, PartialEq, Diffable)]
struct SomeStruct {
    a: i32,
}

#[derive(Debug, Eq, PartialEq, Diffable)]
struct Large {
    a: i32,
    b: SomeEnum,
    c: BTreeMap<Uuid, BTreeSet<usize>>,
    d: SomeStruct,
}

#[derive(Debug, Eq, PartialEq, Diffable)]
struct TupleStruct(String);

#[test]
fn test_basic() {
    let a = SomeEnum::A;
    let b = SomeEnum::B;

    // Enums are just `Leaf`s. We don't try to walk them. User code can do that
    // as necessary.
    let diff = a.diff(&b);
    let expected = Leaf { before: &SomeEnum::A, after: &SomeEnum::B };
    assert_eq!(diff, expected);

    let a = SomeStruct { a: 0 };
    let b = SomeStruct { a: 1 };
    let diff = a.diff(&b);
    let expected = SomeStructDiff { a: Leaf { before: &0, after: &1 } };
    assert_eq!(diff, expected);

    let shared_id = Uuid::new_v4();
    let c1: BTreeMap<Uuid, BTreeSet<usize>> =
        [(shared_id, [1, 2, 3, 4, 5].into_iter().collect())]
            .into_iter()
            .collect();
    let mut c2 = c1.clone();
    c2.get_mut(&shared_id).unwrap().remove(&3);
    c2.get_mut(&shared_id).unwrap().insert(6);
    c2.insert(Uuid::new_v4(), [9].into_iter().collect());
    let a = Large { a: 0, b: SomeEnum::C(4), c: c1, d: SomeStruct { a: 0 } };
    let b = Large { a: 0, b: SomeEnum::B, c: c2, d: SomeStruct { a: 1 } };
    let diff = a.diff(&b);
    println!("{diff:#?}");

    assert_eq!(diff.a.before, diff.a.after);
    assert_eq!(diff.b.before, &SomeEnum::C(4));
    assert_eq!(diff.b.after, &SomeEnum::B);
    assert_eq!(diff.c.unchanged().count(), 0);
    assert_eq!(diff.c.added.len(), 1);
    assert_eq!(diff.c.removed.len(), 0);
    assert_eq!(diff.c.modified().count(), 1);

    let set_diff = &diff.c.modified_diff().next().unwrap().1;
    assert_eq!(set_diff.common, [&1, &2, &4, &5].into_iter().collect());
    assert_eq!(set_diff.added, [&6].into_iter().collect());
    assert_eq!(set_diff.removed, [&3].into_iter().collect());

    assert_eq!(diff.d.a.before, &0);
    assert_eq!(diff.d.a.after, &1);

    let a = TupleStruct("oxide".into());
    let b = TupleStruct("computer company".into());
    let diff = a.diff(&b);
    assert_eq!(diff.0.before, &"oxide".to_string());
    assert_eq!(diff.0.after, &"computer company".to_string());
    println!("{diff:#?}");
}

#[test]
fn test_empty_structs() {
    // Cover every shape that yields an empty diff: unit, empty named, empty
    // tuple, and any of the above where every field is `#[daft(ignore)]`.
    #[derive(Debug, Eq, PartialEq, Diffable)]
    struct UnitStruct;

    #[derive(Debug, Eq, PartialEq, Diffable)]
    struct EmptyNamed {}

    #[derive(Debug, Eq, PartialEq, Diffable)]
    struct EmptyTuple();

    #[derive(Debug, Eq, PartialEq, Diffable)]
    struct AllIgnoredNamed {
        #[daft(ignore)]
        a: i32,
        #[daft(ignore)]
        b: String,
    }

    #[derive(Debug, Eq, PartialEq, Diffable)]
    struct AllIgnoredTuple(#[daft(ignore)] i32, #[daft(ignore)] String);

    // Two diffs of any empty type should compare equal -- there is nothing to
    // distinguish them.
    assert_eq!(UnitStruct.diff(&UnitStruct), UnitStruct.diff(&UnitStruct));
    assert_eq!(
        EmptyNamed {}.diff(&EmptyNamed {}),
        EmptyNamed {}.diff(&EmptyNamed {})
    );
    assert_eq!(
        EmptyTuple().diff(&EmptyTuple()),
        EmptyTuple().diff(&EmptyTuple())
    );

    // For all-ignored structs, even values that differ in the ignored fields
    // must produce equal diffs.
    let a = AllIgnoredNamed { a: 1, b: "x".into() };
    let b = AllIgnoredNamed { a: 2, b: "y".into() };
    assert_eq!(a.diff(&b), a.diff(&a));

    let a = AllIgnoredTuple(1, "x".into());
    let b = AllIgnoredTuple(2, "y".into());
    assert_eq!(a.diff(&b), a.diff(&a));

    // Debug output is just the type name with no field listing.
    assert_eq!(format!("{:?}", UnitStruct.diff(&UnitStruct)), "UnitStructDiff");
    assert_eq!(
        format!(
            "{:?}",
            AllIgnoredTuple(0, String::new())
                .diff(&AllIgnoredTuple(0, String::new()))
        ),
        "AllIgnoredTupleDiff",
    );

    // Empty diff structs should be `Send + Sync` regardless of the original
    // type's auto-traits -- there is no data inside to share.
    #[derive(Diffable)]
    struct AllIgnoredNonSync {
        #[daft(ignore)]
        _c: std::cell::Cell<u32>,
    }

    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}

    assert_send::<UnitStructDiff<'_>>();
    assert_sync::<UnitStructDiff<'_>>();
    assert_send::<AllIgnoredTupleDiff<'_>>();
    assert_sync::<AllIgnoredTupleDiff<'_>>();
    assert_send::<AllIgnoredNonSyncDiff<'_>>();
    assert_sync::<AllIgnoredNonSyncDiff<'_>>();
}