2023-10-29 06:02:13 +00:00
|
|
|
|
2022-11-24 15:28:36 +00:00
|
|
|
use enum_as_inner::EnumAsInner;
|
2023-10-29 06:02:13 +00:00
|
|
|
|
2022-11-29 10:31:57 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2023-03-10 02:50:05 +00:00
|
|
|
use smallvec::SmallVec;
|
2022-11-23 08:26:38 +00:00
|
|
|
|
2023-03-01 13:37:58 +00:00
|
|
|
use crate::{
|
2023-10-29 06:02:13 +00:00
|
|
|
container::richtext::richtext_state::{RichtextStateChunk},
|
|
|
|
delta::{Delta, MapDelta, StyleMeta},
|
|
|
|
op::SliceRanges,
|
|
|
|
utils::string_slice::StringSlice,
|
2023-03-05 09:38:26 +00:00
|
|
|
InternalString, LoroValue,
|
2023-03-01 13:37:58 +00:00
|
|
|
};
|
2022-11-23 17:01:40 +00:00
|
|
|
|
2023-07-31 03:49:55 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
|
|
|
use loro_common::ContainerID;
|
|
|
|
|
|
|
|
use crate::{container::idx::ContainerIdx, version::Frontiers};
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct ContainerDiff {
|
2023-04-04 13:44:41 +00:00
|
|
|
pub id: ContainerID,
|
2023-07-31 03:49:55 +00:00
|
|
|
pub path: Vec<(ContainerID, Index)>,
|
|
|
|
pub(crate) idx: ContainerIdx,
|
|
|
|
pub diff: Diff,
|
2023-04-04 13:44:41 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 03:49:55 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct DiffEvent<'a> {
|
|
|
|
/// whether the event comes from the children of the container.
|
|
|
|
pub from_children: bool,
|
|
|
|
pub container: &'a ContainerDiff,
|
|
|
|
pub doc: &'a DocDiff,
|
2022-11-23 08:26:38 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 03:49:55 +00:00
|
|
|
/// It's the exposed event type.
|
|
|
|
/// It's exposed to the user. The user can use this to apply the diff to their local state.
|
|
|
|
///
|
|
|
|
/// [DocDiff] may include the diff that calculated from several transactions and imports.
|
|
|
|
/// They all should have the same origin and local flag.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct DocDiff {
|
|
|
|
pub from: Frontiers,
|
|
|
|
pub to: Frontiers,
|
|
|
|
pub origin: InternalString,
|
2022-11-24 04:15:25 +00:00
|
|
|
pub local: bool,
|
2023-07-31 03:49:55 +00:00
|
|
|
pub diff: Vec<ContainerDiff>,
|
2022-11-23 08:26:38 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 03:49:55 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct InternalContainerDiff {
|
|
|
|
pub(crate) idx: ContainerIdx,
|
2023-10-29 06:02:13 +00:00
|
|
|
pub(crate) diff: DiffVariant,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, EnumAsInner)]
|
|
|
|
pub(crate) enum DiffVariant {
|
|
|
|
Internal(InternalDiff),
|
|
|
|
External(Diff),
|
2022-12-30 09:50:23 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 03:49:55 +00:00
|
|
|
/// It's used for transmitting and recording the diff internally.
|
|
|
|
///
|
|
|
|
/// It can be convert into a [DocDiff].
|
|
|
|
// Internally, we need to batch the diff then calculate the event. Because
|
|
|
|
// we need to sort the diff by containers' created time, to make sure the
|
|
|
|
// the path to each container is up-to-date.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct InternalDocDiff<'a> {
|
|
|
|
pub(crate) origin: InternalString,
|
|
|
|
pub(crate) local: bool,
|
|
|
|
pub(crate) diff: Cow<'a, [InternalContainerDiff]>,
|
|
|
|
pub(crate) new_version: Cow<'a, Frontiers>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> InternalDocDiff<'a> {
|
|
|
|
pub fn into_owned(self) -> InternalDocDiff<'static> {
|
|
|
|
InternalDocDiff {
|
|
|
|
origin: self.origin,
|
|
|
|
local: self.local,
|
|
|
|
diff: Cow::Owned((*self.diff).to_owned()),
|
|
|
|
new_version: Cow::Owned((*self.new_version).to_owned()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn can_merge(&self, other: &Self) -> bool {
|
|
|
|
self.origin == other.origin && self.local == other.local
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
2023-10-29 06:02:13 +00:00
|
|
|
use loro_common::LoroValue;
|
|
|
|
|
|
|
|
use crate::{ApplyDiff, LoroDoc};
|
2023-07-31 03:49:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_text_event() {
|
|
|
|
let loro = LoroDoc::new();
|
|
|
|
loro.subscribe_deep(Arc::new(|event| {
|
2023-10-29 06:02:13 +00:00
|
|
|
let mut value = LoroValue::String(Default::default());
|
|
|
|
value.apply_diff(&[event.container.diff.clone()]);
|
|
|
|
assert_eq!(value, "h223ello".into());
|
2023-07-31 03:49:55 +00:00
|
|
|
}));
|
|
|
|
let mut txn = loro.txn().unwrap();
|
|
|
|
let text = loro.get_text("id");
|
|
|
|
text.insert(&mut txn, 0, "hello").unwrap();
|
|
|
|
text.insert(&mut txn, 1, "223").unwrap();
|
|
|
|
txn.commit().unwrap();
|
|
|
|
}
|
2022-12-30 09:50:23 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
pub type Path = SmallVec<[Index; 4]>;
|
2022-11-23 08:26:38 +00:00
|
|
|
|
2022-11-29 10:31:57 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
2022-11-23 08:26:38 +00:00
|
|
|
pub enum Index {
|
|
|
|
Key(InternalString),
|
2022-11-23 10:12:23 +00:00
|
|
|
Seq(usize),
|
2022-11-23 08:26:38 +00:00
|
|
|
}
|
|
|
|
|
2023-10-29 06:02:13 +00:00
|
|
|
impl DiffVariant {
|
|
|
|
pub fn compose(self, other: Self) -> Result<Self, Self> {
|
|
|
|
match (self, other) {
|
|
|
|
(DiffVariant::Internal(a), DiffVariant::Internal(b)) => {
|
|
|
|
Ok(DiffVariant::Internal(a.compose(b)?))
|
|
|
|
}
|
|
|
|
(DiffVariant::External(a), DiffVariant::External(b)) => {
|
|
|
|
Ok(DiffVariant::External(a.compose(b)?))
|
|
|
|
}
|
|
|
|
(a, _) => Err(a),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Diff> for DiffVariant {
|
|
|
|
fn from(diff: Diff) -> Self {
|
|
|
|
DiffVariant::External(diff)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<InternalDiff> for DiffVariant {
|
|
|
|
fn from(diff: InternalDiff) -> Self {
|
|
|
|
DiffVariant::Internal(diff)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[non_exhaustive]
|
|
|
|
#[derive(Clone, Debug, EnumAsInner, Serialize)]
|
|
|
|
pub enum InternalDiff {
|
|
|
|
SeqRaw(Delta<SliceRanges>),
|
|
|
|
/// This always uses entity indexes.
|
|
|
|
RichtextRaw(Delta<RichtextStateChunk>),
|
|
|
|
Map(MapDelta),
|
|
|
|
}
|
|
|
|
|
2023-07-28 05:38:52 +00:00
|
|
|
/// Diff is the diff between two versions of a container.
|
|
|
|
/// It's used to describe the change of a container and the events.
|
|
|
|
///
|
|
|
|
/// # Internal
|
|
|
|
///
|
2023-10-29 06:02:13 +00:00
|
|
|
/// Text index variants:
|
2023-07-28 05:38:52 +00:00
|
|
|
///
|
|
|
|
/// - When `wasm` is enabled, it should use utf16 indexes.
|
2023-10-29 06:02:13 +00:00
|
|
|
/// - When `wasm` is disabled, it should use unicode indexes.
|
|
|
|
#[non_exhaustive]
|
2023-01-11 13:40:16 +00:00
|
|
|
#[derive(Clone, Debug, EnumAsInner, Serialize)]
|
2022-11-23 08:26:38 +00:00
|
|
|
pub enum Diff {
|
2023-03-05 09:38:26 +00:00
|
|
|
List(Delta<Vec<LoroValue>>),
|
2023-10-29 06:02:13 +00:00
|
|
|
/// - When feature `wasm` is enabled, it should use utf16 indexes.
|
|
|
|
/// - When feature `wasm` is disabled, it should use unicode indexes.
|
|
|
|
Text(Delta<StringSlice, StyleMeta>),
|
2023-07-04 06:31:50 +00:00
|
|
|
NewMap(MapDelta),
|
2022-11-23 08:26:38 +00:00
|
|
|
}
|
|
|
|
|
2023-10-29 06:02:13 +00:00
|
|
|
impl InternalDiff {
|
|
|
|
pub(crate) fn compose(self, diff: InternalDiff) -> Result<Self, Self> {
|
|
|
|
// PERF: avoid clone
|
|
|
|
match (self, diff) {
|
|
|
|
(InternalDiff::SeqRaw(a), InternalDiff::SeqRaw(b)) => {
|
|
|
|
Ok(InternalDiff::SeqRaw(a.compose(b)))
|
|
|
|
}
|
|
|
|
(InternalDiff::RichtextRaw(a), InternalDiff::RichtextRaw(b)) => {
|
|
|
|
Ok(InternalDiff::RichtextRaw(a.compose(b)))
|
|
|
|
}
|
|
|
|
(InternalDiff::Map(a), InternalDiff::Map(b)) => Ok(InternalDiff::Map(a.compose(b))),
|
|
|
|
(a, _) => Err(a),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-22 11:02:22 +00:00
|
|
|
impl Diff {
|
|
|
|
pub(crate) fn compose(self, diff: Diff) -> Result<Diff, Self> {
|
|
|
|
// PERF: avoid clone
|
|
|
|
match (self, diff) {
|
|
|
|
(Diff::List(a), Diff::List(b)) => Ok(Diff::List(a.compose(b))),
|
|
|
|
(Diff::Text(a), Diff::Text(b)) => Ok(Diff::Text(a.compose(b))),
|
|
|
|
(Diff::NewMap(a), Diff::NewMap(b)) => Ok(Diff::NewMap(a.compose(b))),
|
|
|
|
(a, _) => Err(a),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|