Skip to content

Commit 9c13538

Browse files
committed
feat: impl crdt types
1 parent da970e5 commit 9c13538

File tree

14 files changed

+443
-74
lines changed

14 files changed

+443
-74
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{
77
pub type Client = u64;
88
pub type Clock = u64;
99

10-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
1111
pub struct Id {
1212
pub client: Client,
1313
pub clock: Clock,

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod refs;
66
mod update;
77

88
pub use any::Any;
9-
pub use content::Content;
9+
pub use content::{Content, YType};
1010
pub use id::{Client, Clock, Id};
1111
pub use item::{Item, Parent};
1212
pub use refs::StructInfo;

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

+41-7
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,37 @@ struct RawRefs {
1313
refs: VecDeque<StructInfo>,
1414
}
1515

16-
#[derive(Debug, Clone, PartialEq)]
16+
#[derive(Debug, Clone)]
1717
pub enum StructInfo {
1818
GC { id: Id, len: u64 },
1919
Skip { id: Id, len: u64 },
2020
Item { id: Id, item: Box<Item> },
2121
}
2222

23+
impl PartialEq for StructInfo {
24+
fn eq(&self, other: &Self) -> bool {
25+
self.id() == other.id()
26+
}
27+
}
28+
29+
impl Eq for StructInfo {
30+
fn assert_receiver_is_total_eq(&self) {}
31+
}
32+
2333
impl StructInfo {
24-
pub fn id(&self) -> &Id {
25-
match self {
34+
pub fn id(&self) -> Id {
35+
*match self {
2636
StructInfo::GC { id, .. } => id,
2737
StructInfo::Skip { id, .. } => id,
2838
StructInfo::Item { id, .. } => id,
2939
}
3040
}
3141

32-
pub fn client_id(&self) -> u64 {
42+
pub fn client(&self) -> Client {
3343
self.id().client
3444
}
3545

36-
pub fn clock(&self) -> u64 {
46+
pub fn clock(&self) -> Clock {
3747
self.id().clock
3848
}
3949

@@ -57,6 +67,14 @@ impl StructInfo {
5767
matches!(self, StructInfo::Item { .. })
5868
}
5969

70+
pub fn item(&self) -> Option<&Item> {
71+
if let Self::Item { item, .. } = self {
72+
Some(item.as_ref())
73+
} else {
74+
None
75+
}
76+
}
77+
6078
pub fn left_id(&self) -> Option<Id> {
6179
if let Self::Item { item, .. } = self {
6280
item.left_id
@@ -73,6 +91,22 @@ impl StructInfo {
7391
}
7492
}
7593

94+
pub fn parent(&self) -> Option<&Parent> {
95+
if let Self::Item { item, .. } = self {
96+
item.parent.as_ref()
97+
} else {
98+
None
99+
}
100+
}
101+
102+
pub fn parent_sub(&self) -> Option<&String> {
103+
if let Self::Item { item, .. } = self {
104+
item.parent_sub.as_ref()
105+
} else {
106+
None
107+
}
108+
}
109+
76110
pub fn split_item(&self, diff: u64) -> JwstCodecResult<(Self, Self)> {
77111
if let Self::Item { id, item } = self {
78112
let right_id = Id::new(id.client, id.clock + diff);
@@ -180,7 +214,7 @@ mod tests {
180214
len: 10,
181215
};
182216
assert_eq!(struct_info.len(), 10);
183-
assert_eq!(struct_info.client_id(), 1);
217+
assert_eq!(struct_info.client(), 1);
184218
assert_eq!(struct_info.clock(), 0);
185219
}
186220

@@ -190,7 +224,7 @@ mod tests {
190224
len: 20,
191225
};
192226
assert_eq!(struct_info.len(), 20);
193-
assert_eq!(struct_info.client_id(), 2);
227+
assert_eq!(struct_info.client(), 2);
194228
assert_eq!(struct_info.clock(), 0);
195229
}
196230
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl<'a> Iterator for UpdateIterator<'a> {
202202
let mut cur = self.next_candidate();
203203

204204
while let Some(cur_update) = cur.take() {
205-
let id = *cur_update.id();
205+
let id = cur_update.id();
206206
if cur_update.is_skip() {
207207
cur = self.next_candidate();
208208
continue;

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

+117-33
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
cell::RefCell,
23
collections::{HashMap, HashSet},
34
ops::{Deref, DerefMut},
45
sync::Arc,
@@ -130,7 +131,8 @@ impl Doc {
130131
offset: u64,
131132
) -> JwstCodecResult<()> {
132133
self.repair(&mut struct_info)?;
133-
match &mut struct_info {
134+
let struct_info = Arc::new(RefCell::new(struct_info));
135+
match struct_info.borrow_mut().deref_mut() {
134136
StructInfo::Item { id, item } => {
135137
let mut left =
136138
item.left_id
@@ -139,17 +141,35 @@ impl Doc {
139141
_ => None,
140142
});
141143

142-
let right =
144+
let mut right =
143145
item.right_id
144146
.and_then(|right_id| match self.store.get_item(right_id) {
145147
Ok(right) => Some(right),
146148
_ => None,
147149
});
148150

149-
let parent = item.parent.as_ref().and_then(|parent| match parent {
150-
Parent::String(_) => todo!(),
151-
Parent::Id(id) => Some(*id),
152-
});
151+
let parent = if let Some(parent) = &item.parent {
152+
match parent {
153+
Parent::String(name) => Some(self.store.get_or_create_type(name)),
154+
Parent::Id(id) => {
155+
if let Some(item) = self.store.get_item(*id)?.borrow().item() {
156+
match &item.content {
157+
Content::Type(ytype) => {
158+
Some(Arc::new(RefCell::new(ytype.clone().into())))
159+
}
160+
Content::Deleted(_) => None,
161+
_ => {
162+
return Err(JwstCodecError::InvalidParent);
163+
}
164+
}
165+
} else {
166+
None
167+
}
168+
}
169+
}
170+
} else {
171+
None
172+
};
153173

154174
if offset > 0 {
155175
id.clock += offset;
@@ -160,7 +180,8 @@ impl Doc {
160180
item.content.split(offset)?;
161181
}
162182

163-
if let Some(_parent_id) = parent {
183+
if let Some(parent) = parent {
184+
let mut parent = parent.borrow_mut();
164185
let right_is_null_or_has_left = match &right {
165186
None => true,
166187
Some(right) => right.left_id().is_some(),
@@ -176,35 +197,37 @@ impl Doc {
176197
{
177198
// set the first conflicting item
178199
let mut o = if let Some(left) = left.clone() {
179-
left.right_id()
180-
} else if let Some(_sub) = &item.parent_sub {
181-
// TODO: handle parent_sub, set if parent is Map or Array
182-
unimplemented!()
200+
Some(left)
201+
} else if let Some(parent_sub) = &item.parent_sub {
202+
let o = parent.map.get(parent_sub).cloned();
203+
if let Some(o) = o.as_ref() {
204+
Some(self.store.get_start_item(o.clone()))
205+
} else {
206+
None
207+
}
183208
} else {
184-
// TODO: handle parent w/o sub, occurs if parent is Text
185-
unimplemented!()
209+
parent.start.clone()
186210
};
187211

188212
let mut conflicting_items = HashSet::new();
189213
let mut items_before_origin = HashSet::new();
190214

191-
while let Some(conflict_id) = o {
192-
match right {
193-
Some(right) if right.id() == &conflict_id => {
194-
break;
195-
}
196-
_ => {}
197-
};
198-
199-
items_before_origin.insert(conflict_id);
200-
conflicting_items.insert(conflict_id);
201-
let conflict_item = self.store.get_item(conflict_id)?;
202-
match conflict_item.as_ref() {
203-
StructInfo::Item { item: c, .. } => {
215+
while let Some(conflict) = o {
216+
if Some(conflict.clone()) == right {
217+
break;
218+
}
219+
220+
items_before_origin.insert(conflict.id());
221+
conflicting_items.insert(conflict.id());
222+
match conflict.borrow().deref() {
223+
StructInfo::Item {
224+
id: conflict_id,
225+
item: c,
226+
} => {
204227
if item.left_id == c.left_id {
205228
// case 1
206229
if conflict_id.client < id.client {
207-
left = Some(Arc::clone(&conflict_item));
230+
left = Some(conflict.clone());
208231
conflicting_items.clear();
209232
} else if item.right_id == c.right_id {
210233
// `this` and `c` are conflicting and point to the same
@@ -216,20 +239,66 @@ impl Doc {
216239
if items_before_origin.contains(&conflict_item_left)
217240
&& !conflicting_items.contains(&conflict_item_left)
218241
{
219-
left = Some(Arc::clone(&conflict_item));
242+
left = Some(conflict.clone());
220243
conflicting_items.clear();
221244
}
222245
} else {
223246
break;
224247
}
225-
o = conflict_item.right_id();
248+
o = match c.right_id {
249+
Some(right_id) => Some(self.store.get_item(right_id)?),
250+
None => None,
251+
};
226252
}
227253
_ => {
228254
break;
229255
}
230256
}
231257
}
232-
item.left_id = left.map(|item| *item.id())
258+
259+
// reconnect left/right
260+
match left {
261+
// has left, connect left <-> self <-> left.right
262+
Some(left) => {
263+
item.left_id = Some(left.id());
264+
left.modify(|left| {
265+
if let StructInfo::Item { item: left, .. } = left {
266+
left.right_id = left.right_id.replace(*id);
267+
}
268+
});
269+
}
270+
// no left, right = parent.start
271+
None => {
272+
right = if let Some(parent_sub) = &item.parent_sub {
273+
if let Some(r) = parent.map.get(parent_sub).cloned() {
274+
Some(self.store.get_start_item(r))
275+
} else {
276+
None
277+
}
278+
} else {
279+
parent.start.clone()
280+
};
281+
}
282+
}
283+
284+
match right {
285+
// has right, connect
286+
Some(right) => right.modify(|right| {
287+
if let StructInfo::Item { item: right, .. } = right {
288+
right.left_id = right.left_id.replace(*id);
289+
}
290+
item.right_id = Some(right.id());
291+
}),
292+
// no right, parent.start = item, delete item.left
293+
None => {
294+
if let Some(parent_sub) = &item.parent_sub {
295+
parent
296+
.map
297+
.insert(parent_sub.to_string(), struct_info.clone().into());
298+
}
299+
// left.delete();
300+
}
301+
}
233302
}
234303
}
235304
}
@@ -243,19 +312,34 @@ impl Doc {
243312
// skip ignored
244313
}
245314
}
246-
self.store.add_item(struct_info)
315+
self.store.add_item_ref(struct_info.into())
247316
}
248317

249318
fn repair(&mut self, info: &mut StructInfo) -> JwstCodecResult {
250319
if let StructInfo::Item { item, .. } = info {
251320
if let Some(left_id) = item.left_id {
252321
let left = self.store.get_item_clean_end(left_id)?;
253-
item.left_id = Some(*left.id());
322+
item.left_id = Some(left.id());
254323
}
255324

256325
if let Some(right_id) = item.right_id {
257326
let right = self.store.get_item_clean_start(right_id)?;
258-
item.right_id = Some(*right.id());
327+
item.right_id = Some(right.id());
328+
}
329+
330+
if let Some(parent) = item.parent.take() {
331+
match parent {
332+
Parent::String(str) => {
333+
self.store.get_or_create_type(&str);
334+
}
335+
Parent::Id(parent_id) => {
336+
let parent = self.store.get_item(parent_id)?;
337+
if !parent.is_item() {
338+
item.parent = None
339+
}
340+
}
341+
}
342+
} else {
259343
}
260344
}
261345

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
mod codec;
22
mod document;
33
mod store;
4-
mod traits;
4+
mod types;
55

66
use super::*;
77

88
pub use codec::*;
99
pub use document::{Doc, StateVector};
10-
pub use store::DocStore;
11-
pub use traits::{CrdtList, CrdtMap};
10+
pub use store::{DocStore, StructRef};
11+
pub use types::*;

0 commit comments

Comments
 (0)