1use super::{
2 outdated_encode_reordered::{import_changes_to_oplog, ImportChangesResult, ValueRegister},
3 ImportStatus,
4};
5use crate::{
6 arena::SharedArena,
7 change::{Change, ChangeRef},
8 container::{
9 list::list_op::{DeleteSpan, DeleteSpanWithId, InnerListOp},
10 map::MapSet,
11 richtext::TextStyleInfoFlag,
12 tree::tree_op::TreeOp,
13 },
14 op::{FutureInnerContent, InnerContent, Op, SliceRange},
15 oplog::BlockChangeRef,
16 version::{Frontiers, VersionRange},
17 OpLog, VersionVector,
18};
19use either::Either;
20use itertools::Itertools;
21use json::{JsonChange, JsonOpContent, JsonSchema};
22use loro_common::{
23 ContainerID, ContainerType, HasCounterSpan, HasId, HasIdSpan, IdLp, IdSpan, LoroError,
24 LoroResult, LoroValue, PeerID, TreeID, ID,
25};
26use rle::{HasLength, RleVec, Sliceable};
27use std::sync::Arc;
28
29const SCHEMA_VERSION: u8 = 1;
30
31fn refine_vv(vv: &VersionVector, oplog: &OpLog) -> VersionVector {
32 let mut refined = VersionVector::new();
33 for (&peer, &counter) in vv.iter() {
34 if counter == 0 {
35 continue;
36 }
37 let end = oplog.vv().get(&peer).copied().unwrap_or(0);
38 if end <= counter {
39 refined.insert(peer, end);
40 } else {
41 refined.insert(peer, counter);
42 }
43 }
44 refined
45}
46
47pub(crate) fn export_json<'a, 'c: 'a>(
48 oplog: &'c OpLog,
49 start_vv: &VersionVector,
50 end_vv: &VersionVector,
51 with_peer_compression: bool,
52) -> JsonSchema {
53 let actual_start_vv = refine_vv(start_vv, oplog);
54 let actual_end_vv = refine_vv(end_vv, oplog);
55
56 let frontiers = oplog.dag.vv_to_frontiers(&actual_start_vv);
57
58 let diff_changes = init_encode(oplog, &actual_start_vv, &actual_end_vv);
59 if with_peer_compression {
60 let mut peer_register = ValueRegister::<PeerID>::new();
61 let changes = encode_changes(&diff_changes, &oplog.arena, Some(&mut peer_register));
62 JsonSchema {
63 changes,
64 schema_version: SCHEMA_VERSION,
65 peers: Some(peer_register.unwrap_vec()),
66 start_version: frontiers,
67 }
68 } else {
69 let changes = encode_changes(&diff_changes, &oplog.arena, None);
70 JsonSchema {
71 changes,
72 schema_version: SCHEMA_VERSION,
73 peers: None,
74 start_version: frontiers,
75 }
76 }
77}
78
79pub(crate) fn export_json_in_id_span(oplog: &OpLog, mut id_span: IdSpan) -> Vec<json::JsonChange> {
80 id_span.normalize_();
81 let end = oplog.vv().get(&id_span.peer).copied().unwrap_or(0);
82 if id_span.counter.start >= end {
83 return vec![];
84 }
85
86 id_span.counter.end = id_span.counter.end.min(end);
87 let mut diff_changes: Vec<Either<BlockChangeRef, Change>> = Vec::new();
88 while id_span.counter.end - id_span.counter.start > 0 {
89 let Some(change) = oplog.get_change_at(id_span.id_start()) else {
90 break;
91 };
92 let ctr_end = change.ctr_end();
93 if change.id.counter >= id_span.counter.start && change.ctr_end() <= id_span.counter.end {
94 diff_changes.push(Either::Left(change));
95 } else {
96 let start = if change.id.counter < id_span.counter.start {
97 (id_span.counter.start - change.id.counter) as usize
98 } else {
99 0
100 };
101
102 let end = if change.ctr_end() > id_span.counter.end {
103 (id_span.counter.end - change.id.counter) as usize
104 } else {
105 change.atom_len()
106 };
107
108 diff_changes.push(Either::Right(change.slice(start, end)));
109 }
110
111 id_span.counter.start = ctr_end;
112 }
113
114 encode_changes(&diff_changes, &oplog.arena, None)
115}
116
117pub(crate) fn import_json(oplog: &mut OpLog, json: JsonSchema) -> LoroResult<ImportStatus> {
118 let changes = decode_changes(json, &oplog.arena)?;
119 let ImportChangesResult {
120 latest_ids,
121 pending_changes,
122 changes_that_have_deps_before_shallow_root,
123 mut imported,
124 } = import_changes_to_oplog(changes, oplog);
125 let mut pending = VersionRange::default();
126 pending_changes.iter().for_each(|c| {
127 pending.extends_to_include_id_span(c.id_span());
128 });
129 oplog.try_apply_pending(latest_ids, Some(&mut imported));
130 oplog.import_unknown_lamport_pending_changes(pending_changes)?;
131 if !changes_that_have_deps_before_shallow_root.is_empty() {
132 return Err(LoroError::ImportUpdatesThatDependsOnOutdatedVersion);
133 };
134 Ok(ImportStatus {
135 success: imported,
136 pending: if pending.is_empty() {
137 None
138 } else {
139 Some(pending)
140 },
141 })
142}
143
144fn init_encode<'s, 'a: 's>(
145 oplog: &'a OpLog,
146 start_vv: &VersionVector,
147 end_vv: &VersionVector,
148) -> Vec<Either<BlockChangeRef, Change>> {
149 let mut diff_changes: Vec<Either<BlockChangeRef, Change>> = Vec::new();
150 for change in oplog.iter_changes_peer_by_peer(start_vv, end_vv) {
151 let start_cnt = start_vv.get(&change.id.peer).copied().unwrap_or(0);
152 let end_cnt = end_vv.get(&change.id.peer).copied().unwrap_or(0);
153 if change.id.counter < start_cnt {
154 if change.ctr_end() <= start_cnt {
155 continue;
156 }
157
158 let offset = start_cnt - change.id.counter;
159 let to = change
160 .atom_len()
161 .min((end_cnt - change.id.counter) as usize);
162 diff_changes.push(Either::Right(change.slice(offset as usize, to)));
163 } else if change.id.counter + change.atom_len() as i32 > end_cnt {
164 let len = end_cnt - change.id.counter;
165 diff_changes.push(Either::Right(change.slice(0, len as usize)));
166 } else {
167 diff_changes.push(Either::Left(change));
168 }
169 }
170 diff_changes.sort_by_key(|x| match x {
171 Either::Left(c) => c.lamport,
172 Either::Right(c) => c.lamport,
173 });
174 diff_changes
175}
176
177fn register_id(id: &ID, peer_register: Option<&mut ValueRegister<PeerID>>) -> ID {
178 let peer = match peer_register {
179 Some(peer_register) => peer_register.register(&id.peer) as PeerID,
180 None => id.peer,
181 };
182 ID::new(peer as PeerID, id.counter)
183}
184
185fn register_idlp(idlp: &IdLp, peer_register: Option<&mut ValueRegister<PeerID>>) -> IdLp {
186 let peer = match peer_register {
187 Some(peer_register) => peer_register.register(&idlp.peer) as PeerID,
188 None => idlp.peer,
189 };
190 IdLp {
191 peer,
192 lamport: idlp.lamport,
193 }
194}
195
196fn register_tree_id(tree: &TreeID, peer_register: Option<&mut ValueRegister<PeerID>>) -> TreeID {
197 TreeID {
198 peer: match peer_register {
199 Some(peer_register) => peer_register.register(&tree.peer) as PeerID,
200 None => tree.peer,
201 },
202 counter: tree.counter,
203 }
204}
205
206fn register_container_id(
207 container: ContainerID,
208 peer_register: Option<&mut ValueRegister<PeerID>>,
209) -> ContainerID {
210 match container {
211 ContainerID::Normal {
212 peer,
213 counter,
214 container_type,
215 } => ContainerID::Normal {
216 peer: match peer_register {
217 Some(peer_register) => peer_register.register(&peer) as PeerID,
218 None => peer,
219 },
220 counter,
221 container_type,
222 },
223 r => r,
224 }
225}
226
227fn convert_container_id(container: ContainerID, peers: &Option<Vec<PeerID>>) -> ContainerID {
228 match container {
229 ContainerID::Normal {
230 peer,
231 counter,
232 container_type,
233 } => ContainerID::Normal {
234 peer: get_peer_from_peers(peers, peer),
235 counter,
236 container_type,
237 },
238 r => r,
239 }
240}
241
242pub(crate) fn get_peer_from_peers(peers: &Option<Vec<PeerID>>, peer: PeerID) -> PeerID {
243 match peers {
244 Some(peers) => peers[peer as usize],
245 None => peer,
246 }
247}
248
249fn convert_id(id: &ID, peers: &Option<Vec<PeerID>>) -> ID {
250 ID {
251 peer: get_peer_from_peers(peers, id.peer),
252 counter: id.counter,
253 }
254}
255
256fn convert_idlp(idlp: &IdLp, peers: &Option<Vec<PeerID>>) -> IdLp {
257 IdLp {
258 lamport: idlp.lamport,
259 peer: get_peer_from_peers(peers, idlp.peer),
260 }
261}
262
263fn convert_tree_id(tree: &TreeID, peers: &Option<Vec<PeerID>>) -> TreeID {
264 TreeID {
265 peer: get_peer_from_peers(peers, tree.peer),
266 counter: tree.counter,
267 }
268}
269pub(crate) fn encode_change_to_json(change: ChangeRef<'_>, arena: &SharedArena) -> JsonSchema {
270 let f = change.deps.clone();
271 let changes = vec![encode_change(change, arena, None)];
272 JsonSchema {
273 changes,
274 schema_version: SCHEMA_VERSION,
275 peers: None,
276 start_version: f,
277 }
278}
279
280fn encode_changes(
281 diff_changes: &[Either<BlockChangeRef, Change>],
282 arena: &SharedArena,
283 mut peer_register: Option<&mut ValueRegister<PeerID>>,
284) -> Vec<json::JsonChange> {
285 let mut changes = Vec::with_capacity(diff_changes.len());
286 for change in diff_changes.iter() {
287 let change: &Change = match change {
288 Either::Left(c) => c,
289 Either::Right(c) => c,
290 };
291 let c = encode_change(
292 ChangeRef::from_change(change),
293 arena,
294 peer_register.as_deref_mut(),
295 );
296 changes.push(c);
297 }
298 changes
299}
300
301pub(crate) fn encode_change(
302 change: ChangeRef<'_, Op>,
303 arena: &SharedArena,
304 mut peer_register: Option<&mut ValueRegister<PeerID>>,
305) -> JsonChange {
306 let mut ops = Vec::with_capacity(change.ops.len());
307 for Op {
308 counter,
309 container,
310 content,
311 } in change.ops.iter()
312 {
313 let mut container = arena.get_container_id(*container).unwrap();
314 if container.is_normal() {
315 container = register_container_id(container, peer_register.as_deref_mut());
316 }
317 let op = match container.container_type() {
318 ContainerType::List => match content {
319 InnerContent::List(list) => JsonOpContent::List(match list {
320 InnerListOp::Insert { slice, pos } => {
321 let mut values =
322 arena.get_values(slice.0.start as usize..slice.0.end as usize);
323 values.iter_mut().for_each(|x| {
324 if let LoroValue::Container(id) = x {
325 if id.is_normal() {
326 *id = register_container_id(
327 id.clone(),
328 peer_register.as_deref_mut(),
329 );
330 }
331 }
332 });
333 json::ListOp::Insert {
334 pos: *pos as u32,
335 value: values,
336 }
337 }
338 InnerListOp::Delete(DeleteSpanWithId {
339 id_start,
340 span: DeleteSpan { pos, signed_len },
341 }) => json::ListOp::Delete {
342 pos: *pos as i32,
343 len: *signed_len as i32,
344 start_id: register_id(id_start, peer_register.as_deref_mut()),
345 },
346 _ => unreachable!(),
347 }),
348 _ => unreachable!(),
349 },
350 ContainerType::MovableList => match content {
351 InnerContent::List(list) => JsonOpContent::MovableList(match list {
352 InnerListOp::Insert { slice, pos } => {
353 let mut values =
354 arena.get_values(slice.0.start as usize..slice.0.end as usize);
355 values.iter_mut().for_each(|x| {
356 if let LoroValue::Container(id) = x {
357 if id.is_normal() {
358 *id = register_container_id(
359 id.clone(),
360 peer_register.as_deref_mut(),
361 );
362 }
363 }
364 });
365 json::MovableListOp::Insert {
366 pos: *pos as u32,
367 value: values,
368 }
369 }
370 InnerListOp::Delete(DeleteSpanWithId {
371 id_start,
372 span: DeleteSpan { pos, signed_len },
373 }) => json::MovableListOp::Delete {
374 pos: *pos as i32,
375 len: *signed_len as i32,
376 start_id: register_id(id_start, peer_register.as_deref_mut()),
377 },
378 InnerListOp::Move {
379 from,
380 elem_id: from_id,
381 to,
382 } => json::MovableListOp::Move {
383 from: *from,
384 to: *to,
385 elem_id: register_idlp(from_id, peer_register.as_deref_mut()),
386 },
387 InnerListOp::Set { elem_id, value } => {
388 let value = if let LoroValue::Container(id) = value {
389 if id.is_normal() {
390 LoroValue::Container(register_container_id(
391 id.clone(),
392 peer_register.as_deref_mut(),
393 ))
394 } else {
395 value.clone()
396 }
397 } else {
398 value.clone()
399 };
400 json::MovableListOp::Set {
401 elem_id: register_idlp(elem_id, peer_register.as_deref_mut()),
402 value,
403 }
404 }
405 _ => unreachable!(),
406 }),
407 _ => unreachable!(),
408 },
409 ContainerType::Text => match content {
410 InnerContent::List(list) => JsonOpContent::Text(match list {
411 InnerListOp::InsertText {
412 slice,
413 unicode_start: _,
414 unicode_len: _,
415 pos,
416 } => {
417 let text = String::from_utf8(slice.as_bytes().to_vec()).unwrap();
418 json::TextOp::Insert { pos: *pos, text }
419 }
420 InnerListOp::Delete(DeleteSpanWithId {
421 id_start,
422 span: DeleteSpan { pos, signed_len },
423 }) => json::TextOp::Delete {
424 pos: *pos as i32,
425 len: *signed_len as i32,
426 start_id: register_id(id_start, peer_register.as_deref_mut()),
427 },
428 InnerListOp::StyleStart {
429 start,
430 end,
431 key,
432 value,
433 info,
434 } => json::TextOp::Mark {
435 start: *start,
436 end: *end,
437 style_key: key.to_string(),
438 style_value: value.clone(),
439 info: info.to_byte(),
440 },
441 InnerListOp::StyleEnd => json::TextOp::MarkEnd,
442 _ => unreachable!(),
443 }),
444 _ => unreachable!(),
445 },
446 ContainerType::Map => match content {
447 InnerContent::Map(MapSet { key, value }) => {
448 JsonOpContent::Map(if let Some(v) = value {
449 let value = if let LoroValue::Container(id) = v {
450 if id.is_normal() {
451 LoroValue::Container(register_container_id(
452 id.clone(),
453 peer_register.as_deref_mut(),
454 ))
455 } else {
456 v.clone()
457 }
458 } else {
459 v.clone()
460 };
461 json::MapOp::Insert {
462 key: key.to_string(),
463 value,
464 }
465 } else {
466 json::MapOp::Delete {
467 key: key.to_string(),
468 }
469 })
470 }
471
472 _ => unreachable!(),
473 },
474
475 ContainerType::Tree => match content {
476 InnerContent::Tree(op) => JsonOpContent::Tree(match &**op {
477 TreeOp::Create {
478 target,
479 parent,
480 position,
481 } => json::TreeOp::Create {
482 target: register_tree_id(target, peer_register.as_deref_mut()),
483 parent: parent.map(|p| register_tree_id(&p, peer_register.as_deref_mut())),
484 fractional_index: position.clone(),
485 },
486 TreeOp::Move {
487 target,
488 parent,
489 position,
490 } => json::TreeOp::Move {
491 target: register_tree_id(target, peer_register.as_deref_mut()),
492 parent: parent.map(|p| register_tree_id(&p, peer_register.as_deref_mut())),
493 fractional_index: position.clone(),
494 },
495 TreeOp::Delete { target } => json::TreeOp::Delete {
496 target: register_tree_id(target, peer_register.as_deref_mut()),
497 },
498 }),
499 _ => unreachable!(),
500 },
501 ContainerType::Unknown(_) => {
502 let InnerContent::Future(FutureInnerContent::Unknown { prop, value }) = content
503 else {
504 unreachable!();
505 };
506 JsonOpContent::Future(json::FutureOpWrapper {
507 prop: *prop,
508 value: json::FutureOp::Unknown((**value).clone()),
509 })
510 }
511 #[cfg(feature = "counter")]
512 ContainerType::Counter => {
513 let InnerContent::Future(f) = content else {
514 unreachable!()
515 };
516 match f {
517 FutureInnerContent::Counter(x) => {
518 JsonOpContent::Future(json::FutureOpWrapper {
519 prop: 0,
520 value: json::FutureOp::Counter(super::OwnedValue::F64(*x)),
521 })
522 }
523 _ => unreachable!(),
524 }
525 }
526 };
527 ops.push(json::JsonOp {
528 counter: *counter,
529 container,
530 content: op,
531 });
532 }
533 let c = json::JsonChange {
534 id: register_id(change.id, peer_register.as_deref_mut()),
535 ops,
536 deps: change
537 .deps
538 .iter()
539 .sorted()
541 .map(|id| register_id(&id, peer_register.as_deref_mut()))
542 .collect(),
543 lamport: *change.lamport,
544 timestamp: *change.timestamp,
545 msg: change.commit_msg.as_deref().map(|x| x.to_string()),
546 };
547 c
548}
549
550fn decode_changes(json: JsonSchema, arena: &SharedArena) -> LoroResult<Vec<Change>> {
551 let JsonSchema { peers, changes, .. } = json;
552 let mut ans = Vec::with_capacity(changes.len());
553 for json::JsonChange {
554 id,
555 timestamp,
556 deps,
557 lamport,
558 msg,
559 ops: json_ops,
560 } in changes
561 {
562 let id = convert_id(&id, &peers);
563 let mut ops: RleVec<[Op; 1]> = RleVec::new();
564 for op in json_ops {
565 ops.push(decode_op(op, arena, &peers)?);
566 }
567
568 let change = Change {
569 id,
570 timestamp,
571 deps: Frontiers::from_iter(deps.into_iter().map(|id| convert_id(&id, &peers))),
572 lamport,
573 ops,
574 commit_msg: msg.map(|x| x.into()),
575 };
576 ans.push(change);
577 }
578 Ok(ans)
579}
580
581fn decode_op(op: json::JsonOp, arena: &SharedArena, peers: &Option<Vec<PeerID>>) -> LoroResult<Op> {
582 let json::JsonOp {
583 counter,
584 container,
585 content,
586 } = op;
587 let container = convert_container_id(container, peers);
588 let idx = arena.register_container(&container);
589 let content = match container.container_type() {
590 ContainerType::Text => match content {
591 JsonOpContent::Text(text) => match text {
592 json::TextOp::Insert { pos, text } => {
593 let (slice, result) = arena.alloc_str_with_slice(&text);
594 InnerContent::List(InnerListOp::InsertText {
595 slice,
596 unicode_start: result.start as u32,
597 unicode_len: (result.end - result.start) as u32,
598 pos,
599 })
600 }
601 json::TextOp::Delete {
602 pos,
603 len,
604 start_id: id_start,
605 } => {
606 let id_start = convert_id(&id_start, peers);
607 InnerContent::List(InnerListOp::Delete(DeleteSpanWithId {
608 id_start,
609 span: DeleteSpan {
610 pos: pos as isize,
611 signed_len: len as isize,
612 },
613 }))
614 }
615 json::TextOp::Mark {
616 start,
617 end,
618 style_key,
619 style_value,
620 info,
621 } => InnerContent::List(InnerListOp::StyleStart {
622 start,
623 end,
624 key: style_key.into(),
625 value: style_value,
626 info: TextStyleInfoFlag::from_byte(info),
627 }),
628 json::TextOp::MarkEnd => InnerContent::List(InnerListOp::StyleEnd),
629 },
630 _ => unreachable!(),
631 },
632 ContainerType::List => match content {
633 JsonOpContent::List(list) => match list {
634 json::ListOp::Insert {
635 pos,
636 value: mut values,
637 } => {
638 values.iter_mut().for_each(|v| {
639 if let LoroValue::Container(id) = v {
640 if id.is_normal() {
641 *id = convert_container_id(id.clone(), peers);
642 }
643 }
644 });
645 let range = arena.alloc_values(values.iter().cloned());
646 InnerContent::List(InnerListOp::Insert {
647 slice: SliceRange::new(range.start as u32..range.end as u32),
648 pos: pos as usize,
649 })
650 }
651 json::ListOp::Delete { pos, len, start_id } => {
652 InnerContent::List(InnerListOp::Delete(DeleteSpanWithId {
653 id_start: convert_id(&start_id, peers),
654 span: DeleteSpan {
655 pos: pos as isize,
656 signed_len: len as isize,
657 },
658 }))
659 }
660 },
661 _ => unreachable!(),
662 },
663 ContainerType::MovableList => match content {
664 JsonOpContent::MovableList(list) => match list {
665 json::MovableListOp::Insert {
666 pos,
667 value: mut values,
668 } => {
669 values.iter_mut().for_each(|v| {
670 if let LoroValue::Container(id) = v {
671 if id.is_normal() {
672 *id = convert_container_id(id.clone(), peers);
673 }
674 }
675 });
676 let range = arena.alloc_values(values.iter().cloned());
677 InnerContent::List(InnerListOp::Insert {
678 slice: SliceRange::new(range.start as u32..range.end as u32),
679 pos: pos as usize,
680 })
681 }
682 json::MovableListOp::Delete { pos, len, start_id } => {
683 InnerContent::List(InnerListOp::Delete(DeleteSpanWithId {
684 id_start: convert_id(&start_id, peers),
685 span: DeleteSpan {
686 pos: pos as isize,
687 signed_len: len as isize,
688 },
689 }))
690 }
691 json::MovableListOp::Move {
692 from,
693 elem_id: from_id,
694 to,
695 } => {
696 let from_id = convert_idlp(&from_id, peers);
697 InnerContent::List(InnerListOp::Move {
698 from,
699 elem_id: from_id,
700 to,
701 })
702 }
703 json::MovableListOp::Set { elem_id, mut value } => {
704 let elem_id = convert_idlp(&elem_id, peers);
705 if let LoroValue::Container(id) = &mut value {
706 *id = convert_container_id(id.clone(), peers);
707 }
708 InnerContent::List(InnerListOp::Set { elem_id, value })
709 }
710 },
711 _ => unreachable!(),
712 },
713 ContainerType::Map => match content {
714 JsonOpContent::Map(map) => match map {
715 json::MapOp::Insert { key, mut value } => {
716 if let LoroValue::Container(id) = &mut value {
717 *id = convert_container_id(id.clone(), peers);
718 }
719 InnerContent::Map(MapSet {
720 key: key.into(),
721 value: Some(value),
722 })
723 }
724 json::MapOp::Delete { key } => InnerContent::Map(MapSet {
725 key: key.into(),
726 value: None,
727 }),
728 },
729 _ => unreachable!(),
730 },
731 ContainerType::Tree => match content {
732 JsonOpContent::Tree(tree) => match tree {
733 json::TreeOp::Create {
734 target,
735 parent,
736 fractional_index,
737 } => InnerContent::Tree(Arc::new(TreeOp::Create {
738 target: convert_tree_id(&target, peers),
739 parent: parent.map(|p| convert_tree_id(&p, peers)),
740 position: fractional_index,
741 })),
742 json::TreeOp::Move {
743 target,
744 parent,
745 fractional_index,
746 } => InnerContent::Tree(Arc::new(TreeOp::Move {
747 target: convert_tree_id(&target, peers),
748 parent: parent.map(|p| convert_tree_id(&p, peers)),
749 position: fractional_index,
750 })),
751 json::TreeOp::Delete { target } => InnerContent::Tree(Arc::new(TreeOp::Delete {
752 target: convert_tree_id(&target, peers),
753 })),
754 },
755 _ => unreachable!(),
756 },
757 ContainerType::Unknown(_) => match content {
758 JsonOpContent::Future(json::FutureOpWrapper {
759 prop,
760 value: json::FutureOp::Unknown(value),
761 }) => InnerContent::Future(FutureInnerContent::Unknown {
762 prop,
763 value: Box::new(value),
764 }),
765 _ => unreachable!(),
766 },
767 #[cfg(feature = "counter")]
768 ContainerType::Counter => {
769 let JsonOpContent::Future(json::FutureOpWrapper { prop: _, value }) = content else {
770 unreachable!()
771 };
772 use crate::encoding::OwnedValue;
773 match value {
774 json::FutureOp::Counter(OwnedValue::F64(c))
775 | json::FutureOp::Unknown(OwnedValue::F64(c)) => {
776 InnerContent::Future(FutureInnerContent::Counter(c))
777 }
778 json::FutureOp::Counter(OwnedValue::I64(c))
779 | json::FutureOp::Unknown(OwnedValue::I64(c)) => {
780 InnerContent::Future(FutureInnerContent::Counter(c as f64))
781 }
782 _ => unreachable!(),
783 }
784 } };
786 Ok(Op {
787 counter,
788 container: idx,
789 content,
790 })
791}
792
793impl TryFrom<&str> for JsonSchema {
794 type Error = serde_json::Error;
795
796 fn try_from(value: &str) -> Result<Self, Self::Error> {
797 serde_json::from_str(value)
798 }
799}
800
801impl TryFrom<&String> for JsonSchema {
802 type Error = serde_json::Error;
803
804 fn try_from(value: &String) -> Result<Self, Self::Error> {
805 serde_json::from_str(value)
806 }
807}
808
809impl TryFrom<String> for JsonSchema {
810 type Error = serde_json::Error;
811
812 fn try_from(value: String) -> Result<Self, Self::Error> {
813 serde_json::from_str(&value)
814 }
815}
816
817pub mod json {
818 use crate::{
819 encoding::OwnedValue,
820 version::{Frontiers, VersionRange},
821 };
822 use fractional_index::FractionalIndex;
823 use loro_common::{ContainerID, Counter, IdLp, Lamport, LoroValue, PeerID, TreeID, ID};
824 use serde::{Deserialize, Serialize};
825 use std::ops::Range;
826
827 use super::{get_peer_from_peers, redact_value};
828
829 #[derive(Debug, Clone, Serialize, Deserialize)]
830 pub struct JsonSchema {
831 pub schema_version: u8,
832 #[serde(with = "self::serde_impl::frontiers")]
833 pub start_version: Frontiers,
834 #[serde(with = "self::serde_impl::peer_id")]
835 pub peers: Option<Vec<PeerID>>,
836 pub changes: Vec<JsonChange>,
837 }
838
839 #[derive(Debug, Clone, Serialize, Deserialize)]
840 pub struct JsonChange {
841 #[serde(with = "self::serde_impl::id")]
842 pub id: ID,
843 pub timestamp: i64,
844 #[serde(with = "self::serde_impl::deps")]
845 pub deps: Vec<ID>,
846 pub lamport: Lamport,
847 pub msg: Option<String>,
848 pub ops: Vec<JsonOp>,
849 }
850
851 impl JsonChange {
852 pub fn op_len(&self) -> usize {
853 let last_op = self.ops.last().unwrap();
854 (last_op.counter - self.id.counter) as usize + last_op.content.op_len()
855 }
856 }
857
858 #[derive(Debug, Clone)]
859 pub struct JsonOp {
860 pub content: JsonOpContent,
861 pub container: ContainerID,
862 pub counter: i32,
863 }
864
865 #[derive(Debug, Clone, Serialize, Deserialize)]
866 #[serde(untagged)]
867 pub enum JsonOpContent {
868 List(ListOp),
869 MovableList(MovableListOp),
870 Map(MapOp),
871 Text(TextOp),
872 Tree(TreeOp),
873 Future(FutureOpWrapper),
875 }
876
877 impl JsonOpContent {
878 pub fn op_len(&self) -> usize {
879 match self {
880 JsonOpContent::List(list_op) => list_op.op_len(),
881 JsonOpContent::MovableList(movable_list_op) => movable_list_op.op_len(),
882 JsonOpContent::Map(..) => 1,
883 JsonOpContent::Text(text_op) => text_op.op_len(),
884 JsonOpContent::Tree(..) => 1,
885 JsonOpContent::Future(..) => 1,
886 }
887 }
888 }
889
890 #[derive(Debug, Clone, Serialize, Deserialize)]
891 pub struct FutureOpWrapper {
892 #[serde(flatten)]
893 pub value: FutureOp,
894 pub prop: i32,
895 }
896
897 #[derive(Debug, Clone, Serialize, Deserialize)]
898 #[serde(tag = "type", rename_all = "snake_case")]
899 pub enum ListOp {
900 Insert {
901 pos: u32,
902 value: Vec<LoroValue>,
903 },
904 Delete {
905 pos: i32,
906 len: i32,
907 #[serde(with = "self::serde_impl::id")]
908 start_id: ID,
909 },
910 }
911
912 impl ListOp {
913 fn op_len(&self) -> usize {
914 match self {
915 ListOp::Insert { value: values, .. } => values.len(),
916 ListOp::Delete { len, .. } => (*len).unsigned_abs() as usize,
917 }
918 }
919 }
920
921 #[derive(Debug, Clone, Serialize, Deserialize)]
922 #[serde(tag = "type", rename_all = "snake_case")]
923 pub enum MovableListOp {
924 Insert {
925 pos: u32,
926 value: Vec<LoroValue>,
927 },
928 Delete {
929 pos: i32,
930 len: i32,
931 #[serde(with = "self::serde_impl::id")]
932 start_id: ID,
933 },
934 Move {
935 from: u32,
936 to: u32,
937 #[serde(with = "self::serde_impl::idlp")]
938 elem_id: IdLp,
939 },
940 Set {
941 #[serde(with = "self::serde_impl::idlp")]
942 elem_id: IdLp,
943 value: LoroValue,
944 },
945 }
946
947 impl MovableListOp {
948 fn op_len(&self) -> usize {
949 match self {
950 MovableListOp::Insert { value: values, .. } => values.len(),
951 MovableListOp::Delete { len, .. } => (*len).unsigned_abs() as usize,
952 MovableListOp::Move { .. } => 1,
953 MovableListOp::Set { .. } => 1,
954 }
955 }
956 }
957
958 #[derive(Debug, Clone, Serialize, Deserialize)]
959 #[serde(tag = "type", rename_all = "snake_case")]
960 pub enum MapOp {
961 Insert { key: String, value: LoroValue },
962 Delete { key: String },
963 }
964
965 #[derive(Debug, Clone, Serialize, Deserialize)]
966 #[serde(tag = "type", rename_all = "snake_case")]
967 pub enum TextOp {
968 Insert {
969 pos: u32,
970 text: String,
971 },
972 Delete {
973 pos: i32,
974 len: i32,
975 #[serde(with = "self::serde_impl::id")]
976 start_id: ID,
977 },
978 Mark {
979 start: u32,
980 end: u32,
981 style_key: String,
982 style_value: LoroValue,
983 info: u8,
984 },
985 MarkEnd,
986 }
987
988 impl TextOp {
989 fn op_len(&self) -> usize {
990 match self {
991 TextOp::Insert { text, .. } => text.chars().count(),
992 TextOp::Delete { len, .. } => len.unsigned_abs() as usize,
993 TextOp::Mark { .. } => 1,
994 TextOp::MarkEnd => 1,
995 }
996 }
997 }
998
999 #[derive(Debug, Clone, Serialize, Deserialize)]
1000 #[serde(tag = "type", rename_all = "snake_case")]
1001 pub enum TreeOp {
1002 Create {
1003 #[serde(with = "self::serde_impl::tree_id")]
1004 target: TreeID,
1005 #[serde(with = "self::serde_impl::option_tree_id")]
1006 parent: Option<TreeID>,
1007 #[serde(default, with = "self::serde_impl::fractional_index")]
1008 fractional_index: FractionalIndex,
1009 },
1010 Move {
1011 #[serde(with = "self::serde_impl::tree_id")]
1012 target: TreeID,
1013 #[serde(with = "self::serde_impl::option_tree_id")]
1014 parent: Option<TreeID>,
1015 #[serde(default, with = "self::serde_impl::fractional_index")]
1016 fractional_index: FractionalIndex,
1017 },
1018 Delete {
1019 #[serde(with = "self::serde_impl::tree_id")]
1020 target: TreeID,
1021 },
1022 }
1023
1024 #[derive(Debug, Clone, Serialize, Deserialize)]
1025 #[serde(tag = "type", rename_all = "snake_case")]
1026 pub enum FutureOp {
1027 #[cfg(feature = "counter")]
1028 Counter(OwnedValue),
1029 Unknown(OwnedValue),
1030 }
1031
1032 mod serde_impl {
1033
1034 use loro_common::{ContainerID, ContainerType};
1035 use serde::{
1036 de::{MapAccess, Visitor},
1037 ser::SerializeStruct,
1038 Deserialize, Deserializer, Serialize, Serializer,
1039 };
1040
1041 #[allow(unused_imports)]
1042 use crate::encoding::OwnedValue;
1043
1044 impl Serialize for super::JsonOp {
1045 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1046 where
1047 S: Serializer,
1048 {
1049 let mut s = serializer.serialize_struct("Op", 3)?;
1050 s.serialize_field("container", &self.container.to_string())?;
1051 s.serialize_field("content", &self.content)?;
1052 s.serialize_field("counter", &self.counter)?;
1053 s.end()
1054 }
1055 }
1056
1057 impl<'de> Deserialize<'de> for super::JsonOp {
1058 fn deserialize<D>(deserializer: D) -> Result<super::JsonOp, D::Error>
1059 where
1060 D: Deserializer<'de>,
1061 {
1062 struct __Visitor;
1063
1064 impl<'de> Visitor<'de> for __Visitor {
1065 type Value = super::JsonOp;
1066 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1067 formatter.write_str("struct Op")
1068 }
1069
1070 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
1071 where
1072 A: MapAccess<'de>,
1073 {
1074 let (_key, container) = map.next_entry::<String, String>()?.unwrap();
1075 let is_unknown = container.ends_with(')');
1076 let container = ContainerID::try_from(container.as_str())
1077 .map_err(|_| serde::de::Error::custom("invalid container id"))?;
1078 let op = if is_unknown {
1079 let (_key, op) =
1080 map.next_entry::<String, super::FutureOpWrapper>()?.unwrap();
1081 super::JsonOpContent::Future(op)
1082 } else {
1083 match container.container_type() {
1084 ContainerType::List => {
1085 let (_key, op) =
1086 map.next_entry::<String, super::ListOp>()?.unwrap();
1087 super::JsonOpContent::List(op)
1088 }
1089 ContainerType::MovableList => {
1090 let (_key, op) =
1091 map.next_entry::<String, super::MovableListOp>()?.unwrap();
1092 super::JsonOpContent::MovableList(op)
1093 }
1094 ContainerType::Map => {
1095 let (_key, op) =
1096 map.next_entry::<String, super::MapOp>()?.unwrap();
1097 super::JsonOpContent::Map(op)
1098 }
1099 ContainerType::Text => {
1100 let (_key, op) =
1101 map.next_entry::<String, super::TextOp>()?.unwrap();
1102 super::JsonOpContent::Text(op)
1103 }
1104 ContainerType::Tree => {
1105 let (_key, op) =
1106 map.next_entry::<String, super::TreeOp>()?.unwrap();
1107 super::JsonOpContent::Tree(op)
1108 }
1109 #[cfg(feature = "counter")]
1110 ContainerType::Counter => {
1111 let (_key, value) =
1112 map.next_entry::<String, OwnedValue>()?.unwrap();
1113 super::JsonOpContent::Future(super::FutureOpWrapper {
1114 prop: 0,
1115 value: super::FutureOp::Counter(value),
1116 })
1117 }
1118 _ => unreachable!(),
1119 }
1120 };
1121 let (_, counter) = map.next_entry::<String, i32>()?.unwrap();
1122 Ok(super::JsonOp {
1123 container,
1124 content: op,
1125 counter,
1126 })
1127 }
1128 }
1129 const FIELDS: &[&str] = &["container", "content", "counter"];
1130 deserializer.deserialize_struct("JsonOp", FIELDS, __Visitor)
1131 }
1132 }
1133
1134 pub mod id {
1135 use loro_common::ID;
1136 use serde::{Deserialize, Deserializer, Serializer};
1137
1138 pub fn serialize<S>(id: &ID, s: S) -> Result<S::Ok, S::Error>
1139 where
1140 S: Serializer,
1141 {
1142 s.serialize_str(&id.to_string())
1143 }
1144
1145 pub fn deserialize<'de, 'a, D>(d: D) -> Result<ID, D::Error>
1146 where
1147 D: Deserializer<'de>,
1148 {
1149 let str: String = Deserialize::deserialize(d)?;
1151 let id: ID = ID::try_from(str.as_str()).unwrap();
1152 Ok(id)
1153 }
1154 }
1155
1156 pub mod frontiers {
1157 use itertools::Itertools;
1158 use loro_common::ID;
1159 use serde::{ser::SerializeMap, Deserializer, Serializer};
1160
1161 use crate::version::Frontiers;
1162
1163 pub fn serialize<S>(f: &Frontiers, s: S) -> Result<S::Ok, S::Error>
1164 where
1165 S: Serializer,
1166 {
1167 let mut map = s.serialize_map(Some(f.len()))?;
1168 for id in f
1169 .iter()
1170 .sorted()
1172 {
1173 map.serialize_entry(&id.peer.to_string(), &id.counter)?;
1174 }
1175 map.end()
1176 }
1177
1178 pub fn deserialize<'de, 'a, D>(d: D) -> Result<Frontiers, D::Error>
1179 where
1180 D: Deserializer<'de>,
1181 {
1182 struct __Visitor;
1183 impl<'de> serde::de::Visitor<'de> for __Visitor {
1184 type Value = Frontiers;
1185 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1186 formatter.write_str("a Frontiers")
1187 }
1188
1189 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
1190 where
1191 A: serde::de::MapAccess<'de>,
1192 {
1193 let mut f = Frontiers::default();
1194 while let Some((k, v)) = map.next_entry::<String, i32>()? {
1195 f.push(ID::new(k.parse().unwrap(), v))
1196 }
1197 Ok(f)
1198 }
1199 }
1200 d.deserialize_map(__Visitor)
1201 }
1202 }
1203
1204 pub mod deps {
1205 use loro_common::ID;
1206 use serde::{Deserialize, Deserializer, Serializer};
1207
1208 pub fn serialize<S>(deps: &[ID], s: S) -> Result<S::Ok, S::Error>
1209 where
1210 S: Serializer,
1211 {
1212 s.collect_seq(deps.iter().map(|x| x.to_string()))
1213 }
1214
1215 pub fn deserialize<'de, 'a, D>(d: D) -> Result<Vec<ID>, D::Error>
1216 where
1217 D: Deserializer<'de>,
1218 {
1219 let deps: Vec<String> = Deserialize::deserialize(d)?;
1220 Ok(deps
1221 .into_iter()
1222 .map(|x| ID::try_from(x.as_str()).unwrap())
1223 .collect())
1224 }
1225 }
1226
1227 pub mod peer_id {
1228 use loro_common::PeerID;
1229 use serde::{Deserialize, Deserializer, Serializer};
1230
1231 pub fn serialize<S>(peers: &Option<Vec<PeerID>>, s: S) -> Result<S::Ok, S::Error>
1232 where
1233 S: Serializer,
1234 {
1235 match peers {
1236 Some(peers) => s.collect_seq(peers.iter().map(|x| x.to_string())),
1237 None => s.serialize_none(),
1238 }
1239 }
1240
1241 pub fn deserialize<'de, 'a, D>(d: D) -> Result<Option<Vec<PeerID>>, D::Error>
1242 where
1243 D: Deserializer<'de>,
1244 {
1245 let peers: Option<Vec<String>> = Deserialize::deserialize(d)?;
1246 Ok(peers.map(|x| x.into_iter().map(|x| x.parse().unwrap()).collect()))
1247 }
1248 }
1249
1250 pub mod idlp {
1251 use loro_common::IdLp;
1252 use serde::{Deserialize, Deserializer, Serializer};
1253
1254 pub fn serialize<S>(idlp: &IdLp, s: S) -> Result<S::Ok, S::Error>
1255 where
1256 S: Serializer,
1257 {
1258 s.serialize_str(&idlp.to_string())
1259 }
1260
1261 pub fn deserialize<'de, 'a, D>(d: D) -> Result<IdLp, D::Error>
1262 where
1263 D: Deserializer<'de>,
1264 {
1265 let str: String = Deserialize::deserialize(d)?;
1266 let id: IdLp = IdLp::try_from(str.as_str()).unwrap();
1267 Ok(id)
1268 }
1269 }
1270
1271 pub mod tree_id {
1272 use loro_common::TreeID;
1273 use serde::{Deserialize, Deserializer, Serializer};
1274
1275 pub fn serialize<S>(id: &TreeID, s: S) -> Result<S::Ok, S::Error>
1276 where
1277 S: Serializer,
1278 {
1279 s.serialize_str(&id.to_string())
1280 }
1281
1282 pub fn deserialize<'de, 'a, D>(d: D) -> Result<TreeID, D::Error>
1283 where
1284 D: Deserializer<'de>,
1285 {
1286 let str: String = Deserialize::deserialize(d)?;
1287 let id: TreeID = TreeID::try_from(str.as_str()).unwrap();
1288 Ok(id)
1289 }
1290 }
1291
1292 pub mod option_tree_id {
1293 use loro_common::TreeID;
1294 use serde::{Deserialize, Deserializer, Serializer};
1295
1296 pub fn serialize<S>(id: &Option<TreeID>, s: S) -> Result<S::Ok, S::Error>
1297 where
1298 S: Serializer,
1299 {
1300 match id {
1301 Some(id) => s.serialize_str(&id.to_string()),
1302 None => s.serialize_none(),
1303 }
1304 }
1305
1306 pub fn deserialize<'de, 'a, D>(d: D) -> Result<Option<TreeID>, D::Error>
1307 where
1308 D: Deserializer<'de>,
1309 {
1310 let str: Option<String> = Deserialize::deserialize(d)?;
1311 match str {
1312 Some(str) => {
1313 let id: TreeID = TreeID::try_from(str.as_str()).unwrap();
1314 Ok(Some(id))
1315 }
1316 None => Ok(None),
1317 }
1318 }
1319 }
1320
1321 pub mod fractional_index {
1322 use fractional_index::FractionalIndex;
1323 use serde::{Deserialize, Deserializer, Serializer};
1324
1325 pub fn serialize<S>(fi: &FractionalIndex, s: S) -> Result<S::Ok, S::Error>
1326 where
1327 S: Serializer,
1328 {
1329 s.serialize_str(&fi.to_string())
1330 }
1331
1332 pub fn deserialize<'de, 'a, D>(d: D) -> Result<FractionalIndex, D::Error>
1333 where
1334 D: Deserializer<'de>,
1335 {
1336 let str: String = Deserialize::deserialize(d)?;
1337 let fi = FractionalIndex::from_hex_string(str);
1338 Ok(fi)
1339 }
1340 }
1341 }
1342
1343 #[derive(thiserror::Error, Debug, PartialEq, Eq)]
1344 pub enum RedactError {
1345 #[error("unknown operation type")]
1346 UnknownOperationType,
1347 }
1348
1349 pub fn redact(json: &mut JsonSchema, range: VersionRange) -> Result<(), RedactError> {
1366 let peers = json.peers.clone();
1367 let mut errors = Vec::new();
1368 for change in json.changes.iter_mut() {
1369 let real_peer = get_peer_from_peers(&peers, change.id.peer);
1370 let real_id = ID::new(real_peer, change.id.counter);
1371 if !range.has_overlap_with(real_id.to_span(change.op_len())) {
1372 continue;
1373 }
1374
1375 let redact_range = range.get(&real_peer).copied().unwrap();
1376 for op in change.ops.iter_mut() {
1377 if op.counter >= redact_range.1 {
1378 break;
1379 }
1380
1381 let len = op.content.op_len() as Counter;
1382 if op.counter + len <= redact_range.0 {
1383 continue;
1384 }
1385
1386 let result = redact_op(
1387 &mut op.content,
1388 (redact_range.0 - op.counter).max(0).min(len)
1389 ..(redact_range.1 - op.counter).max(0).min(len),
1390 );
1391 match result {
1392 Ok(()) => {}
1393 Err(e) => errors.push(e),
1394 }
1395 }
1396 }
1397
1398 if errors.is_empty() {
1399 Ok(())
1400 } else {
1401 Err(errors.pop().unwrap())
1402 }
1403 }
1404
1405 fn redact_op(op: &mut JsonOpContent, range: Range<Counter>) -> Result<(), RedactError> {
1406 match op {
1407 JsonOpContent::List(list_op) => {
1408 match list_op {
1409 ListOp::Insert { value: values, .. } => {
1410 for i in range {
1411 redact_value(&mut values[i as usize]);
1412 }
1413 }
1414 ListOp::Delete { .. } => {
1415 }
1417 }
1418 }
1419 JsonOpContent::MovableList(movable_list_op) => {
1420 match movable_list_op {
1421 MovableListOp::Insert { value: values, .. } => {
1422 for i in range {
1423 redact_value(&mut values[i as usize]);
1424 }
1425 }
1426 MovableListOp::Delete { .. } | MovableListOp::Move { .. } => {
1427 }
1429 MovableListOp::Set { value, .. } => {
1430 assert!(range.start == 0 && range.len() == 1);
1431 redact_value(value);
1432 }
1433 }
1434 }
1435 JsonOpContent::Map(map_op) => {
1436 match map_op {
1437 MapOp::Insert { value, .. } => {
1438 assert!(range.start == 0 && range.len() == 1);
1439 redact_value(value);
1440 }
1441 MapOp::Delete { .. } => {
1442 }
1444 }
1445 }
1446 JsonOpContent::Text(text_op) => {
1447 match text_op {
1448 TextOp::Insert { text, .. } => {
1449 let mut chars = vec![];
1450 for (i, c) in text.chars().enumerate() {
1451 if i < range.start as usize || i >= range.end as usize {
1452 chars.push(c);
1453 } else {
1454 chars.push("� ".chars().next().unwrap());
1455 }
1456 }
1457 *text = chars.into_iter().collect();
1458 }
1459 TextOp::Delete { .. } => {
1460 }
1462 TextOp::Mark { style_value, .. } => {
1463 assert!(range.start == 0 && range.len() == 1);
1464 *style_value = LoroValue::Null;
1465 }
1466 TextOp::MarkEnd => {
1467 }
1469 }
1470 }
1471 JsonOpContent::Tree(..) => {
1472 }
1474 JsonOpContent::Future(future_op_wrapper) => match &mut future_op_wrapper.value {
1475 #[cfg(feature = "counter")]
1476 FutureOp::Counter(owned_value) => {
1477 *owned_value = OwnedValue::I64(0);
1478 }
1479 FutureOp::Unknown(..) => {
1480 return Err(RedactError::UnknownOperationType);
1481 }
1482 },
1483 }
1484
1485 Ok(())
1486 }
1487}
1488
1489fn redact_value(v: &mut LoroValue) {
1490 match v {
1491 LoroValue::Container(_) => {}
1492 _ => *v = LoroValue::Null,
1493 }
1494}
1495
1496#[cfg(test)]
1497mod tests {
1498 use crate::{LoroDoc, VersionVector};
1499
1500 #[test]
1501 fn json_range_version() {
1502 let doc = LoroDoc::new_auto_commit();
1503 doc.set_peer_id(0).unwrap();
1504 let list = doc.get_list("list");
1505 list.insert(0, "a").unwrap();
1506 list.insert(0, "b").unwrap();
1507 list.insert(0, "c").unwrap();
1508 let json = doc.export_json_updates(
1509 &VersionVector::from_iter(vec![(0, 1)]),
1510 &VersionVector::from_iter(vec![(0, 2)]),
1511 true,
1512 );
1513 assert_eq!(json.changes[0].ops.len(), 1);
1514 let json = doc.export_json_updates(
1515 &VersionVector::from_iter(vec![(0, 0)]),
1516 &VersionVector::from_iter(vec![(0, 2)]),
1517 true,
1518 );
1519 assert_eq!(json.changes[0].ops.len(), 2);
1520 }
1521}