serde-diff icon indicating copy to clipboard operation
serde-diff copied to clipboard

This crate looks unmaintained

Open stephanemagnenat opened this issue 3 years ago • 6 comments

Looking at the issues, PR and latest commit, this crate looks unmaintained, which is a pity.

Is there a fork that is maintained?

stephanemagnenat avatar Jun 29 '22 13:06 stephanemagnenat

Looks like there isn't and there isn't any crate with similar functionality.

PPakalns avatar Apr 13 '23 17:04 PPakalns

I probably should have replied earlier to this, sorry. I personally just don't have time to spare for this project, and I suspect @kabergstrom is in the same place with that. I would be quite happy to see someone fork this project and continue it forward.

aclysma avatar Apr 13 '23 18:04 aclysma

If anyone wants to take this crate further: It would be nice to represent the diff in a more space-efficient / binary way (maybe BSON/bincode). And e.g. instead of encoding enum variants as strings, using their discriminant (int) instead.

Boscop avatar Apr 16 '23 09:04 Boscop

@PPakalns Have you found a crate with similar functionality? Maybe even with more compact data representation like CBOR?

Boscop avatar Sep 29 '24 15:09 Boscop

@Boscop Hi, I have not found such crate. Additionally, this crate wasn't very efficient for my use case because it always tries to compare full state and it gets slow very fast with linear growing state.

I have experimented with writing custom "StateTracking" library that tracks modifications of the data structure and stores them, so no additional comparison is needed. Sadly the API interface ergonomics weren't very nice to use so I decided to use another approach.

In my use case for users of the diff full state is not needed, I manually store the changes that should be sent to the client and reconstruct the necessary state representation on the client side.

If intereseted, API interface that I explored. I can publish the library, but will not have time to improve it as I am not using it:
#[cfg(test)]
mod tests {
    use super::*;
    use crate as diff_tracker;

    #[derive(Default, Clone, DiffTracker, serde::Serialize, serde::Deserialize)]
    pub struct Test {
        a: u32,
        b: bool,
        unit: TestUnit,
        inner: TestInner,
    }

    #[derive(Default, Clone, DiffTracker, serde::Serialize, serde::Deserialize)]
    pub struct TestInner {
        a: u8,
        b: u16,
        c: u32,
        id_to_value: HashMap<i32, TestHashMap>,
    }

    #[derive(Default, Clone, DiffTracker, serde::Serialize, serde::Deserialize)]
    pub struct TestHashMap {
        a: u8,
    }

    #[derive(Default, Clone, Copy, serde::Serialize, serde::Deserialize)]
    pub struct TestUnit {
        a: u8,
    }
    diff_tracker_base!(TestUnit);

    #[test]
    fn it_works() {
        let mut test = Test::default();
        let mut test_old = test.clone();

        let mut test_changes = <Test as DiffTracked>::Change::default();

        let mut tracker = <Test as DiffTracked>::Tracker::new(&mut test, &mut test_changes);

        assert_eq!(tracker.a, 0);
        tracker.a_mut().get().set(10);
        assert_eq!(tracker.a, 10);

        assert_eq!(tracker.inner.a, 0);
        tracker.inner_mut().get().a_mut().get().set(5);
        assert_eq!(tracker.inner.a, 5);

        let a = tracker.with_inner(|mut inner| {
            inner.with_a(|mut a| {
                a.set(9);
                *a.cow() = 10;
                *a
            })
        });
        assert_eq!(a, 10);

        assert_eq!(tracker.inner.a, 10);

        assert_eq!(tracker.unit.a, 0);
        tracker.with_unit(|mut unit| {
            let mut unit = unit.cow();
            unit.a = 5;
        });
        assert_eq!(tracker.unit.a, 5);

        assert_eq!(tracker.inner.id_to_value.len(), 0);
        tracker
            .inner_mut()
            .get()
            .id_to_value_mut()
            .get()
            .insert(5, TestHashMap { a: 5 });
        tracker.with_inner(|mut inner| {
            inner.with_id_to_value(|mut id_to_value| {
                let mut entry = id_to_value.entry(&10);
                let mut value = entry.get_or_default();
                value.with_a(|mut a| {
                    a.set(14);
                });
            });
        });
        assert_eq!(tracker.inner.id_to_value.get(&5).map(|v| v.a), Some(5));

        {
            let mut inner_core = tracker.inner_mut();
            let mut inner = inner_core.get();
            let mut map = inner.id_to_value_mut();
            let mut map = map.get();
            let mut entry_core = map.entry(&5);
            let mut entry = entry_core.get_mut().unwrap();
            let mut a = entry.a_mut();
            let mut a = a.get();
            a.set(11);
        }

        assert_eq!(tracker.inner.id_to_value.get(&5).map(|v| v.a), Some(11));

        assert_eq!(&test_changes.a.as_ref().unwrap().value, &Some(10));
        assert_eq!(
            &test_changes
                .inner
                .as_ref()
                .unwrap()
                .a
                .as_ref()
                .unwrap()
                .value,
            &Some(10)
        );

        assert_eq!(test_old.a, 0);
        assert_eq!(test_old.inner.a, 0);
        assert_eq!(test_old.inner.id_to_value.get(&5).map(|v| v.a), None);
        assert_eq!(test_old.unit.a, 0);

        let serialized_test_changes = serde_json::to_string_pretty(&test_changes).unwrap();
        println!("{}", &serialized_test_changes);
        let test_changes: TestChange = serde_json::from_str(&serialized_test_changes).unwrap();
        test_old.apply(&test_changes);

        assert_eq!(test_old.a, 10);
        assert_eq!(test_old.inner.a, 10);
        assert_eq!(test_old.inner.id_to_value.get(&5).map(|v| v.a), Some(11));
        assert_eq!(test_old.inner.id_to_value.get(&10).map(|v| v.a), Some(14));
        assert_eq!(test_old.unit.a, 5);
    }
}

PPakalns avatar Sep 30 '24 06:09 PPakalns

@PPakalns Interesting. Have you investigated whether any of these reactive/signals-based crates work for your use-case (instead of diffing: Send granular updates on each field change)?

  • https://crates.io/crates/futures-signals
  • https://crates.io/crates/dioxus-signals
  • https://crates.io/crates/rxrust
  • https://crates.io/crates/another-rxrust

Boscop avatar Oct 02 '24 17:10 Boscop