Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This crate looks unmaintained #42

Open
stephanemagnenat opened this issue Jun 29, 2022 · 6 comments
Open

This crate looks unmaintained #42

stephanemagnenat opened this issue Jun 29, 2022 · 6 comments

Comments

@stephanemagnenat
Copy link

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

Is there a fork that is maintained?

@PPakalns
Copy link

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

@aclysma
Copy link
Collaborator

aclysma commented Apr 13, 2023

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.

@Boscop
Copy link
Contributor

Boscop commented Apr 16, 2023

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
Copy link
Contributor

Boscop commented Sep 29, 2024

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

@PPakalns
Copy link

PPakalns commented Sep 30, 2024

@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);
    }
}

@Boscop
Copy link
Contributor

Boscop commented Oct 2, 2024

@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)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants