From 08e4ed9d407128debe616cfb9d3865e1e69b338e Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Wed, 8 Nov 2023 16:15:11 +0800 Subject: [PATCH] feat: add `from_checkout` mark to event (#164) --- crates/loro-internal/src/event.rs | 20 +++++++++++++++++++- crates/loro-internal/src/loro.rs | 2 ++ crates/loro-internal/src/state.rs | 3 +++ crates/loro-internal/src/txn.rs | 1 + crates/loro-internal/tests/test.rs | 24 +++++++++++++++++++++++- 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/crates/loro-internal/src/event.rs b/crates/loro-internal/src/event.rs index 3482a0ce..66f7bbb2 100644 --- a/crates/loro-internal/src/event.rs +++ b/crates/loro-internal/src/event.rs @@ -1,4 +1,5 @@ use enum_as_inner::EnumAsInner; +use fxhash::FxHasher64; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; @@ -10,7 +11,10 @@ use crate::{ InternalString, LoroValue, }; -use std::borrow::Cow; +use std::{ + borrow::Cow, + hash::{Hash, Hasher}, +}; use loro_common::{ContainerID, TreeID}; @@ -43,9 +47,21 @@ pub struct DocDiff { pub to: Frontiers, pub origin: InternalString, pub local: bool, + /// Whether the diff is created from the checkout operation. + pub from_checkout: bool, pub diff: Vec, } +impl DocDiff { + /// Get the unique id of the diff. + pub fn id(&self) -> u64 { + let mut hasher = FxHasher64::default(); + self.from.hash(&mut hasher); + self.to.hash(&mut hasher); + hasher.finish() + } +} + #[derive(Debug, Clone)] pub(crate) struct InternalContainerDiff { pub(crate) idx: ContainerIdx, @@ -71,6 +87,7 @@ pub(crate) enum DiffVariant { pub(crate) struct InternalDocDiff<'a> { pub(crate) origin: InternalString, pub(crate) local: bool, + pub(crate) from_checkout: bool, pub(crate) diff: Cow<'a, [InternalContainerDiff]>, pub(crate) new_version: Cow<'a, Frontiers>, } @@ -80,6 +97,7 @@ impl<'a> InternalDocDiff<'a> { InternalDocDiff { origin: self.origin, local: self.local, + from_checkout: self.from_checkout, diff: Cow::Owned((*self.diff).to_owned()), new_version: Cow::Owned((*self.new_version).to_owned()), } diff --git a/crates/loro-internal/src/loro.rs b/crates/loro-internal/src/loro.rs index f8f70a13..e4a72640 100644 --- a/crates/loro-internal/src/loro.rs +++ b/crates/loro-internal/src/loro.rs @@ -404,6 +404,7 @@ impl LoroDoc { origin, local: false, diff: (diff).into(), + from_checkout: false, new_version: Cow::Owned(oplog.frontiers().clone()), }); } @@ -627,6 +628,7 @@ impl LoroDoc { origin: "checkout".into(), local: true, diff: Cow::Owned(diff), + from_checkout: true, new_version: Cow::Owned(frontiers.clone()), }); let events = state.take_events(); diff --git a/crates/loro-internal/src/state.rs b/crates/loro-internal/src/state.rs index 05a12446..a3939122 100644 --- a/crates/loro-internal/src/state.rs +++ b/crates/loro-internal/src/state.rs @@ -429,6 +429,7 @@ impl DocState { self.record_diff(InternalDocDiff { origin: Default::default(), local: false, + from_checkout: false, diff, new_version: Cow::Borrowed(&frontiers), }); @@ -664,6 +665,7 @@ impl DocState { let to = (*diffs.last().unwrap().new_version).to_owned(); let origin = diffs[0].origin.clone(); let local = diffs[0].local; + let from_checkout = diffs[0].from_checkout; for diff in diffs { #[allow(clippy::unnecessary_to_owned)] for container_diff in diff.diff.into_owned() { @@ -714,6 +716,7 @@ impl DocState { from, to, origin, + from_checkout, local, diff, } diff --git a/crates/loro-internal/src/txn.rs b/crates/loro-internal/src/txn.rs index f2d70a24..f4f01cd5 100644 --- a/crates/loro-internal/src/txn.rs +++ b/crates/loro-internal/src/txn.rs @@ -321,6 +321,7 @@ impl Transaction { }) .collect(), ), + from_checkout: false, new_version: Cow::Borrowed(oplog.frontiers()), }), ); diff --git a/crates/loro-internal/tests/test.rs b/crates/loro-internal/tests/test.rs index 2268a181..befadcb6 100644 --- a/crates/loro-internal/tests/test.rs +++ b/crates/loro-internal/tests/test.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, Mutex}; +use std::sync::{atomic::AtomicBool, Arc, Mutex}; use loro_common::{ContainerID, ContainerType, LoroValue, ID}; use loro_internal::{ @@ -6,6 +6,28 @@ use loro_internal::{ }; use serde_json::json; +#[test] +fn event_from_checkout() { + let mut a = LoroDoc::new_auto_commit(); + let sub_id = a.subscribe_root(Arc::new(|event| { + assert!(!event.doc.from_checkout); + })); + a.get_text("text").insert_(0, "hello").unwrap(); + a.commit_then_renew(); + let version = a.oplog_frontiers(); + a.get_text("text").insert_(0, "hello").unwrap(); + a.commit_then_renew(); + a.unsubscribe(sub_id); + let ran = Arc::new(AtomicBool::new(false)); + let ran_cloned = ran.clone(); + a.subscribe_root(Arc::new(move |event| { + assert!(event.doc.from_checkout); + ran.store(true, std::sync::atomic::Ordering::Relaxed); + })); + a.checkout(&version).unwrap(); + assert!(ran_cloned.load(std::sync::atomic::Ordering::Relaxed)); +} + #[test] fn out_of_bound_test() { let a = LoroDoc::new_auto_commit();