mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-22 21:07:43 +00:00
refactor: undo redo use counter span
undo & redo should be a local only operation
This commit is contained in:
parent
b616f39273
commit
0d13c9562c
7 changed files with 94 additions and 37 deletions
0
crates/loro-core/src/dag.rs
Normal file
0
crates/loro-core/src/dag.rs
Normal file
|
@ -6,16 +6,17 @@
|
|||
pub mod change;
|
||||
pub mod configure;
|
||||
pub mod container;
|
||||
pub mod dag;
|
||||
pub mod id;
|
||||
pub mod op;
|
||||
pub mod version;
|
||||
|
||||
mod error;
|
||||
mod id_span;
|
||||
mod log_store;
|
||||
mod loro;
|
||||
mod smstring;
|
||||
mod snapshot;
|
||||
mod span;
|
||||
mod tests;
|
||||
mod value;
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ use crate::{
|
|||
configure::Configure,
|
||||
container::{Container, ContainerID, ContainerManager},
|
||||
id::{ClientID, Counter},
|
||||
id_span::IdSpan,
|
||||
op::OpProxy,
|
||||
span::IdSpan,
|
||||
version::TotalOrderStamp,
|
||||
Lamport, Op, Timestamp, ID,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use crate::{container::ContainerID, id::ID, id_span::IdSpan};
|
||||
use crate::{
|
||||
container::ContainerID,
|
||||
id::ID,
|
||||
span::{CounterSpan, IdSpan},
|
||||
};
|
||||
use rle::{HasLength, Mergable, RleVec, Sliceable};
|
||||
mod insert_content;
|
||||
mod op_content;
|
||||
|
@ -47,7 +51,7 @@ impl Op {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_delete_op(id: ID, container: ContainerID, target: RleVec<IdSpan>) -> Self {
|
||||
pub fn new_delete_op(id: ID, container: ContainerID, target: RleVec<CounterSpan>) -> Self {
|
||||
Op::new(id, OpContent::Undo { target }, container)
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ pub trait InsertContent:
|
|||
HasLength + std::fmt::Debug + Any + MergeableContent + SliceableContent + CloneContent
|
||||
{
|
||||
fn id(&self) -> ContentType;
|
||||
// TODO: provide an encoding method
|
||||
}
|
||||
|
||||
impl<T: Sliceable + InsertContent> SliceableContent for T {
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
use rle::{HasLength, Mergable, RleVec, Sliceable};
|
||||
|
||||
use crate::{container::ContainerID, id::ID, id_span::IdSpan, OpType};
|
||||
use crate::{
|
||||
container::ContainerID,
|
||||
id::ID,
|
||||
span::{CounterSpan, IdSpan},
|
||||
OpType,
|
||||
};
|
||||
|
||||
use super::{InsertContent, MergeableContent};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OpContent {
|
||||
Normal { content: Box<dyn InsertContent> },
|
||||
Undo { target: RleVec<IdSpan> },
|
||||
Redo { target: RleVec<IdSpan> },
|
||||
Undo { target: RleVec<CounterSpan> },
|
||||
Redo { target: RleVec<CounterSpan> },
|
||||
}
|
||||
|
||||
impl OpContent {
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
use crate::id::{ClientID, ID};
|
||||
use crate::id::{ClientID, Counter, ID};
|
||||
use rle::{HasLength, Mergable, Slice, Sliceable};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct IdSpan {
|
||||
pub client_id: ClientID,
|
||||
pub from: usize,
|
||||
pub to: usize,
|
||||
pub struct CounterSpan {
|
||||
pub from: Counter,
|
||||
pub to: Counter,
|
||||
}
|
||||
|
||||
impl IdSpan {
|
||||
impl CounterSpan {
|
||||
#[inline]
|
||||
pub fn min(&self) -> usize {
|
||||
pub fn new(from: Counter, to: Counter) -> Self {
|
||||
CounterSpan { from, to }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn min(&self) -> Counter {
|
||||
if self.from < self.to {
|
||||
self.from
|
||||
} else {
|
||||
|
@ -19,7 +23,7 @@ impl IdSpan {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max(&self) -> usize {
|
||||
pub fn max(&self) -> Counter {
|
||||
if self.from > self.to {
|
||||
self.from
|
||||
} else {
|
||||
|
@ -28,44 +32,90 @@ impl IdSpan {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasLength for IdSpan {
|
||||
impl HasLength for CounterSpan {
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
if self.to > self.from {
|
||||
self.to - self.from
|
||||
(self.to - self.from) as usize
|
||||
} else {
|
||||
self.from - self.to
|
||||
(self.from - self.to) as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sliceable for IdSpan {
|
||||
impl Sliceable for CounterSpan {
|
||||
fn slice(&self, from: usize, to: usize) -> Self {
|
||||
assert!(from <= to);
|
||||
let len = to - from;
|
||||
assert!(len <= self.len());
|
||||
if self.from < self.to {
|
||||
IdSpan {
|
||||
client_id: self.client_id,
|
||||
from: self.from + from,
|
||||
to: self.from + to,
|
||||
CounterSpan {
|
||||
from: self.from + from as Counter,
|
||||
to: self.from + to as Counter,
|
||||
}
|
||||
} else {
|
||||
IdSpan {
|
||||
client_id: self.client_id,
|
||||
from: self.from - from,
|
||||
to: self.from - to,
|
||||
CounterSpan {
|
||||
from: self.from - from as Counter,
|
||||
to: self.from - to as Counter,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mergable for CounterSpan {
|
||||
#[inline]
|
||||
fn is_mergable(&self, other: &Self, _: &()) -> bool {
|
||||
self.to == other.from
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn merge(&mut self, other: &Self, _: &()) {
|
||||
self.to = other.to;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct IdSpan {
|
||||
pub client_id: ClientID,
|
||||
pub counter: CounterSpan,
|
||||
}
|
||||
|
||||
impl IdSpan {
|
||||
#[inline]
|
||||
pub fn min(&self) -> Counter {
|
||||
self.counter.min()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max(&self) -> Counter {
|
||||
self.counter.max()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasLength for IdSpan {
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
self.counter.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Sliceable for IdSpan {
|
||||
#[inline]
|
||||
fn slice(&self, from: usize, to: usize) -> Self {
|
||||
IdSpan {
|
||||
client_id: self.client_id,
|
||||
counter: self.counter.slice(from, to),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mergable for IdSpan {
|
||||
fn is_mergable(&self, other: &Self, _: &()) -> bool {
|
||||
self.client_id == other.client_id && self.to == other.from
|
||||
self.client_id == other.client_id && self.counter.is_mergable(&other.counter, &())
|
||||
}
|
||||
|
||||
fn merge(&mut self, other: &Self, _: &()) {
|
||||
self.to = other.to;
|
||||
self.counter.merge(&other.counter, &())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,8 +132,7 @@ mod test_id_span {
|
|||
$(
|
||||
id_spans.push(IdSpan {
|
||||
client_id: $client_id,
|
||||
from: $from,
|
||||
to: $to,
|
||||
counter: CounterSpan::new($from, $to),
|
||||
});
|
||||
)*
|
||||
id_spans
|
||||
|
@ -96,22 +145,19 @@ mod test_id_span {
|
|||
let mut id_span_vec = RleVec::new();
|
||||
id_span_vec.push(IdSpan {
|
||||
client_id: 0,
|
||||
from: 0,
|
||||
to: 2,
|
||||
counter: CounterSpan::new(0, 2),
|
||||
});
|
||||
assert_eq!(id_span_vec.merged_len(), 1);
|
||||
assert_eq!(id_span_vec.len(), 2);
|
||||
id_span_vec.push(IdSpan {
|
||||
client_id: 0,
|
||||
from: 2,
|
||||
to: 4,
|
||||
counter: CounterSpan::new(2, 4),
|
||||
});
|
||||
assert_eq!(id_span_vec.merged_len(), 1);
|
||||
assert_eq!(id_span_vec.len(), 4);
|
||||
id_span_vec.push(IdSpan {
|
||||
client_id: 2,
|
||||
from: 2,
|
||||
to: 4,
|
||||
counter: CounterSpan::new(2, 4),
|
||||
});
|
||||
assert_eq!(id_span_vec.merged_len(), 2);
|
||||
assert_eq!(id_span_vec.len(), 6);
|
Loading…
Reference in a new issue