1use std::{
2 borrow::Cow,
3 cmp::Ordering,
4 collections::HashMap,
5 ops::{ControlFlow, Deref},
6 sync::{Arc, Mutex},
7};
8
9use loro::{
10 cursor::CannotFindRelativePosition, ChangeTravelError, CounterSpan, DocAnalysis,
11 FrontiersNotIncluded, IdSpan, JsonSchema, Lamport, LoroDoc as InnerLoroDoc, LoroEncodeError,
12 LoroError, LoroResult, PeerID, StyleConfig, Timestamp, ID,
13};
14
15use crate::{
16 event::{DiffBatch, DiffEvent, Subscriber},
17 AbsolutePosition, Configure, ContainerID, ContainerIdLike, Cursor, Frontiers, Index,
18 JsonPathError, LoroCounter, LoroList, LoroMap, LoroMovableList, LoroText, LoroTree, LoroValue,
19 StyleConfigMap, SubscribeJsonPathCallback, ValueOrContainer, VersionRange, VersionVector,
20 VersionVectorDiff,
21};
22
23#[inline]
25pub fn decode_import_blob_meta(
26 bytes: &[u8],
27 check_checksum: bool,
28) -> LoroResult<ImportBlobMetadata> {
29 let s = InnerLoroDoc::decode_import_blob_meta(bytes, check_checksum)?;
30 Ok(s.into())
31}
32
33pub struct LoroDoc {
34 pub(crate) doc: InnerLoroDoc,
35}
36
37impl LoroDoc {
38 pub fn new() -> Self {
39 Self {
40 doc: InnerLoroDoc::new(),
41 }
42 }
43
44 pub fn fork(&self) -> Arc<Self> {
45 let doc = self.doc.fork();
46 Arc::new(LoroDoc { doc })
47 }
48
49 pub fn fork_at(&self, frontiers: &Frontiers) -> Arc<Self> {
50 let doc = self.doc.fork_at(&frontiers.into());
51 Arc::new(LoroDoc { doc })
52 }
53
54 #[inline]
56 pub fn config(&self) -> Arc<Configure> {
57 Arc::new(self.doc.config().clone().into())
58 }
59
60 #[inline]
74 pub fn get_change(&self, id: ID) -> Option<ChangeMeta> {
75 self.doc.get_change(id).map(|x| x.into())
76 }
77
78 #[inline]
88 pub fn set_record_timestamp(&self, record: bool) {
89 self.doc.set_record_timestamp(record);
90 }
91
92 #[inline]
100 pub fn set_change_merge_interval(&self, interval: i64) {
101 self.doc.set_change_merge_interval(interval);
102 }
103
104 #[inline]
112 pub fn config_text_style(&self, text_style: Arc<StyleConfigMap>) {
113 self.doc.config_text_style(text_style.as_ref().to_loro())
114 }
115
116 pub fn config_default_text_style(&self, text_style: Option<StyleConfig>) {
125 self.doc.config_default_text_style(text_style);
126 }
127
128 #[inline]
135 pub fn attach(&self) {
136 self.doc.attach()
137 }
138
139 #[inline]
148 pub fn checkout(&self, frontiers: &Frontiers) -> LoroResult<()> {
149 self.doc.checkout(&frontiers.into())
150 }
151
152 #[inline]
161 pub fn checkout_to_latest(&self) {
162 self.doc.checkout_to_latest()
163 }
164
165 #[inline]
169 pub fn cmp_with_frontiers(&self, other: &Frontiers) -> Ordering {
170 self.doc.cmp_with_frontiers(&other.into())
171 }
172
173 pub fn cmp_frontiers(
175 &self,
176 a: &Frontiers,
177 b: &Frontiers,
178 ) -> Result<Option<Ordering>, FrontiersNotIncluded> {
179 self.doc.cmp_frontiers(&a.into(), &b.into())
180 }
181
182 #[inline]
188 pub fn detach(&self) {
189 self.doc.detach()
190 }
191
192 #[inline]
196 pub fn import_batch(&self, bytes: &[Vec<u8>]) -> Result<ImportStatus, LoroError> {
197 let status = self.doc.import_batch(bytes)?;
198 Ok(status.into())
199 }
200
201 pub fn get_movable_list(&self, id: Arc<dyn ContainerIdLike>) -> Arc<LoroMovableList> {
202 Arc::new(LoroMovableList {
203 inner: self.doc.get_movable_list(loro::ContainerID::from(
204 id.as_container_id(crate::ContainerType::MovableList),
205 )),
206 })
207 }
208
209 pub fn get_list(&self, id: Arc<dyn ContainerIdLike>) -> Arc<LoroList> {
210 Arc::new(LoroList {
211 inner: self.doc.get_list(loro::ContainerID::from(
212 id.as_container_id(crate::ContainerType::List),
213 )),
214 })
215 }
216
217 pub fn get_map(&self, id: Arc<dyn ContainerIdLike>) -> Arc<LoroMap> {
218 Arc::new(LoroMap {
219 inner: self.doc.get_map(loro::ContainerID::from(
220 id.as_container_id(crate::ContainerType::Map),
221 )),
222 })
223 }
224
225 pub fn get_text(&self, id: Arc<dyn ContainerIdLike>) -> Arc<LoroText> {
226 Arc::new(LoroText {
227 inner: self.doc.get_text(loro::ContainerID::from(
228 id.as_container_id(crate::ContainerType::Text),
229 )),
230 })
231 }
232
233 pub fn get_tree(&self, id: Arc<dyn ContainerIdLike>) -> Arc<LoroTree> {
234 Arc::new(LoroTree {
235 inner: self.doc.get_tree(loro::ContainerID::from(
236 id.as_container_id(crate::ContainerType::Tree),
237 )),
238 })
239 }
240
241 pub fn get_counter(&self, id: Arc<dyn ContainerIdLike>) -> Arc<LoroCounter> {
242 Arc::new(LoroCounter {
243 inner: self.doc.get_counter(loro::ContainerID::from(
244 id.as_container_id(crate::ContainerType::Counter),
245 )),
246 })
247 }
248
249 pub fn get_container(&self, id: &ContainerID) -> Option<Arc<dyn ValueOrContainer>> {
250 self.doc
251 .get_container(id.clone().into())
252 .map(|c| Arc::new(loro::ValueOrContainer::Container(c)) as Arc<dyn ValueOrContainer>)
253 }
254
255 #[inline]
265 pub fn commit(&self) {
266 self.doc.commit()
267 }
268
269 pub fn commit_with(&self, options: CommitOptions) {
270 self.doc.commit_with(options.into())
271 }
272
273 pub fn set_next_commit_message(&self, msg: &str) {
277 self.doc.set_next_commit_message(msg)
278 }
279
280 pub fn set_next_commit_origin(&self, origin: &str) {
284 self.doc.set_next_commit_origin(origin)
285 }
286
287 pub fn set_next_commit_timestamp(&self, timestamp: i64) {
292 self.doc.set_next_commit_timestamp(timestamp)
293 }
294
295 pub fn set_next_commit_options(&self, options: CommitOptions) {
299 self.doc.set_next_commit_options(options.into())
300 }
301
302 pub fn clear_next_commit_options(&self) {
304 self.doc.clear_next_commit_options()
305 }
306
307 #[inline]
310 pub fn is_detached(&self) -> bool {
311 self.doc.is_detached()
312 }
313
314 #[inline]
316 pub fn import(&self, bytes: &[u8]) -> Result<ImportStatus, LoroError> {
317 let status = self.doc.import_with(bytes, "")?;
318 Ok(status.into())
319 }
320
321 #[inline]
326 pub fn import_with(&self, bytes: &[u8], origin: &str) -> Result<ImportStatus, LoroError> {
327 let status = self.doc.import_with(bytes, origin)?;
328 Ok(status.into())
329 }
330
331 pub fn import_json_updates(&self, json: &str) -> Result<ImportStatus, LoroError> {
332 let status = self.doc.import_json_updates(json)?;
333 Ok(status.into())
334 }
335
336 #[inline]
338 pub fn export_json_updates(&self, start_vv: &VersionVector, end_vv: &VersionVector) -> String {
339 let json = self
340 .doc
341 .export_json_updates(&start_vv.into(), &end_vv.into());
342 serde_json::to_string(&json).unwrap()
343 }
344
345 #[inline]
350 pub fn export_json_updates_without_peer_compression(
351 &self,
352 start_vv: &VersionVector,
353 end_vv: &VersionVector,
354 ) -> String {
355 serde_json::to_string(
356 &self
357 .doc
358 .export_json_updates_without_peer_compression(&start_vv.into(), &end_vv.into()),
359 )
360 .unwrap()
361 }
362
363 pub fn redact_json_updates(
376 &self,
377 json: &str,
378 version_range: &VersionRange,
379 ) -> Result<String, LoroError> {
380 let mut schema: JsonSchema =
381 serde_json::from_str(json).map_err(|_e| LoroError::InvalidJsonSchema)?;
382 loro::json::redact(&mut schema, version_range.into())
383 .map_err(|e| LoroError::Unknown(e.to_string().into_boxed_str()))?;
384 Ok(serde_json::to_string(&schema).unwrap())
385 }
386
387 pub fn export_json_in_id_span(&self, id_span: IdSpan) -> Vec<String> {
390 self.doc
391 .export_json_in_id_span(id_span)
392 .into_iter()
393 .map(|x| serde_json::to_string(&x).unwrap())
394 .collect()
395 }
396
397 #[inline]
400 pub fn export_updates(&self, vv: &VersionVector) -> Result<Vec<u8>, LoroEncodeError> {
401 self.doc.export(loro::ExportMode::Updates {
402 from: Cow::Owned(vv.into()),
403 })
404 }
405
406 #[inline]
408 pub fn export_snapshot(&self) -> Result<Vec<u8>, LoroEncodeError> {
409 self.doc.export(loro::ExportMode::Snapshot)
410 }
411
412 pub fn export_snapshot_at(&self, frontiers: &Frontiers) -> Result<Vec<u8>, LoroEncodeError> {
413 self.doc.export(loro::ExportMode::SnapshotAt {
414 version: Cow::Owned(frontiers.into()),
415 })
416 }
417
418 pub fn frontiers_to_vv(&self, frontiers: &Frontiers) -> Option<Arc<VersionVector>> {
419 self.doc
420 .frontiers_to_vv(&frontiers.into())
421 .map(|v| Arc::new(v.into()))
422 }
423
424 pub fn minimize_frontiers(&self, frontiers: &Frontiers) -> FrontiersOrID {
425 match self.doc.minimize_frontiers(&frontiers.into()) {
426 Ok(f) => FrontiersOrID {
427 frontiers: Some(Arc::new(f.into())),
428 id: None,
429 },
430 Err(id) => FrontiersOrID {
431 frontiers: None,
432 id: Some(id),
433 },
434 }
435 }
436
437 pub fn vv_to_frontiers(&self, vv: &VersionVector) -> Arc<Frontiers> {
438 Arc::new(self.doc.vv_to_frontiers(&vv.into()).into())
439 }
440
441 pub fn oplog_vv(&self) -> Arc<VersionVector> {
445 Arc::new(self.doc.oplog_vv().into())
446 }
447
448 pub fn state_vv(&self) -> Arc<VersionVector> {
449 Arc::new(self.doc.state_vv().into())
450 }
451
452 #[inline]
456 pub fn shallow_since_vv(&self) -> Arc<VersionVector> {
457 Arc::new(loro::VersionVector::from_im_vv(&self.doc.shallow_since_vv()).into())
458 }
459
460 #[inline]
462 pub fn len_ops(&self) -> u64 {
463 self.doc.len_ops() as u64
464 }
465
466 #[inline]
468 pub fn len_changes(&self) -> u64 {
469 self.doc.len_changes() as u64
470 }
471
472 #[inline]
474 pub fn get_value(&self) -> LoroValue {
475 self.doc.get_value().into()
476 }
477
478 pub fn get_deep_value(&self) -> LoroValue {
479 self.doc.get_deep_value().into()
480 }
481
482 pub fn get_deep_value_with_id(&self) -> LoroValue {
484 self.doc.get_deep_value_with_id().into()
485 }
486
487 pub fn oplog_frontiers(&self) -> Arc<Frontiers> {
488 Arc::new(self.doc.oplog_frontiers().into())
489 }
490
491 pub fn state_frontiers(&self) -> Arc<Frontiers> {
492 Arc::new(self.doc.state_frontiers().into())
493 }
494
495 #[inline]
497 pub fn peer_id(&self) -> PeerID {
498 self.doc.peer_id()
499 }
500
501 #[inline]
506 pub fn set_peer_id(&self, peer: PeerID) -> LoroResult<()> {
507 self.doc.set_peer_id(peer)
508 }
509
510 pub fn subscribe(
511 &self,
512 container_id: &ContainerID,
513 subscriber: Arc<dyn Subscriber>,
514 ) -> Arc<Subscription> {
515 Arc::new(
516 self.doc
517 .subscribe(
518 &(container_id.into()),
519 Arc::new(move |e| {
520 subscriber.on_diff(DiffEvent::from(e));
521 }),
522 )
523 .into(),
524 )
525 }
526
527 pub fn subscribe_root(&self, subscriber: Arc<dyn Subscriber>) -> Arc<Subscription> {
528 Arc::new(
530 self.doc
531 .subscribe_root(Arc::new(move |e| {
532 subscriber.on_diff(DiffEvent::from(e));
533 }))
534 .into(),
535 )
536 }
537
538 pub fn subscribe_local_update(
540 &self,
541 callback: Arc<dyn LocalUpdateCallback>,
542 ) -> Arc<Subscription> {
543 let s = self.doc.subscribe_local_update(Box::new(move |update| {
544 callback.on_local_update(update.to_vec());
546 true
547 }));
548 Arc::new(Subscription(Mutex::new(Some(s))))
549 }
550
551 #[inline]
554 pub fn check_state_correctness_slow(&self) {
555 self.doc.check_state_correctness_slow()
556 }
557
558 pub fn get_by_path(&self, path: &[Index]) -> Option<Arc<dyn ValueOrContainer>> {
559 self.doc
560 .get_by_path(&path.iter().map(|v| v.clone().into()).collect::<Vec<_>>())
561 .map(|x| Arc::new(x) as Arc<dyn ValueOrContainer>)
562 }
563
564 pub fn get_by_str_path(&self, path: &str) -> Option<Arc<dyn ValueOrContainer>> {
617 self.doc
618 .get_by_str_path(path)
619 .map(|v| Arc::new(v) as Arc<dyn ValueOrContainer>)
620 }
621
622 pub fn get_cursor_pos(
623 &self,
624 cursor: &Cursor,
625 ) -> Result<PosQueryResult, CannotFindRelativePosition> {
626 let loro::cursor::PosQueryResult { update, current } = self.doc.get_cursor_pos(cursor)?;
627 Ok(PosQueryResult {
628 current: AbsolutePosition {
629 pos: current.pos as u32,
630 side: current.side,
631 },
632 update: update.map(|x| Arc::new(x.into())),
633 })
634 }
635
636 #[inline]
638 pub fn has_history_cache(&self) -> bool {
639 self.doc.has_history_cache()
640 }
641
642 #[inline]
647 pub fn free_history_cache(&self) {
648 self.doc.free_history_cache()
649 }
650
651 #[inline]
653 pub fn free_diff_calculator(&self) {
654 self.doc.free_diff_calculator()
655 }
656
657 #[inline]
661 pub fn compact_change_store(&self) {
662 self.doc.compact_change_store()
663 }
664
665 pub fn export_updates_in_range(&self, spans: &[IdSpan]) -> Result<Vec<u8>, LoroEncodeError> {
671 self.doc.export(loro::ExportMode::UpdatesInRange {
672 spans: Cow::Borrowed(spans),
673 })
674 }
675
676 pub fn export_shallow_snapshot(
677 &self,
678 frontiers: &Frontiers,
679 ) -> Result<Vec<u8>, LoroEncodeError> {
680 self.doc
681 .export(loro::ExportMode::ShallowSnapshot(Cow::Owned(
682 frontiers.into(),
683 )))
684 }
685
686 pub fn export_state_only(
687 &self,
688 frontiers: Option<Arc<Frontiers>>,
689 ) -> Result<Vec<u8>, LoroEncodeError> {
690 self.doc
691 .export(loro::ExportMode::StateOnly(frontiers.map(|x| {
692 let a = x.as_ref();
693 Cow::Owned(loro::Frontiers::from(a))
694 })))
695 }
696
697 pub fn analyze(&self) -> DocAnalysis {
702 self.doc.analyze()
703 }
704
705 pub fn get_path_to_container(&self, id: &ContainerID) -> Option<Vec<ContainerPath>> {
707 self.doc.get_path_to_container(&id.into()).map(|x| {
708 x.into_iter()
709 .map(|(id, idx)| ContainerPath {
710 id: id.into(),
711 path: (&idx).into(),
712 })
713 .collect()
714 })
715 }
716
717 #[inline]
733 pub fn jsonpath(&self, path: &str) -> Result<Vec<Arc<dyn ValueOrContainer>>, JsonPathError> {
734 self.doc.jsonpath(path).map(|vec| {
735 vec.into_iter()
736 .map(|v| Arc::new(v) as Arc<dyn ValueOrContainer>)
737 .collect()
738 })
739 }
740
741 #[inline]
746 pub fn subscribe_jsonpath(
747 &self,
748 path: &str,
749 callback: Arc<dyn JsonPathSubscriber>,
750 ) -> LoroResult<Arc<Subscription>> {
751 let callback: SubscribeJsonPathCallback = Arc::new(move || {
752 callback.on_jsonpath_changed();
753 });
754
755 self.doc
756 .subscribe_jsonpath(path, callback)
757 .map(|subscription| Arc::new(subscription.into()))
758 }
759
760 pub fn travel_change_ancestors(
761 &self,
762 ids: &[ID],
763 f: Arc<dyn ChangeAncestorsTraveler>,
764 ) -> Result<(), ChangeTravelError> {
765 self.doc
766 .travel_change_ancestors(ids, &mut |change| match f.travel(change.into()) {
767 true => ControlFlow::Continue(()),
768 false => ControlFlow::Break(()),
769 })
770 }
771
772 pub fn get_changed_containers_in(&self, id: ID, len: u32) -> Vec<ContainerID> {
773 self.doc
774 .get_changed_containers_in(id, len as usize)
775 .into_iter()
776 .map(|x| x.into())
777 .collect()
778 }
779
780 pub fn is_shallow(&self) -> bool {
781 self.doc.is_shallow()
782 }
783
784 pub fn get_pending_txn_len(&self) -> u32 {
785 self.doc.get_pending_txn_len() as u32
786 }
787
788 #[inline]
790 pub fn find_id_spans_between(&self, from: &Frontiers, to: &Frontiers) -> VersionVectorDiff {
791 self.doc
792 .find_id_spans_between(&from.into(), &to.into())
793 .into()
794 }
795
796 #[inline]
802 pub fn revert_to(&self, version: &Frontiers) -> LoroResult<()> {
803 self.doc.revert_to(&version.into())
804 }
805
806 #[inline]
810 pub fn apply_diff(&self, diff: &DiffBatch) -> LoroResult<()> {
811 self.doc.apply_diff(diff.clone().into())
812 }
813
814 #[inline]
816 pub fn diff(&self, a: &Frontiers, b: &Frontiers) -> LoroResult<Arc<DiffBatch>> {
817 self.doc
818 .diff(&a.into(), &b.into())
819 .map(|x| Arc::new(x.into()))
820 }
821
822 pub fn has_container(&self, id: &ContainerID) -> bool {
827 self.doc.has_container(&id.into())
828 }
829
830 pub fn subscribe_first_commit_from_peer(
836 &self,
837 subscriber: Arc<dyn FirstCommitFromPeerCallback>,
838 ) -> Arc<Subscription> {
839 let subscriber: loro::FirstCommitFromPeerCallback = Box::new(move |e| {
840 subscriber.on_first_commit_from_peer(FirstCommitFromPeerPayload { peer: e.peer });
841 true
842 });
843 Arc::new(self.doc.subscribe_first_commit_from_peer(subscriber).into())
844 }
845
846 pub fn subscribe_pre_commit(&self, callback: Arc<dyn PreCommitCallback>) -> Arc<Subscription> {
851 let subscriber: loro::PreCommitCallback = Box::new(move |e| {
852 callback.on_pre_commit(PreCommitCallbackPayload {
853 change_meta: e.change_meta.clone().into(),
854 origin: e.origin.clone(),
855 modifier: Arc::new(ChangeModifier(e.modifier.clone())),
856 });
857 true
858 });
859 Arc::new(self.doc.subscribe_pre_commit(subscriber).into())
860 }
861
862 pub fn set_hide_empty_root_containers(&self, hide: bool) {
864 self.doc.set_hide_empty_root_containers(hide);
865 }
866
867 pub fn delete_root_container(&self, cid: ContainerID) {
875 self.doc.delete_root_container(cid.into());
876 }
877}
878
879pub trait ChangeAncestorsTraveler: Sync + Send {
880 fn travel(&self, change: ChangeMeta) -> bool;
881}
882
883impl Default for LoroDoc {
884 fn default() -> Self {
885 Self::new()
886 }
887}
888
889impl Deref for LoroDoc {
890 type Target = InnerLoroDoc;
891 fn deref(&self) -> &Self::Target {
892 &self.doc
893 }
894}
895
896pub struct ChangeMeta {
897 pub lamport: Lamport,
899 pub id: ID,
901 pub timestamp: Timestamp,
904 pub message: Option<String>,
906 pub deps: Arc<Frontiers>,
908 pub len: u32,
910}
911
912impl From<loro::ChangeMeta> for ChangeMeta {
913 fn from(value: loro::ChangeMeta) -> Self {
914 Self {
915 lamport: value.lamport,
916 id: value.id,
917 timestamp: value.timestamp,
918 message: value.message.map(|x| (*x).to_string()),
919 deps: Arc::new(value.deps.into()),
920 len: value.len as u32,
921 }
922 }
923}
924
925pub struct ImportBlobMetadata {
926 pub partial_start_vv: Arc<VersionVector>,
932 pub partial_end_vv: Arc<VersionVector>,
938 pub start_timestamp: i64,
939 pub start_frontiers: Arc<Frontiers>,
940 pub end_timestamp: i64,
941 pub change_num: u32,
942 pub mode: String,
943}
944
945impl From<loro::ImportBlobMetadata> for ImportBlobMetadata {
946 fn from(value: loro::ImportBlobMetadata) -> Self {
947 Self {
948 partial_start_vv: Arc::new(value.partial_start_vv.into()),
949 partial_end_vv: Arc::new(value.partial_end_vv.into()),
950 start_timestamp: value.start_timestamp,
951 start_frontiers: Arc::new(value.start_frontiers.into()),
952 end_timestamp: value.end_timestamp,
953 change_num: value.change_num,
954 mode: value.mode.to_string(),
955 }
956 }
957}
958
959pub struct CommitOptions {
960 pub origin: Option<String>,
961 pub immediate_renew: bool,
962 pub timestamp: Option<Timestamp>,
963 pub commit_msg: Option<String>,
964}
965
966impl From<CommitOptions> for loro::CommitOptions {
967 fn from(value: CommitOptions) -> Self {
968 loro::CommitOptions {
969 origin: value.origin.map(|x| x.into()),
970 immediate_renew: value.immediate_renew,
971 timestamp: value.timestamp,
972 commit_msg: value.commit_msg.map(|x| x.into()),
973 }
974 }
975}
976
977pub trait JsonSchemaLike {
978 fn to_json_schema(&self) -> LoroResult<JsonSchema>;
979}
980
981impl<T: TryInto<JsonSchema> + Clone> JsonSchemaLike for T {
982 fn to_json_schema(&self) -> LoroResult<JsonSchema> {
983 self.clone()
984 .try_into()
985 .map_err(|_| LoroError::InvalidJsonSchema)
986 }
987}
988
989pub trait JsonPathSubscriber: Sync + Send {
990 fn on_jsonpath_changed(&self);
991}
992
993pub trait LocalUpdateCallback: Sync + Send {
994 fn on_local_update(&self, update: Vec<u8>);
995}
996
997pub trait FirstCommitFromPeerCallback: Sync + Send {
998 fn on_first_commit_from_peer(&self, e: FirstCommitFromPeerPayload);
999}
1000
1001pub struct FirstCommitFromPeerPayload {
1002 pub peer: PeerID,
1003}
1004
1005pub trait PreCommitCallback: Sync + Send {
1006 fn on_pre_commit(&self, e: PreCommitCallbackPayload);
1007}
1008
1009pub struct PreCommitCallbackPayload {
1010 pub change_meta: ChangeMeta,
1011 pub origin: String,
1012 pub modifier: Arc<ChangeModifier>,
1013}
1014
1015pub struct ChangeModifier(loro::ChangeModifier);
1016
1017impl ChangeModifier {
1018 pub fn set_message(&self, msg: &str) {
1019 self.0.set_message(msg);
1020 }
1021 pub fn set_timestamp(&self, timestamp: Timestamp) {
1022 self.0.set_timestamp(timestamp);
1023 }
1024}
1025
1026pub trait Unsubscriber: Sync + Send {
1027 fn on_unsubscribe(&self);
1028}
1029
1030pub struct Subscription(pub(crate) Mutex<Option<loro::Subscription>>);
1033
1034impl Subscription {
1035 pub fn detach(self: Arc<Self>) {
1039 let s = self.0.lock().unwrap().take().unwrap();
1040 s.detach();
1041 }
1042
1043 pub fn unsubscribe(self: Arc<Self>) {
1045 let s = self.0.lock().unwrap().take().unwrap();
1046 s.unsubscribe();
1047 }
1048}
1049
1050impl std::fmt::Debug for Subscription {
1051 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1052 f.write_str("Subscription")
1053 }
1054}
1055
1056impl From<loro::Subscription> for Subscription {
1057 fn from(value: loro::Subscription) -> Self {
1058 Self(Mutex::new(Some(value)))
1059 }
1060}
1061
1062pub struct PosQueryResult {
1063 pub update: Option<Arc<Cursor>>,
1064 pub current: AbsolutePosition,
1065}
1066
1067pub struct ContainerPath {
1096 pub id: ContainerID,
1097 pub path: Index,
1098}
1099
1100pub struct ImportStatus {
1101 pub success: HashMap<u64, CounterSpan>,
1102 pub pending: Option<HashMap<u64, CounterSpan>>,
1103}
1104
1105impl From<loro::ImportStatus> for ImportStatus {
1106 fn from(value: loro::ImportStatus) -> Self {
1107 let a = &value.success;
1108 Self {
1109 success: vr_to_map(a),
1110 pending: value.pending.as_ref().map(vr_to_map),
1111 }
1112 }
1113}
1114
1115fn vr_to_map(a: &loro::VersionRange) -> HashMap<u64, CounterSpan> {
1116 a.iter()
1117 .map(|x| {
1118 (
1119 *x.0,
1120 CounterSpan {
1121 start: x.1 .0,
1122 end: x.1 .1,
1123 },
1124 )
1125 })
1126 .collect()
1127}
1128
1129pub struct FrontiersOrID {
1130 pub frontiers: Option<Arc<Frontiers>>,
1131 pub id: Option<ID>,
1132}