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