Skip to content

Commit a5278dd

Browse files
committed
feat: impl crdt types
1 parent 7799148 commit a5278dd

20 files changed

+1392
-270
lines changed

libs/jwst-codec/src/doc/codec/content.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -171,15 +171,18 @@ impl Content {
171171
}
172172
}
173173

174-
pub fn split(&self, diff: u64) -> JwstCodecResult<(Self, Self)> {
174+
pub fn countable(&self) -> bool {
175+
!matches!(self, Content::Format { .. } | Content::Deleted(_))
176+
}
177+
178+
pub fn split(&mut self, diff: u64) -> JwstCodecResult<Self> {
175179
// TODO: implement split for other types
176180
match self {
177181
Self::String(str) => {
178182
let (left, right) = str.split_at(diff as usize);
179-
Ok((
180-
Self::String(left.to_string()),
181-
Self::String(right.to_string()),
182-
))
183+
let right = right.to_string();
184+
*str = left.to_string();
185+
Ok(Self::String(right))
183186
}
184187
_ => Err(JwstCodecError::ContentSplitNotSupport(diff)),
185188
}

libs/jwst-codec/src/doc/codec/delete.rs

-33
This file was deleted.
+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use crate::doc::common::OrderRange;
2+
3+
use super::*;
4+
use std::{
5+
collections::{hash_map::Entry, HashMap},
6+
ops::{Deref, DerefMut, Range},
7+
};
8+
9+
impl<R: CrdtReader> CrdtRead<R> for Range<u64> {
10+
fn read(decoder: &mut R) -> JwstCodecResult<Self> {
11+
let clock = decoder.read_var_u64()?;
12+
let len = decoder.read_var_u64()?;
13+
Ok(clock..clock + len)
14+
}
15+
}
16+
17+
impl<R: CrdtReader> CrdtRead<R> for OrderRange {
18+
fn read(decoder: &mut R) -> JwstCodecResult<Self> {
19+
let num_of_deletes = decoder.read_var_u64()? as usize;
20+
let mut deletes = Vec::with_capacity(num_of_deletes);
21+
22+
for _ in 0..num_of_deletes {
23+
deletes.push(Range::<u64>::read(decoder)?);
24+
}
25+
26+
Ok(OrderRange::Fragment(deletes))
27+
}
28+
}
29+
30+
impl<R: CrdtReader> CrdtRead<R> for DeleteSet {
31+
fn read(decoder: &mut R) -> JwstCodecResult<Self> {
32+
let num_of_clients = decoder.read_var_u64()? as usize;
33+
let mut map = HashMap::with_capacity(num_of_clients);
34+
35+
for _ in 0..num_of_clients {
36+
let client = decoder.read_var_u64()?;
37+
let deletes = OrderRange::read(decoder)?;
38+
map.insert(client, deletes);
39+
}
40+
41+
Ok(DeleteSet(map))
42+
}
43+
}
44+
45+
#[derive(Debug, Default)]
46+
pub struct DeleteSet(pub HashMap<Client, OrderRange>);
47+
48+
impl Deref for DeleteSet {
49+
type Target = HashMap<Client, OrderRange>;
50+
51+
fn deref(&self) -> &Self::Target {
52+
&self.0
53+
}
54+
}
55+
56+
impl DerefMut for DeleteSet {
57+
fn deref_mut(&mut self) -> &mut Self::Target {
58+
&mut self.0
59+
}
60+
}
61+
62+
impl DeleteSet {
63+
pub fn add(&mut self, client: Client, from: Clock, len: Clock) {
64+
self.add_range(client, from..from + len);
65+
}
66+
67+
pub fn add_range(&mut self, client: Client, range: Range<u64>) {
68+
match self.0.entry(client) {
69+
Entry::Occupied(e) => {
70+
let r = e.into_mut();
71+
if r.is_empty() {
72+
*r = range.into();
73+
} else {
74+
r.push(range);
75+
}
76+
}
77+
Entry::Vacant(e) => {
78+
e.insert(range.into());
79+
}
80+
}
81+
}
82+
83+
pub fn batch_push(&mut self, client: Client, ranges: Vec<Range<u64>>) {
84+
match self.0.entry(client) {
85+
Entry::Occupied(e) => {
86+
e.into_mut().extends(ranges);
87+
}
88+
Entry::Vacant(e) => {
89+
e.insert(ranges.into());
90+
}
91+
}
92+
}
93+
94+
pub fn merge(&mut self, other: Self) {
95+
for (client, range) in other.0 {
96+
match self.0.entry(client) {
97+
Entry::Occupied(e) => {
98+
e.into_mut().merge(range);
99+
}
100+
Entry::Vacant(e) => {
101+
e.insert(range);
102+
}
103+
}
104+
}
105+
}
106+
}

libs/jwst-codec/src/doc/codec/id.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use std::{
2+
cmp::Ordering,
23
hash::Hash,
34
ops::{Add, Sub},
45
};
56

67
pub type Client = u64;
78
pub type Clock = u64;
89

9-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
1011
pub struct Id {
1112
pub client: Client,
1213
pub clock: Clock,
@@ -39,3 +40,18 @@ impl Add<Clock> for Id {
3940
(self.client, self.clock + rhs).into()
4041
}
4142
}
43+
44+
impl PartialOrd for Id {
45+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
46+
match self.client.cmp(&other.client) {
47+
Ordering::Equal => Some(self.clock.cmp(&other.clock)),
48+
_ => None,
49+
}
50+
}
51+
}
52+
53+
impl Ord for Id {
54+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
55+
self.clock.cmp(&other.clock)
56+
}
57+
}

libs/jwst-codec/src/doc/codec/item.rs

+141-12
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,139 @@ pub enum Parent {
66
Id(Id),
77
}
88

9+
#[rustfmt::skip]
10+
#[allow(dead_code)]
11+
pub mod item_flags {
12+
pub const ITEM_KEEP : u8 = 0b0000_0001;
13+
pub const ITEM_COUNTABLE : u8 = 0b0000_0010;
14+
pub const ITEM_DELETED : u8 = 0b0000_0100;
15+
pub const ITEM_MARKED : u8 = 0b0000_1000;
16+
pub const ITEM_HAS_PARENT_SUB : u8 = 0b0010_0000;
17+
pub const ITEM_HAS_RIGHT_ID : u8 = 0b0100_0000;
18+
pub const ITEM_HAS_LEFT_ID : u8 = 0b1000_0000;
19+
}
20+
21+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
22+
pub struct ItemFlags(u8);
23+
24+
impl From<u8> for ItemFlags {
25+
fn from(flags: u8) -> Self {
26+
Self(flags)
27+
}
28+
}
29+
30+
impl ItemFlags {
31+
#[inline(always)]
32+
pub fn set(&mut self, flag: u8) {
33+
self.0 |= flag;
34+
}
35+
36+
#[inline(always)]
37+
pub fn clear(&mut self, flag: u8) {
38+
self.0 &= !flag;
39+
}
40+
41+
#[inline(always)]
42+
pub fn check(&self, flag: u8) -> bool {
43+
self.0 & flag == flag
44+
}
45+
46+
#[inline(always)]
47+
pub fn not(&self, flag: u8) -> bool {
48+
self.0 & flag == 0
49+
}
50+
51+
#[inline(always)]
52+
pub fn keep(&self) -> bool {
53+
self.check(item_flags::ITEM_KEEP)
54+
}
55+
56+
#[inline(always)]
57+
pub fn set_keep(&mut self) {
58+
self.set(item_flags::ITEM_KEEP);
59+
}
60+
61+
#[inline(always)]
62+
pub fn clear_keep(&mut self) {
63+
self.clear(item_flags::ITEM_KEEP);
64+
}
65+
66+
#[inline(always)]
67+
pub fn countable(&self) -> bool {
68+
self.check(item_flags::ITEM_COUNTABLE)
69+
}
70+
71+
#[inline(always)]
72+
pub fn set_countable(&mut self) {
73+
self.set(item_flags::ITEM_COUNTABLE);
74+
}
75+
76+
#[inline(always)]
77+
pub fn clear_countable(&mut self) {
78+
self.clear(item_flags::ITEM_COUNTABLE);
79+
}
80+
81+
#[inline(always)]
82+
pub fn deleted(&self) -> bool {
83+
self.check(item_flags::ITEM_DELETED)
84+
}
85+
86+
#[inline(always)]
87+
pub fn set_deleted(&mut self) {
88+
self.set(item_flags::ITEM_DELETED);
89+
}
90+
91+
#[inline(always)]
92+
pub fn clear_deleted(&mut self) {
93+
self.clear(item_flags::ITEM_DELETED);
94+
}
95+
}
96+
997
#[derive(Debug, Clone, PartialEq)]
1098
pub struct Item {
1199
pub left_id: Option<Id>,
12100
pub right_id: Option<Id>,
13101
pub parent: Option<Parent>,
14102
pub parent_sub: Option<String>,
15103
pub content: Content,
104+
pub flags: ItemFlags,
105+
}
106+
107+
impl Default for Item {
108+
fn default() -> Self {
109+
Self {
110+
left_id: None,
111+
right_id: None,
112+
parent: None,
113+
parent_sub: None,
114+
content: Content::String("".into()),
115+
flags: ItemFlags::from(item_flags::ITEM_COUNTABLE),
116+
}
117+
}
118+
}
119+
120+
impl Item {
121+
pub fn is_empty(&self) -> bool {
122+
self.len() == 0
123+
}
124+
125+
pub fn len(&self) -> u64 {
126+
self.content.clock_len()
127+
}
128+
129+
pub fn deleted(&self) -> bool {
130+
self.flags.deleted()
131+
}
132+
133+
pub fn delete(&mut self) {
134+
if self.deleted() {
135+
return;
136+
}
137+
138+
// self.content.delete();
139+
140+
self.flags.deleted();
141+
}
16142
}
17143

18144
impl Item {
@@ -21,14 +147,15 @@ impl Item {
21147
info: u8,
22148
first_5_bit: u8,
23149
) -> JwstCodecResult<Self> {
24-
let has_left_id = info & 0b1000_0000 == 0b1000_0000;
25-
let has_right_id = info & 0b0100_0000 == 0b0100_0000;
26-
let has_parent_sub = info & 0b0010_0000 == 0b0010_0000;
27-
let has_not_parent_info = info & 0b1100_0000 == 0;
150+
let flags: ItemFlags = info.into();
151+
let has_left_id = flags.check(item_flags::ITEM_HAS_LEFT_ID);
152+
let has_right_id = flags.check(item_flags::ITEM_HAS_RIGHT_ID);
153+
let has_parent_sub = flags.check(item_flags::ITEM_HAS_PARENT_SUB);
154+
let has_not_parent_info = !(has_left_id || has_right_id);
28155

29156
// NOTE: read order must keep the same as the order in yjs
30157
// TODO: this data structure design will break the cpu OOE, need to be optimized
31-
let item = Self {
158+
let mut item = Self {
32159
left_id: if has_left_id {
33160
Some(decoder.read_item_id()?)
34161
} else {
@@ -62,8 +189,13 @@ impl Item {
62189
debug_assert_ne!(first_5_bit, 10);
63190
Content::read(decoder, first_5_bit)?
64191
},
192+
flags: ItemFlags::from(0),
65193
};
66194

195+
if item.content.countable() {
196+
item.flags.set_countable();
197+
}
198+
67199
Ok(item)
68200
}
69201

@@ -72,16 +204,13 @@ impl Item {
72204
// write info
73205
let mut info = self.content.get_info();
74206
if self.left_id.is_some() {
75-
info |= 0b1000_0000;
207+
info |= item_flags::ITEM_HAS_LEFT_ID;
76208
}
77209
if self.right_id.is_some() {
78-
info |= 0b0100_0000;
79-
}
80-
if self.parent.is_some() || self.parent_sub.is_some() {
81-
info |= 0b0010_0000;
210+
info |= item_flags::ITEM_HAS_RIGHT_ID;
82211
}
83-
if self.parent.is_none() && self.parent_sub.is_none() {
84-
info |= 0b0001_0000;
212+
if self.parent_sub.is_some() {
213+
info |= item_flags::ITEM_HAS_PARENT_SUB;
85214
}
86215
encoder.write_info(info)?;
87216
}

0 commit comments

Comments
 (0)