1use std::cmp::Ordering;
2use std::collections::{BTreeSet, HashMap, HashSet};
3use std::fmt::Debug;
4use std::num::NonZeroU64;
5use std::ops::RangeBounds;
6
7use itertools::Itertools;
8
9use crate::change_graph::ChangeGraph;
10use crate::columnar::Key as EncodedKey;
11use crate::cursor::{CursorPosition, MoveCursor, OpCursor};
12use crate::exid::ExId;
13use crate::iter::{Keys, ListRange, MapRange, Spans, Values};
14use crate::marks::{Mark, MarkAccumulator, MarkSet, MarkStateMachine};
15use crate::op_set::{OpSet, OpSetData, OpSetInternal};
16use crate::parents::Parents;
17use crate::patches::{Patch, PatchLog, TextRepresentation};
18use crate::query;
19use crate::read::ReadDocInternal;
20use crate::storage::{self, load, CompressConfig, VerificationMode};
21use crate::transaction::{
22 self, CommitOptions, Failure, Success, Transactable, Transaction, TransactionArgs,
23};
24use crate::types::{
25 ActorId, ChangeHash, Clock, ElemId, Export, Exportable, Key, ListEncoding, MarkData, ObjId,
26 ObjMeta, OpBuilder, OpId, OpIds, OpType, TextEncoding, Value,
27};
28use crate::{hydrate, ScalarValue};
29use crate::{AutomergeError, Change, Cursor, ObjType, Prop, ReadDoc};
30
31pub(crate) mod current_state;
32pub(crate) mod diff;
33
34#[cfg(test)]
35mod tests;
36
37#[derive(Debug, Clone, PartialEq)]
38pub(crate) enum Actor {
39 Unused(ActorId),
40 Cached(usize),
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum OnPartialLoad {
46 Ignore,
48 Error,
50}
51
52#[derive(Debug)]
54pub enum StringMigration {
55 NoMigration,
57 ConvertToText,
59}
60
61#[derive(Debug)]
62pub struct LoadOptions<'a> {
63 on_partial_load: OnPartialLoad,
64 verification_mode: VerificationMode,
65 string_migration: StringMigration,
66 patch_log: Option<&'a mut PatchLog>,
67 text_encoding: TextEncoding,
68}
69
70impl<'a> LoadOptions<'a> {
71 pub fn new() -> LoadOptions<'static> {
72 LoadOptions::default()
73 }
74
75 pub fn on_partial_load(self, on_partial_load: OnPartialLoad) -> Self {
79 Self {
80 on_partial_load,
81 ..self
82 }
83 }
84
85 pub fn verification_mode(self, verification_mode: VerificationMode) -> Self {
89 Self {
90 verification_mode,
91 ..self
92 }
93 }
94
95 pub fn patch_log(self, patch_log: &'a mut PatchLog) -> Self {
99 Self {
100 patch_log: Some(patch_log),
101 ..self
102 }
103 }
104
105 pub fn migrate_strings(self, migration: StringMigration) -> Self {
123 Self {
124 string_migration: migration,
125 ..self
126 }
127 }
128
129 pub fn text_encoding(self, encoding: TextEncoding) -> Self {
130 Self {
131 text_encoding: encoding,
132 ..self
133 }
134 }
135}
136
137impl std::default::Default for LoadOptions<'static> {
138 fn default() -> Self {
139 Self {
140 on_partial_load: OnPartialLoad::Error,
141 verification_mode: VerificationMode::Check,
142 patch_log: None,
143 string_migration: StringMigration::NoMigration,
144 text_encoding: TextEncoding::default(),
145 }
146 }
147}
148
149#[derive(Debug, Clone)]
178pub struct Automerge {
179 queue: Vec<Change>,
181 history: Vec<Change>,
183 history_index: HashMap<ChangeHash, usize>,
185 change_graph: ChangeGraph,
187 states: HashMap<usize, Vec<usize>>,
189 deps: HashSet<ChangeHash>,
191 ops: OpSet,
193 actor: Actor,
195 max_op: u64,
197 text_encoding: TextEncoding,
199}
200
201impl Automerge {
202 pub fn new() -> Self {
204 Automerge {
205 queue: vec![],
206 history: vec![],
207 history_index: HashMap::new(),
208 change_graph: ChangeGraph::new(),
209 states: HashMap::new(),
210 ops: OpSetInternal::new(TextEncoding::default()),
211 deps: Default::default(),
212 actor: Actor::Unused(ActorId::random()),
213 max_op: 0,
214 text_encoding: TextEncoding::default(),
215 }
216 }
217
218 pub fn new_with_encoding(encoding: TextEncoding) -> Self {
219 Automerge {
220 queue: vec![],
221 history: vec![],
222 history_index: HashMap::new(),
223 change_graph: ChangeGraph::new(),
224 states: HashMap::new(),
225 ops: OpSetInternal::new(encoding),
226 deps: Default::default(),
227 actor: Actor::Unused(ActorId::random()),
228 max_op: 0,
229 text_encoding: encoding,
230 }
231 }
232
233 pub(crate) fn ops_mut(&mut self) -> &mut OpSet {
234 &mut self.ops
235 }
236
237 pub(crate) fn ops(&self) -> &OpSet {
238 &self.ops
239 }
240
241 pub(crate) fn osd(&self) -> &OpSetData {
242 &self.ops.osd
243 }
244
245 pub fn is_empty(&self) -> bool {
247 self.history.is_empty() && self.queue.is_empty()
248 }
249
250 pub(crate) fn actor_id(&self) -> ActorId {
251 match &self.actor {
252 Actor::Unused(id) => id.clone(),
253 Actor::Cached(idx) => self.ops.osd.actors[*idx].clone(),
254 }
255 }
256
257 pub fn with_actor(mut self, actor: ActorId) -> Self {
259 self.actor = Actor::Unused(actor);
260 self
261 }
262
263 pub fn set_actor(&mut self, actor: ActorId) -> &mut Self {
265 self.actor = Actor::Unused(actor);
266 self
267 }
268
269 pub fn get_actor(&self) -> &ActorId {
271 match &self.actor {
272 Actor::Unused(actor) => actor,
273 Actor::Cached(index) => self.ops.osd.actors.get(*index),
274 }
275 }
276
277 pub(crate) fn get_actor_index(&mut self) -> usize {
278 match &mut self.actor {
279 Actor::Unused(actor) => {
280 let index = self
281 .ops
282 .osd
283 .actors
284 .cache(std::mem::replace(actor, ActorId::from(&[][..])));
285 self.actor = Actor::Cached(index);
286 index
287 }
288 Actor::Cached(index) => *index,
289 }
290 }
291
292 pub fn transaction(&mut self) -> Transaction<'_> {
294 let args = self.transaction_args(None);
295 Transaction::new(
296 self,
297 args,
298 PatchLog::inactive(TextRepresentation::String(self.text_encoding)),
299 )
300 }
301
302 pub fn transaction_log_patches(&mut self, patch_log: PatchLog) -> Transaction<'_> {
304 let args = self.transaction_args(None);
305 Transaction::new(self, args, patch_log)
306 }
307
308 pub fn transaction_at(&mut self, patch_log: PatchLog, heads: &[ChangeHash]) -> Transaction<'_> {
310 let args = self.transaction_args(Some(heads));
311 Transaction::new(self, args, patch_log)
312 }
313
314 pub(crate) fn transaction_args(&mut self, heads: Option<&[ChangeHash]>) -> TransactionArgs {
315 let actor_index;
316 let seq;
317 let mut deps;
318 let scope;
319 match heads {
320 Some(heads) => {
321 deps = heads.to_vec();
322 let isolation = self.isolate_actor(heads);
323 actor_index = isolation.actor_index;
324 seq = isolation.seq;
325 scope = Some(isolation.clock);
326 }
327 None => {
328 actor_index = self.get_actor_index();
329 seq = self.states.get(&actor_index).map_or(0, |v| v.len()) as u64 + 1;
330 deps = self.get_heads();
331 scope = None;
332 if seq > 1 {
333 let last_hash = self.get_hash(actor_index, seq - 1).unwrap();
334 if !deps.contains(&last_hash) {
335 deps.push(last_hash);
336 }
337 }
338 }
339 }
340
341 let start_op = NonZeroU64::new(self.max_op + 1).unwrap();
343 let idx_range = self.osd().start_range();
344 TransactionArgs {
345 actor_index,
346 seq,
347 start_op,
348 idx_range,
349 deps,
350 scope,
351 text_encoding: self.text_encoding,
352 }
353 }
354
355 pub fn transact<F, O, E>(&mut self, f: F) -> transaction::Result<O, E>
358 where
359 F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
360 {
361 self.transact_with_impl(None::<&dyn Fn(&O) -> CommitOptions>, f)
362 }
363
364 pub fn transact_with<F, O, E, C>(&mut self, c: C, f: F) -> transaction::Result<O, E>
366 where
367 F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
368 C: FnOnce(&O) -> CommitOptions,
369 {
370 self.transact_with_impl(Some(c), f)
372 }
373
374 fn transact_with_impl<F, O, E, C>(&mut self, c: Option<C>, f: F) -> transaction::Result<O, E>
375 where
376 F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
377 C: FnOnce(&O) -> CommitOptions,
378 {
379 let mut tx = self.transaction();
380 let result = f(&mut tx);
381 match result {
382 Ok(result) => {
383 let (hash, patch_log) = if let Some(c) = c {
384 let commit_options = c(&result);
385 tx.commit_with(commit_options)
386 } else {
387 tx.commit()
388 };
389 Ok(Success {
390 result,
391 hash,
392 patch_log,
393 })
394 }
395 Err(error) => Err(Failure {
396 error,
397 cancelled: tx.rollback(),
398 }),
399 }
400 }
401
402 pub fn transact_and_log_patches<F, O, E>(
407 &mut self,
408 text_rep: TextRepresentation,
409 f: F,
410 ) -> transaction::Result<O, E>
411 where
412 F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
413 {
414 self.transact_and_log_patches_with_impl(text_rep, None::<&dyn Fn(&O) -> CommitOptions>, f)
415 }
416
417 pub fn transact_and_log_patches_with<F, O, E, C>(
419 &mut self,
420 text_rep: TextRepresentation,
421 c: C,
422 f: F,
423 ) -> transaction::Result<O, E>
424 where
425 F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
426 C: FnOnce(&O) -> CommitOptions,
427 {
428 self.transact_and_log_patches_with_impl(text_rep, Some(c), f)
429 }
430
431 fn transact_and_log_patches_with_impl<F, O, E, C>(
432 &mut self,
433 text_rep: TextRepresentation,
434 c: Option<C>,
435 f: F,
436 ) -> transaction::Result<O, E>
437 where
438 F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
439 C: FnOnce(&O) -> CommitOptions,
440 {
441 let mut tx = self.transaction_log_patches(PatchLog::active(text_rep));
442 let result = f(&mut tx);
443 match result {
444 Ok(result) => {
445 let (hash, history) = if let Some(c) = c {
446 let commit_options = c(&result);
447 tx.commit_with(commit_options)
448 } else {
449 tx.commit()
450 };
451 Ok(Success {
452 result,
453 hash,
454 patch_log: history,
455 })
456 }
457 Err(error) => Err(Failure {
458 error,
459 cancelled: tx.rollback(),
460 }),
461 }
462 }
463
464 pub fn empty_commit(&mut self, opts: CommitOptions) -> ChangeHash {
469 let args = self.transaction_args(None);
470 Transaction::empty(self, args, opts)
471 }
472
473 pub fn fork(&self) -> Self {
477 let mut f = self.clone();
478 f.set_actor(ActorId::random());
479 f
480 }
481
482 pub fn fork_at(&self, heads: &[ChangeHash]) -> Result<Self, AutomergeError> {
486 let mut seen = heads.iter().cloned().collect::<HashSet<_>>();
487 let mut heads = heads.to_vec();
488 let mut changes = vec![];
489 while let Some(hash) = heads.pop() {
490 if let Some(idx) = self.history_index.get(&hash) {
491 let change = &self.history[*idx];
492 for dep in change.deps() {
493 if !seen.contains(dep) {
494 heads.push(*dep);
495 }
496 }
497 changes.push(change);
498 seen.insert(hash);
499 } else {
500 return Err(AutomergeError::InvalidHash(hash));
501 }
502 }
503 let mut f = Self::new();
504 f.set_actor(ActorId::random());
505 f.apply_changes(changes.into_iter().rev().cloned())?;
506 Ok(f)
507 }
508
509 pub(crate) fn exid_to_opid(&self, id: &ExId) -> Result<OpId, AutomergeError> {
510 match id {
511 ExId::Root => Ok(OpId::new(0, 0)),
512 ExId::Id(ctr, actor, idx) => {
513 let opid = if self.ops.osd.actors.cache.get(*idx) == Some(actor) {
514 OpId::new(*ctr, *idx)
515 } else if let Some(backup_idx) = self.ops.osd.actors.lookup(actor) {
516 OpId::new(*ctr, backup_idx)
517 } else {
518 return Err(AutomergeError::InvalidObjId(id.to_string()));
519 };
520 Ok(opid)
521 }
522 }
523 }
524
525 pub(crate) fn get_obj_meta(&self, id: ObjId) -> Result<ObjMeta, AutomergeError> {
526 if id.is_root() {
527 Ok(ObjMeta::root())
528 } else if let Some(typ) = self.ops.obj_type(&id) {
529 Ok(ObjMeta { id, typ })
530 } else {
531 Err(AutomergeError::NotAnObject)
532 }
533 }
534
535 pub(crate) fn op_cursor_to_opid(
536 &self,
537 cursor: &OpCursor,
538 clock: Option<&Clock>,
539 ) -> Result<OpId, AutomergeError> {
540 if let Some(idx) = self.ops.osd.actors.lookup(&cursor.actor) {
541 let opid = OpId::new(cursor.ctr, idx);
542 match clock {
543 Some(clock) if !clock.covers(&opid) => {
544 Err(AutomergeError::InvalidCursor(Cursor::Op(cursor.clone())))
545 }
546 _ => Ok(opid),
547 }
548 } else {
549 Err(AutomergeError::InvalidCursor(Cursor::Op(cursor.clone())))
550 }
551 }
552
553 pub(crate) fn exid_to_obj(&self, id: &ExId) -> Result<ObjMeta, AutomergeError> {
554 let opid = self.exid_to_opid(id)?;
555 let obj = ObjId(opid);
556 self.get_obj_meta(obj)
557 }
558
559 pub(crate) fn id_to_exid(&self, id: OpId) -> ExId {
560 self.ops.id_to_exid(id)
561 }
562
563 pub fn load(data: &[u8]) -> Result<Self, AutomergeError> {
565 Self::load_with_options(data, Default::default())
566 }
567
568 pub fn load_unverified_heads(data: &[u8]) -> Result<Self, AutomergeError> {
572 Self::load_with_options(
573 data,
574 LoadOptions {
575 verification_mode: VerificationMode::DontCheck,
576 ..Default::default()
577 },
578 )
579 }
580
581 #[deprecated(since = "0.5.2", note = "Use `load_with_options` instead")]
591 #[tracing::instrument(skip(data), err)]
592 pub fn load_with(
593 data: &[u8],
594 on_error: OnPartialLoad,
595 mode: VerificationMode,
596 patch_log: &mut PatchLog,
597 ) -> Result<Self, AutomergeError> {
598 Self::load_with_options(
599 data,
600 LoadOptions::new()
601 .on_partial_load(on_error)
602 .verification_mode(mode)
603 .patch_log(patch_log),
604 )
605 }
606
607 #[tracing::instrument(skip(data), err)]
613 pub fn load_with_options<'a, 'b>(
614 data: &'a [u8],
615 options: LoadOptions<'b>,
616 ) -> Result<Self, AutomergeError> {
617 if data.is_empty() {
618 tracing::trace!("no data, initializing empty document");
619 return Ok(Self::new());
620 }
621 tracing::trace!("loading first chunk");
622 let (remaining, first_chunk) = storage::Chunk::parse(storage::parse::Input::new(data))
623 .map_err(|e| load::Error::Parse(Box::new(e)))?;
624 if !first_chunk.checksum_valid() {
625 return Err(load::Error::BadChecksum.into());
626 }
627
628 let mut change: Option<Change> = None;
629 let mut first_chunk_was_doc = false;
630 let mut am = match first_chunk {
631 storage::Chunk::Document(d) => {
632 tracing::trace!("first chunk is document chunk, inflating");
633 first_chunk_was_doc = true;
634 reconstruct_document(&d, options.verification_mode, options.text_encoding)?
635 }
636 storage::Chunk::Change(stored_change) => {
637 tracing::trace!("first chunk is change chunk");
638 change = Some(
639 Change::new_from_unverified(stored_change.into_owned(), None)
640 .map_err(|e| load::Error::InvalidChangeColumns(Box::new(e)))?,
641 );
642 Self::new()
643 }
644 storage::Chunk::CompressedChange(stored_change, compressed) => {
645 tracing::trace!("first chunk is compressed change");
646 change = Some(
647 Change::new_from_unverified(
648 stored_change.into_owned(),
649 Some(compressed.into_owned()),
650 )
651 .map_err(|e| load::Error::InvalidChangeColumns(Box::new(e)))?,
652 );
653 Self::new()
654 }
655 };
656 tracing::trace!("loading change chunks");
657 match load::load_changes(remaining.reset(), options.text_encoding) {
658 load::LoadedChanges::Complete(c) => {
659 am.apply_changes(change.into_iter().chain(c))?;
660 if !am.queue.is_empty()
663 && !first_chunk_was_doc
664 && options.on_partial_load == OnPartialLoad::Error
665 {
666 return Err(AutomergeError::MissingDeps);
667 }
668 }
669 load::LoadedChanges::Partial { error, .. } => {
670 if options.on_partial_load == OnPartialLoad::Error {
671 return Err(error.into());
672 }
673 }
674 }
675 if let StringMigration::ConvertToText = options.string_migration {
676 am.convert_scalar_strings_to_text()?;
677 }
678 if let Some(patch_log) = options.patch_log {
679 if patch_log.is_active() {
680 current_state::log_current_state_patches(&am, patch_log);
681 }
682 }
683 Ok(am)
684 }
685
686 pub fn make_patches(&self, patch_log: &mut PatchLog) -> Vec<Patch> {
690 patch_log.make_patches(self)
691 }
692
693 pub fn current_state(&self, text_rep: TextRepresentation) -> Vec<Patch> {
699 let mut patch_log = PatchLog::active(text_rep);
700 current_state::log_current_state_patches(self, &mut patch_log);
701 patch_log.make_patches(self)
702 }
703
704 pub fn load_incremental(&mut self, data: &[u8]) -> Result<usize, AutomergeError> {
712 self.load_incremental_log_patches(
713 data,
714 &mut PatchLog::inactive(TextRepresentation::String(self.text_encoding)),
715 )
716 }
717
718 pub fn load_incremental_log_patches(
721 &mut self,
722 data: &[u8],
723 patch_log: &mut PatchLog,
724 ) -> Result<usize, AutomergeError> {
725 if self.is_empty() {
726 let mut doc = Self::load_with_options(
727 data,
728 LoadOptions::new()
729 .on_partial_load(OnPartialLoad::Ignore)
730 .verification_mode(VerificationMode::Check),
731 )?;
732 doc = doc.with_actor(self.actor_id());
733 if patch_log.is_active() {
734 current_state::log_current_state_patches(&doc, patch_log);
735 }
736 *self = doc;
737 return Ok(self.ops.len());
738 }
739 let changes = match load::load_changes(storage::parse::Input::new(data), self.text_encoding)
740 {
741 load::LoadedChanges::Complete(c) => c,
742 load::LoadedChanges::Partial { error, loaded, .. } => {
743 tracing::warn!(successful_chunks=loaded.len(), err=?error, "partial load");
744 loaded
745 }
746 };
747 let start = self.ops.len();
748 self.apply_changes_log_patches(changes, patch_log)?;
749 let delta = self.ops.len() - start;
750 Ok(delta)
751 }
752
753 fn duplicate_seq(&self, change: &Change) -> bool {
754 let mut dup = false;
755 if let Some(actor_index) = self.ops.osd.actors.lookup(change.actor_id()) {
756 if let Some(s) = self.states.get(&actor_index) {
757 dup = s.len() >= change.seq() as usize;
758 }
759 }
760 dup
761 }
762
763 pub fn apply_changes(
768 &mut self,
769 changes: impl IntoIterator<Item = Change>,
770 ) -> Result<(), AutomergeError> {
771 self.apply_changes_log_patches(
772 changes,
773 &mut PatchLog::inactive(TextRepresentation::String(self.text_encoding)),
774 )
775 }
776
777 pub fn apply_changes_log_patches<I: IntoIterator<Item = Change>>(
780 &mut self,
781 changes: I,
782 patch_log: &mut PatchLog,
783 ) -> Result<(), AutomergeError> {
784 for c in changes {
789 if !self.history_index.contains_key(&c.hash()) {
790 if self.duplicate_seq(&c) {
791 return Err(AutomergeError::DuplicateSeqNumber(
792 c.seq(),
793 c.actor_id().clone(),
794 ));
795 }
796 if self.is_causally_ready(&c) {
797 self.apply_change(c, patch_log)?;
798 } else {
799 self.queue.push(c);
800 }
801 }
802 }
803 while let Some(c) = self.pop_next_causally_ready_change() {
804 if !self.history_index.contains_key(&c.hash()) {
805 self.apply_change(c, patch_log)?;
806 }
807 }
808 Ok(())
809 }
810
811 fn apply_change(
812 &mut self,
813 change: Change,
814 patch_log: &mut PatchLog,
815 ) -> Result<(), AutomergeError> {
816 let ops = self.import_ops(&change);
817 self.update_history(change, ops.len());
818 for (obj, op, pred) in ops {
819 self.insert_op(&obj, op, &pred, patch_log)?;
820 }
821 Ok(())
822 }
823
824 fn is_causally_ready(&self, change: &Change) -> bool {
825 change
826 .deps()
827 .iter()
828 .all(|d| self.history_index.contains_key(d))
829 }
830
831 fn pop_next_causally_ready_change(&mut self) -> Option<Change> {
832 let mut index = 0;
833 while index < self.queue.len() {
834 if self.is_causally_ready(&self.queue[index]) {
835 return Some(self.queue.swap_remove(index));
836 }
837 index += 1;
838 }
839 None
840 }
841
842 fn import_ops(&mut self, change: &Change) -> Vec<(ObjId, OpBuilder, OpIds)> {
843 let actor = self.ops.osd.actors.cache(change.actor_id().clone());
844 let mut actors = Vec::with_capacity(change.other_actor_ids().len() + 1);
845 actors.push(actor);
846 actors.extend(
847 change
848 .other_actor_ids()
849 .iter()
850 .map(|a| self.ops.osd.actors.cache(a.clone()))
851 .collect::<Vec<_>>(),
852 );
853 change
854 .iter_ops()
855 .enumerate()
856 .map(|(i, c)| {
857 let id = OpId::new(change.start_op().get() + i as u64, actor);
858 let key = match &c.key {
859 EncodedKey::Prop(n) => Key::Map(self.ops.osd.props.cache(n.to_string())),
860 EncodedKey::Elem(e) if e.is_head() => Key::Seq(ElemId::head()),
861 EncodedKey::Elem(ElemId(o)) => {
862 Key::Seq(ElemId(OpId::new(o.counter(), actors[o.actor()])))
863 }
864 };
865 let obj = if c.obj.is_root() {
866 ObjId::root()
867 } else {
868 ObjId(OpId::new(
869 c.obj.opid().counter(),
870 actors[c.obj.opid().actor()],
871 ))
872 };
873 let pred = c
874 .pred
875 .iter()
876 .map(|p| OpId::new(p.counter(), actors[p.actor()]));
877 let pred = self.ops.osd.sorted_opids(pred);
878 (
879 obj,
880 OpBuilder {
881 id,
882 action: OpType::from_action_and_value(
883 c.action,
884 c.val,
885 c.mark_name,
886 c.expand,
887 ),
888 key,
889 insert: c.insert,
890 },
891 pred,
892 )
893 })
894 .collect()
895 }
896
897 pub fn merge(&mut self, other: &mut Self) -> Result<Vec<ChangeHash>, AutomergeError> {
899 self.merge_and_log_patches(
900 other,
901 &mut PatchLog::inactive(TextRepresentation::String(self.text_encoding)),
902 )
903 }
904
905 pub fn merge_and_log_patches(
908 &mut self,
909 other: &mut Self,
910 patch_log: &mut PatchLog,
911 ) -> Result<Vec<ChangeHash>, AutomergeError> {
912 let changes = self
914 .get_changes_added(other)
915 .into_iter()
916 .cloned()
917 .collect::<Vec<_>>();
918 tracing::trace!(changes=?changes.iter().map(|c| c.hash()).collect::<Vec<_>>(), "merging new changes");
919 self.apply_changes_log_patches(changes, patch_log)?;
920 Ok(self.get_heads())
921 }
922
923 pub fn save_with_options(&self, options: SaveOptions) -> Vec<u8> {
925 let heads = self.get_heads();
926 let c = self.history.iter();
927 let compress = if options.deflate {
928 None
929 } else {
930 Some(CompressConfig::None)
931 };
932 let mut bytes = crate::storage::save::save_document(
933 c,
934 self.ops.iter().map(|(objid, _, op)| (objid, op)),
935 &self.ops.osd.actors,
936 &self.ops.osd.props,
937 &heads,
938 compress,
939 );
940 if options.retain_orphans {
941 for orphaned in self.queue.iter() {
942 bytes.extend(orphaned.raw_bytes());
943 }
944 }
945 bytes
946 }
947
948 pub fn save(&self) -> Vec<u8> {
950 self.save_with_options(SaveOptions::default())
951 }
952
953 pub fn save_and_verify(&self) -> Result<Vec<u8>, AutomergeError> {
955 let bytes = self.save();
956 Self::load(&bytes)?;
957 Ok(bytes)
958 }
959
960 pub fn save_nocompress(&self) -> Vec<u8> {
962 self.save_with_options(SaveOptions {
963 deflate: false,
964 ..Default::default()
965 })
966 }
967
968 pub fn save_after(&self, heads: &[ChangeHash]) -> Vec<u8> {
975 let changes = self.get_changes(heads);
976 let mut bytes = vec![];
977 for c in changes {
978 bytes.extend(c.raw_bytes());
979 }
980 bytes
981 }
982
983 pub(crate) fn filter_changes(
987 &self,
988 heads: &[ChangeHash],
989 changes: &mut BTreeSet<ChangeHash>,
990 ) -> Result<(), AutomergeError> {
991 let heads = heads
992 .iter()
993 .filter(|hash| self.history_index.contains_key(hash))
994 .copied()
995 .collect::<Vec<_>>();
996
997 self.change_graph.remove_ancestors(changes, &heads);
998
999 Ok(())
1000 }
1001
1002 fn get_changes_clock(&self, have_deps: &[ChangeHash]) -> Vec<&Change> {
1004 let clock = self.clock_at(have_deps);
1006
1007 let mut change_indexes: Vec<usize> = Vec::new();
1010 for (actor_index, actor_changes) in &self.states {
1012 if let Some(clock_data) = clock.get_for_actor(actor_index) {
1013 change_indexes.extend(&actor_changes[clock_data.seq as usize..]);
1016 } else {
1017 change_indexes.extend(&actor_changes[..]);
1018 }
1019 }
1020
1021 change_indexes.sort_unstable();
1023
1024 change_indexes
1025 .into_iter()
1026 .map(|i| &self.history[i])
1027 .collect()
1028 }
1029
1030 pub fn get_last_local_change(&self) -> Option<&Change> {
1032 return self
1033 .history
1034 .iter()
1035 .rev()
1036 .find(|c| c.actor_id() == self.get_actor());
1037 }
1038
1039 pub(crate) fn clock_at(&self, heads: &[ChangeHash]) -> Clock {
1040 self.change_graph.clock_for_heads(heads)
1041 }
1042
1043 fn get_isolated_actor_index(&mut self, level: usize) -> usize {
1044 if level == 0 {
1045 self.get_actor_index()
1046 } else {
1047 let base_actor = self.get_actor();
1048 let new_actor = base_actor.with_concurrency(level);
1049 self.ops.osd.actors.cache(new_actor)
1050 }
1051 }
1052
1053 pub(crate) fn isolate_actor(&mut self, heads: &[ChangeHash]) -> Isolation {
1054 let mut clock = self.clock_at(heads);
1055 let mut actor_index = self.get_isolated_actor_index(0);
1056
1057 for i in 1.. {
1058 let max_op = self.max_op_for_actor(actor_index);
1059 if max_op == 0 || clock.covers(&OpId::new(max_op, actor_index)) {
1060 clock.isolate(actor_index);
1061 break;
1062 }
1063 actor_index = self.get_isolated_actor_index(i);
1064 }
1065
1066 let seq = self.states.get(&actor_index).map_or(0, |v| v.len()) as u64 + 1;
1067
1068 Isolation {
1069 actor_index,
1070 seq,
1071 clock,
1072 }
1073 }
1074
1075 fn get_hash(&self, actor: usize, seq: u64) -> Result<ChangeHash, AutomergeError> {
1076 self.states
1077 .get(&actor)
1078 .and_then(|v| v.get(seq as usize - 1))
1079 .and_then(|&i| self.history.get(i))
1080 .map(|c| c.hash())
1081 .ok_or(AutomergeError::InvalidSeq(seq))
1082 }
1083
1084 fn max_op_for_actor(&mut self, actor_index: usize) -> u64 {
1085 self.states
1086 .get(&actor_index)
1087 .and_then(|s| s.last())
1088 .and_then(|index| self.history.get(*index))
1089 .map(|change| change.max_op())
1090 .unwrap_or(0)
1091 }
1092
1093 pub(crate) fn update_history(&mut self, change: Change, num_ops: usize) -> usize {
1094 self.max_op = std::cmp::max(self.max_op, change.start_op().get() + num_ops as u64 - 1);
1095
1096 self.update_deps(&change);
1097
1098 let history_index = self.history.len();
1099
1100 let actor_index = self.ops.osd.actors.cache(change.actor_id().clone());
1101 self.states
1102 .entry(actor_index)
1103 .or_default()
1104 .push(history_index);
1105
1106 self.history_index.insert(change.hash(), history_index);
1107 self.change_graph
1108 .add_change(&change, actor_index)
1109 .expect("Change's deps should already be in the document");
1110
1111 self.history.push(change);
1112
1113 history_index
1114 }
1115
1116 fn update_deps(&mut self, change: &Change) {
1117 for d in change.deps() {
1118 self.deps.remove(d);
1119 }
1120 self.deps.insert(change.hash());
1121 }
1122
1123 #[doc(hidden)]
1124 pub fn import(&self, s: &str) -> Result<(ExId, ObjType), AutomergeError> {
1125 let obj = self.import_obj(s)?;
1126 if obj == ExId::Root {
1127 Ok((ExId::Root, ObjType::Map))
1128 } else {
1129 let obj_type = self
1130 .object_type(&obj)
1131 .map_err(|_| AutomergeError::InvalidObjId(s.to_owned()))?;
1132 Ok((obj, obj_type))
1133 }
1134 }
1135
1136 #[doc(hidden)]
1137 pub fn import_obj(&self, s: &str) -> Result<ExId, AutomergeError> {
1138 if s == "_root" {
1139 Ok(ExId::Root)
1140 } else {
1141 let n = s
1142 .find('@')
1143 .ok_or_else(|| AutomergeError::InvalidObjIdFormat(s.to_owned()))?;
1144 let counter = s[0..n]
1145 .parse()
1146 .map_err(|_| AutomergeError::InvalidObjIdFormat(s.to_owned()))?;
1147 let actor = ActorId::from(hex::decode(&s[(n + 1)..]).unwrap());
1148 let actor = self
1149 .ops
1150 .osd
1151 .actors
1152 .lookup(&actor)
1153 .ok_or_else(|| AutomergeError::InvalidObjId(s.to_owned()))?;
1154 let obj = ExId::Id(counter, self.ops.osd.actors.cache[actor].clone(), actor);
1155 Ok(obj)
1156 }
1157 }
1158
1159 pub(crate) fn to_short_string<E: Exportable>(&self, id: E) -> String {
1160 match id.export() {
1161 Export::Id(id) => {
1162 let mut actor = self.ops.osd.actors[id.actor()].to_string();
1163 actor.truncate(6);
1164 format!("{}@{}", id.counter(), actor)
1165 }
1166 Export::Prop(index) => self.ops.osd.props[index].clone(),
1167 Export::Special(s) => s,
1168 }
1169 }
1170
1171 pub fn dump(&self) {
1172 log!(
1173 " {:12} {:3} {:12} {:12} {:12} {:12} {:12}",
1174 "id",
1175 "ins",
1176 "obj",
1177 "key",
1178 "value",
1179 "pred",
1180 "succ"
1181 );
1182 for (obj, _, op) in self.ops.iter() {
1183 let id = self.to_short_string(*op.id());
1184 let obj = self.to_short_string(obj);
1185 let key = match *op.key() {
1186 Key::Map(n) => self.ops.osd.props[n].clone(),
1187 Key::Seq(n) => self.to_short_string(n),
1188 };
1189 let value: String = match op.action() {
1190 OpType::Put(value) => format!("{}", value),
1191 OpType::Make(obj) => format!("make({})", obj),
1192 OpType::Increment(obj) => format!("inc({})", obj),
1193 OpType::Delete => format!("del{}", 0),
1194 OpType::MarkBegin(_, MarkData { name, value }) => {
1195 format!("mark({},{})", name, value)
1196 }
1197 OpType::MarkEnd(_) => "/mark".to_string(),
1198 };
1199 let pred: Vec<_> = op.pred().map(|op| self.to_short_string(*op.id())).collect();
1200 let succ: Vec<_> = op.succ().map(|op| self.to_short_string(*op.id())).collect();
1201 let insert = match op.insert() {
1202 true => "t",
1203 false => "f",
1204 };
1205 log!(
1206 " {:12} {:3} {:12} {:12} {:12} {:12?} {:12?}",
1207 id,
1208 insert,
1209 obj,
1210 key,
1211 value,
1212 pred,
1213 succ
1214 );
1215 }
1216 }
1217
1218 #[cfg(feature = "optree-visualisation")]
1225 pub fn visualise_optree(&self, objects: Option<Vec<ExId>>) -> String {
1226 let objects = objects.map(|os| {
1227 os.iter()
1228 .filter_map(|o| self.exid_to_obj(o).ok())
1229 .map(|o| o.id)
1230 .collect()
1231 });
1232 self.ops.visualise(objects)
1233 }
1234
1235 pub(crate) fn insert_op(
1236 &mut self,
1237 obj: &ObjId,
1238 op: OpBuilder,
1239 pred: &OpIds,
1240 patch_log: &mut PatchLog,
1241 ) -> Result<(), AutomergeError> {
1242 let is_delete = op.is_delete();
1243 let idx = self.ops.load(*obj, op);
1244 let op = idx.as_op(&self.ops.osd);
1245
1246 let (pos, succ) = if patch_log.is_active() {
1247 let obj = self.get_obj_meta(*obj)?;
1248 let found = self.ops.find_op_with_patch_log(
1249 &obj,
1250 patch_log.text_rep().encoding(obj.typ),
1251 op,
1252 pred,
1253 );
1254 found.log_patches(&obj, op, pred, self, patch_log);
1255 (found.pos, found.succ)
1256 } else {
1257 let found = self.ops.find_op_without_patch_log(obj, op, pred);
1258 (found.pos, found.succ)
1259 };
1260
1261 self.ops.add_succ(obj, &succ, idx);
1262
1263 if !is_delete {
1264 self.ops.insert(pos, obj, idx);
1265 }
1266 Ok(())
1267 }
1268
1269 pub fn diff(
1273 &self,
1274 before_heads: &[ChangeHash],
1275 after_heads: &[ChangeHash],
1276 text_rep: TextRepresentation,
1277 ) -> Vec<Patch> {
1278 let before = self.clock_at(before_heads);
1279 let after = self.clock_at(after_heads);
1280 let mut patch_log = PatchLog::active(text_rep);
1281 diff::log_diff(self, &before, &after, &mut patch_log);
1282 patch_log.heads = Some(after_heads.to_vec());
1283 patch_log.make_patches(self)
1284 }
1285
1286 pub fn get_heads(&self) -> Vec<ChangeHash> {
1288 let mut deps: Vec<_> = self.deps.iter().copied().collect();
1289 deps.sort_unstable();
1290 deps
1291 }
1292
1293 pub fn get_changes(&self, have_deps: &[ChangeHash]) -> Vec<&Change> {
1294 self.get_changes_clock(have_deps)
1295 }
1296
1297 pub fn get_changes_added<'a>(&self, other: &'a Self) -> Vec<&'a Change> {
1299 let mut stack: Vec<_> = other.get_heads();
1302 tracing::trace!(their_heads=?stack, "finding changes to merge");
1303 let mut seen_hashes = HashSet::new();
1304 let mut added_change_hashes = Vec::new();
1305 while let Some(hash) = stack.pop() {
1306 if !seen_hashes.contains(&hash) && self.get_change_by_hash(&hash).is_none() {
1307 seen_hashes.insert(hash);
1308 added_change_hashes.push(hash);
1309 if let Some(change) = other.get_change_by_hash(&hash) {
1310 stack.extend(change.deps());
1311 }
1312 }
1313 }
1314 added_change_hashes.reverse();
1317 added_change_hashes
1318 .into_iter()
1319 .filter_map(|h| other.get_change_by_hash(&h))
1320 .collect()
1321 }
1322
1323 pub fn hash_for_opid(&self, exid: &ExId) -> Option<ChangeHash> {
1329 match exid {
1330 ExId::Root => None,
1331 ExId::Id(..) => {
1332 let opid = self.exid_to_opid(exid).ok()?;
1333 let actor_indices = self.states.get(&opid.actor())?;
1334 let change_index_index = actor_indices
1335 .binary_search_by(|change_index| {
1336 let change = self
1337 .history
1338 .get(*change_index)
1339 .expect("State index should refer to a valid change");
1340 let start = change.start_op().get();
1341 let len = change.len() as u64;
1342 if opid.counter() < start {
1343 Ordering::Greater
1344 } else if start + len <= opid.counter() {
1345 Ordering::Less
1346 } else {
1347 Ordering::Equal
1348 }
1349 })
1350 .ok()?;
1351 let change_index = actor_indices.get(change_index_index).unwrap();
1352 Some(self.history.get(*change_index).unwrap().hash())
1353 }
1354 }
1355 }
1356
1357 fn calculate_marks(
1358 &self,
1359 obj: &ExId,
1360 clock: Option<Clock>,
1361 ) -> Result<Vec<Mark<'_>>, AutomergeError> {
1362 let obj = self.exid_to_obj(obj.as_ref())?;
1363 let ops_by_key = self.ops().iter_ops(&obj.id).chunk_by(|o| o.elemid_or_key());
1364 let mut index = 0;
1365 let mut marks = MarkStateMachine::default();
1366 let mut acc = MarkAccumulator::default();
1367 let mut last_marks = None;
1368 let mut mark_len = 0;
1369 let mut mark_index = 0;
1370 for (_key, key_ops) in ops_by_key.into_iter() {
1371 if let Some(o) = key_ops.filter(|o| o.visible_or_mark(clock.as_ref())).last() {
1372 match o.action() {
1373 OpType::Make(_) | OpType::Put(_) => {
1374 let len = o.width(
1375 TextRepresentation::String(self.text_encoding).encoding(obj.typ),
1376 );
1377 if last_marks.as_ref() != marks.current() {
1378 match last_marks.as_ref() {
1379 Some(m) if mark_len > 0 => acc.add(mark_index, mark_len, m),
1380 _ => (),
1381 }
1382 last_marks = marks.current().cloned();
1383 mark_index = index;
1384 mark_len = 0;
1385 }
1386 mark_len += len;
1387 index += len;
1388 }
1389 OpType::MarkBegin(_, data) => {
1390 marks.mark_begin(*o.id(), data, &self.ops.osd);
1391 }
1392 OpType::MarkEnd(_) => {
1393 marks.mark_end(*o.id(), &self.ops.osd);
1394 }
1395 OpType::Increment(_) | OpType::Delete => {}
1396 }
1397 }
1398 }
1399 match last_marks.as_ref() {
1400 Some(m) if mark_len > 0 => acc.add(mark_index, mark_len, m),
1401 _ => (),
1402 }
1403 Ok(acc.into_iter_no_unmark().collect())
1404 }
1405
1406 pub fn hydrate(&self, heads: Option<&[ChangeHash]>) -> hydrate::Value {
1407 let clock = heads.map(|heads| self.clock_at(heads));
1408 self.hydrate_map(&ObjId::root(), clock.as_ref())
1409 }
1410
1411 pub(crate) fn hydrate_obj(
1412 &self,
1413 obj: &crate::ObjId,
1414 heads: Option<&[ChangeHash]>,
1415 ) -> Result<hydrate::Value, AutomergeError> {
1416 let obj = self.exid_to_obj(obj)?;
1417 let clock = heads.map(|heads| self.clock_at(heads));
1418 Ok(match obj.typ {
1419 ObjType::Map | ObjType::Table => self.hydrate_map(&obj.id, clock.as_ref()),
1420 ObjType::List => self.hydrate_list(&obj.id, clock.as_ref()),
1421 ObjType::Text => self.hydrate_text(&obj.id, clock.as_ref()),
1422 })
1423 }
1424
1425 pub(crate) fn parents_for(
1426 &self,
1427 obj: &ExId,
1428 clock: Option<Clock>,
1429 ) -> Result<Parents<'_>, AutomergeError> {
1430 let obj = self.exid_to_obj(obj)?;
1431 Ok(self.ops.parents(
1433 obj.id,
1434 TextRepresentation::String(self.text_encoding),
1435 clock,
1436 ))
1437 }
1438
1439 pub(crate) fn keys_for(&self, obj: &ExId, clock: Option<Clock>) -> Keys<'_> {
1440 self.exid_to_obj(obj)
1441 .ok()
1442 .map(|obj| self.ops.keys(&obj.id, clock))
1443 .unwrap_or_default()
1444 }
1445
1446 pub(crate) fn map_range_for<'a, R: RangeBounds<String> + 'a>(
1447 &'a self,
1448 obj: &ExId,
1449 range: R,
1450 clock: Option<Clock>,
1451 ) -> MapRange<'a, R> {
1452 self.exid_to_obj(obj)
1453 .ok()
1454 .map(|obj| self.ops.map_range(&obj.id, range, clock))
1455 .unwrap_or_default()
1456 }
1457
1458 pub(crate) fn list_range_for<R: RangeBounds<usize>>(
1459 &self,
1460 obj: &ExId,
1461 range: R,
1462 clock: Option<Clock>,
1463 ) -> ListRange<'_, R> {
1464 self.exid_to_obj(obj)
1465 .ok()
1466 .map(|obj| {
1467 self.ops.list_range(
1468 &obj.id,
1469 range,
1470 TextRepresentation::Array.encoding(obj.typ),
1471 clock,
1472 )
1473 })
1474 .unwrap_or_default()
1475 }
1476
1477 pub(crate) fn values_for(&self, obj: &ExId, clock: Option<Clock>) -> Values<'_> {
1478 self.exid_to_obj(obj)
1479 .ok()
1480 .map(|obj| Values::new(self.ops.top_ops(&obj.id, clock.clone()), clock))
1481 .unwrap_or_default()
1482 }
1483
1484 pub(crate) fn length_for(&self, obj: &ExId, clock: Option<Clock>) -> usize {
1485 self.exid_to_obj(obj)
1487 .map(|obj| {
1488 self.ops.length(
1489 &obj.id,
1490 TextRepresentation::String(self.text_encoding).encoding(obj.typ),
1491 clock,
1492 )
1493 })
1494 .unwrap_or(0)
1495 }
1496
1497 pub(crate) fn text_for(
1498 &self,
1499 obj: &ExId,
1500 clock: Option<Clock>,
1501 ) -> Result<String, AutomergeError> {
1502 let obj = self.exid_to_obj(obj)?;
1503 Ok(self.ops.text(&obj.id, clock))
1504 }
1505
1506 pub(crate) fn spans_for(
1507 &self,
1508 obj: &ExId,
1509 clock: Option<Clock>,
1510 ) -> Result<Spans<'_>, AutomergeError> {
1511 let obj = self.exid_to_obj(obj)?;
1512 let iter = self.ops.iter_obj(&obj.id);
1513 Ok(Spans::new(iter, self, clock))
1514 }
1515
1516 pub(crate) fn get_cursor_for(
1517 &self,
1518 obj: &ExId,
1519 position: CursorPosition,
1520 clock: Option<Clock>,
1521 move_cursor: MoveCursor,
1522 ) -> Result<Cursor, AutomergeError> {
1523 let obj = self.exid_to_obj(obj)?;
1524 if !obj.typ.is_sequence() {
1525 Err(AutomergeError::InvalidOp(obj.typ))
1526 } else {
1527 match position {
1528 CursorPosition::Start => Ok(Cursor::Start),
1529 CursorPosition::End => Ok(Cursor::End),
1530 CursorPosition::Index(i) => {
1531 let found = self.ops.seek_ops_by_prop(
1532 &obj.id,
1533 i.into(),
1534 TextRepresentation::String(self.text_encoding).encoding(obj.typ),
1535 clock.as_ref(),
1536 );
1537
1538 if let Some(op) = found.ops.last() {
1539 return Ok(Cursor::Op(OpCursor::new(
1540 *op.id(),
1541 &self.ops.osd,
1542 move_cursor,
1543 )));
1544 }
1545
1546 Err(AutomergeError::InvalidIndex(i))
1547 }
1548 }
1549 }
1550 }
1551
1552 pub(crate) fn get_cursor_position_for(
1553 &self,
1554 obj: &ExId,
1555 cursor: &Cursor,
1556 clock: Option<Clock>,
1557 ) -> Result<usize, AutomergeError> {
1558 match cursor {
1559 Cursor::Start => Ok(0),
1560 Cursor::End => Ok(self.length_for(obj, clock)),
1561 Cursor::Op(op) => {
1562 let obj_meta = self.exid_to_obj(obj)?;
1563
1564 if !obj_meta.typ.is_sequence() {
1565 return Err(AutomergeError::InvalidCursor(cursor.clone()));
1566 }
1567
1568 let opid = self.op_cursor_to_opid(op, clock.as_ref())?;
1569
1570 let found = self
1571 .ops
1572 .seek_list_opid(
1573 &obj_meta.id,
1574 opid,
1575 TextRepresentation::String(self.text_encoding).encoding(obj_meta.typ),
1576 clock.as_ref(),
1577 )
1578 .ok_or_else(|| AutomergeError::InvalidCursor(cursor.clone()))?;
1579
1580 match op.move_cursor {
1581 MoveCursor::After => Ok(found.index),
1592 MoveCursor::Before => {
1593 if found.visible || found.index == 0 {
1601 Ok(found.index)
1602 } else {
1603 let mut key = found
1610 .op
1611 .key()
1612 .elemid()
1613 .expect("failed to retrieve initial cursor op key for MoveCursor::Before")
1614 .0;
1615
1616 loop {
1617 let f = self.ops.seek_list_opid(
1618 &obj_meta.id,
1619 key,
1620 TextRepresentation::String(self.text_encoding)
1621 .encoding(obj_meta.typ),
1622 clock.as_ref(),
1623 );
1624
1625 match f {
1626 Some(f) => {
1627 if f.visible {
1628 return Ok(f.index);
1629 }
1630
1631 key = f
1632 .op
1633 .key()
1634 .elemid()
1635 .expect(
1636 "failed to retrieve op key in MoveCursor::Before",
1637 )
1638 .0;
1639 }
1640 None => break Ok(0),
1642 }
1643 }
1644 }
1645 }
1646 }
1647 }
1648 }
1649 }
1650
1651 pub(crate) fn marks_for(
1652 &self,
1653 obj: &ExId,
1654 clock: Option<Clock>,
1655 ) -> Result<Vec<Mark<'_>>, AutomergeError> {
1656 self.calculate_marks(obj, clock)
1657 }
1658
1659 pub(crate) fn get_for(
1660 &self,
1661 obj: &ExId,
1662 prop: Prop,
1663 clock: Option<Clock>,
1664 ) -> Result<Option<(Value<'_>, ExId)>, AutomergeError> {
1665 let obj = self.exid_to_obj(obj)?;
1666 Ok(self
1667 .ops
1668 .seek_ops_by_prop(
1669 &obj.id,
1670 prop,
1671 TextRepresentation::String(self.text_encoding).encoding(obj.typ),
1672 clock.as_ref(),
1673 )
1674 .ops
1675 .into_iter()
1676 .last()
1677 .map(|op| op.tagged_value(clock.as_ref())))
1678 }
1679
1680 pub(crate) fn get_all_for<O: AsRef<ExId>, P: Into<Prop>>(
1681 &self,
1682 obj: O,
1683 prop: P,
1684 clock: Option<Clock>,
1685 ) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError> {
1686 let prop = prop.into();
1687 let obj = self.exid_to_obj(obj.as_ref())?;
1688 let values = self
1689 .ops
1690 .seek_ops_by_prop(
1691 &obj.id,
1692 prop,
1693 TextRepresentation::String(self.text_encoding).encoding(obj.typ),
1694 clock.as_ref(),
1695 )
1696 .ops
1697 .into_iter()
1698 .map(|op| op.tagged_value(clock.as_ref()))
1699 .collect::<Vec<_>>();
1700 assert_eq!(
1702 values.iter().map(|v| &v.1).collect::<Vec<_>>(),
1703 values.iter().map(|v| &v.1).sorted().collect::<Vec<_>>()
1704 );
1705 Ok(values)
1706 }
1707
1708 pub(crate) fn get_marks_for<O: AsRef<ExId>>(
1709 &self,
1710 obj: O,
1711 index: usize,
1712 clock: Option<Clock>,
1713 ) -> Result<MarkSet, AutomergeError> {
1714 let obj = self.exid_to_obj(obj.as_ref())?;
1715 let result = self
1716 .ops
1717 .search(
1718 &obj.id,
1719 query::Nth::new(
1720 index,
1721 TextRepresentation::String(self.text_encoding).encoding(obj.typ),
1722 clock,
1723 &self.ops.osd,
1724 )
1725 .with_marks(),
1726 )
1727 .marks()
1728 .as_deref()
1729 .cloned()
1730 .unwrap_or_default();
1731 Ok(result)
1732 }
1733
1734 fn convert_scalar_strings_to_text(&mut self) -> Result<(), AutomergeError> {
1735 struct Conversion {
1736 obj_id: ExId,
1737 prop: Prop,
1738 text: smol_str::SmolStr,
1739 }
1740 let mut to_convert = Vec::new();
1741 for (obj, ops) in self.ops.iter_objs() {
1742 match obj.typ {
1743 ObjType::Map | ObjType::List => {
1744 for op in ops {
1745 let op = op.as_op(self.osd());
1746 if !op.visible() {
1747 continue;
1748 }
1749 if let OpType::Put(ScalarValue::Str(s)) = op.action() {
1750 let prop = match *op.key() {
1751 Key::Map(prop) => Prop::Map(self.ops.osd.props.get(prop).clone()),
1752 Key::Seq(_) => {
1753 let Some(found) = self.ops.seek_list_opid(
1754 &obj.id,
1755 *op.id(),
1756 ListEncoding::List,
1757 None,
1758 ) else {
1759 continue;
1760 };
1761 Prop::Seq(found.index)
1762 }
1763 };
1764 to_convert.push(Conversion {
1765 obj_id: self.ops.id_to_exid(obj.id.0),
1766 prop,
1767 text: s.clone(),
1768 })
1769 }
1770 }
1771 }
1772 _ => {}
1773 }
1774 }
1775
1776 if !to_convert.is_empty() {
1777 let mut tx = self.transaction();
1778 for Conversion { obj_id, prop, text } in to_convert {
1779 let text_id = tx.put_object(obj_id, prop, ObjType::Text)?;
1780 tx.splice_text(&text_id, 0, 0, &text)?;
1781 }
1782 tx.commit();
1783 }
1784
1785 Ok(())
1786 }
1787
1788 pub(crate) fn visible_obj_paths(
1789 &self,
1790 at: Option<&[ChangeHash]>,
1791 ) -> HashMap<ExId, Vec<(ExId, Prop)>> {
1792 let at = at.map(|heads| self.clock_at(heads));
1793 let mut paths = HashMap::<ExId, Vec<(ExId, Prop)>>::new();
1794 let mut visible_objs = HashSet::<crate::types::ObjId>::new();
1795 visible_objs.insert(crate::types::ObjId::root());
1796 paths.insert(ExId::Root, vec![]);
1797
1798 for (obj, ops) in self.ops.iter_objs() {
1799 if !visible_objs.contains(&obj.id) {
1804 continue;
1805 }
1806 for op_idx in ops {
1807 let op = op_idx.as_op(self.osd());
1808 if op.visible_at(at.as_ref()) {
1809 if let OpType::Make(_) = op.action() {
1810 visible_objs.insert(op.id().into());
1811 let (mut path, parent_obj_id) = if obj.id.is_root() {
1812 (vec![], ExId::Root)
1813 } else {
1814 let parent_obj_id = self.ops.id_to_exid(obj.id.into());
1815 (paths.get(&parent_obj_id).cloned().unwrap(), parent_obj_id)
1816 };
1817 let prop = match op.key() {
1818 Key::Map(prop) => Prop::Map(self.ops.osd.props.get(*prop).clone()),
1819 Key::Seq(_) => {
1820 let encoding = match obj.typ {
1821 ObjType::Text => ListEncoding::Text(self.text_encoding),
1822 _ => ListEncoding::List,
1823 };
1824 let found = self
1825 .ops
1826 .seek_list_opid(&obj.id, *op.id(), encoding, at.as_ref())
1827 .unwrap();
1828 Prop::Seq(found.index)
1829 }
1830 };
1831 path.push((parent_obj_id.clone(), prop));
1832 let obj_id = self.ops.id_to_exid(*op.id());
1833 paths.insert(obj_id, path);
1834 }
1835 }
1836 }
1837 }
1838 paths
1839 }
1840
1841 pub fn has_our_changes(&self, other: &crate::sync::State) -> bool {
1843 other.shared_heads == self.get_heads()
1844 }
1845
1846 pub fn text_encoding(&self) -> TextEncoding {
1847 self.text_encoding
1848 }
1849}
1850
1851impl ReadDoc for Automerge {
1852 fn parents<O: AsRef<ExId>>(&self, obj: O) -> Result<Parents<'_>, AutomergeError> {
1853 self.parents_for(obj.as_ref(), None)
1854 }
1855
1856 fn parents_at<O: AsRef<ExId>>(
1857 &self,
1858 obj: O,
1859 heads: &[ChangeHash],
1860 ) -> Result<Parents<'_>, AutomergeError> {
1861 let clock = self.clock_at(heads);
1862 self.parents_for(obj.as_ref(), Some(clock))
1863 }
1864
1865 fn keys<O: AsRef<ExId>>(&self, obj: O) -> Keys<'_> {
1866 self.keys_for(obj.as_ref(), None)
1867 }
1868
1869 fn keys_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> Keys<'_> {
1870 let clock = self.clock_at(heads);
1871 self.keys_for(obj.as_ref(), Some(clock))
1872 }
1873
1874 fn map_range<'a, O: AsRef<ExId>, R: RangeBounds<String> + 'a>(
1875 &'a self,
1876 obj: O,
1877 range: R,
1878 ) -> MapRange<'a, R> {
1879 self.map_range_for(obj.as_ref(), range, None)
1880 }
1881
1882 fn map_range_at<'a, O: AsRef<ExId>, R: RangeBounds<String> + 'a>(
1883 &'a self,
1884 obj: O,
1885 range: R,
1886 heads: &[ChangeHash],
1887 ) -> MapRange<'a, R> {
1888 let clock = self.clock_at(heads);
1889 self.map_range_for(obj.as_ref(), range, Some(clock))
1890 }
1891
1892 fn list_range<O: AsRef<ExId>, R: RangeBounds<usize>>(
1893 &self,
1894 obj: O,
1895 range: R,
1896 ) -> ListRange<'_, R> {
1897 self.list_range_for(obj.as_ref(), range, None)
1898 }
1899
1900 fn list_range_at<O: AsRef<ExId>, R: RangeBounds<usize>>(
1901 &self,
1902 obj: O,
1903 range: R,
1904 heads: &[ChangeHash],
1905 ) -> ListRange<'_, R> {
1906 let clock = self.clock_at(heads);
1907 self.list_range_for(obj.as_ref(), range, Some(clock))
1908 }
1909
1910 fn values<O: AsRef<ExId>>(&self, obj: O) -> Values<'_> {
1911 self.values_for(obj.as_ref(), None)
1912 }
1913
1914 fn values_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> Values<'_> {
1915 let clock = self.clock_at(heads);
1916 self.values_for(obj.as_ref(), Some(clock))
1917 }
1918
1919 fn length<O: AsRef<ExId>>(&self, obj: O) -> usize {
1920 self.length_for(obj.as_ref(), None)
1921 }
1922
1923 fn length_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> usize {
1924 let clock = self.clock_at(heads);
1925 self.length_for(obj.as_ref(), Some(clock))
1926 }
1927
1928 fn text<O: AsRef<ExId>>(&self, obj: O) -> Result<String, AutomergeError> {
1929 self.text_for(obj.as_ref(), None)
1930 }
1931
1932 fn spans<O: AsRef<ExId>>(&self, obj: O) -> Result<Spans<'_>, AutomergeError> {
1933 self.spans_for(obj.as_ref(), None)
1934 }
1935
1936 fn spans_at<O: AsRef<ExId>>(
1937 &self,
1938 obj: O,
1939 heads: &[ChangeHash],
1940 ) -> Result<Spans<'_>, AutomergeError> {
1941 let clock = self.clock_at(heads);
1942 self.spans_for(obj.as_ref(), Some(clock))
1943 }
1944
1945 fn get_cursor<O: AsRef<ExId>, I: Into<CursorPosition>>(
1946 &self,
1947 obj: O,
1948 position: I,
1949 at: Option<&[ChangeHash]>,
1950 ) -> Result<Cursor, AutomergeError> {
1951 let clock = at.map(|heads| self.clock_at(heads));
1952 self.get_cursor_for(obj.as_ref(), position.into(), clock, MoveCursor::After)
1953 }
1954
1955 fn get_cursor_moving<O: AsRef<ExId>, I: Into<CursorPosition>>(
1956 &self,
1957 obj: O,
1958 position: I,
1959 at: Option<&[ChangeHash]>,
1960 move_cursor: MoveCursor,
1961 ) -> Result<Cursor, AutomergeError> {
1962 let clock = at.map(|heads| self.clock_at(heads));
1963 self.get_cursor_for(obj.as_ref(), position.into(), clock, move_cursor)
1964 }
1965
1966 fn get_cursor_position<O: AsRef<ExId>>(
1967 &self,
1968 obj: O,
1969 cursor: &Cursor,
1970 at: Option<&[ChangeHash]>,
1971 ) -> Result<usize, AutomergeError> {
1972 let clock = at.map(|heads| self.clock_at(heads));
1973 self.get_cursor_position_for(obj.as_ref(), cursor, clock)
1974 }
1975
1976 fn text_at<O: AsRef<ExId>>(
1977 &self,
1978 obj: O,
1979 heads: &[ChangeHash],
1980 ) -> Result<String, AutomergeError> {
1981 let clock = self.clock_at(heads);
1982 self.text_for(obj.as_ref(), Some(clock))
1983 }
1984
1985 fn marks<O: AsRef<ExId>>(&self, obj: O) -> Result<Vec<Mark<'_>>, AutomergeError> {
1986 self.marks_for(obj.as_ref(), None)
1987 }
1988
1989 fn marks_at<O: AsRef<ExId>>(
1990 &self,
1991 obj: O,
1992 heads: &[ChangeHash],
1993 ) -> Result<Vec<Mark<'_>>, AutomergeError> {
1994 let clock = self.clock_at(heads);
1995 self.marks_for(obj.as_ref(), Some(clock))
1996 }
1997
1998 fn hydrate<O: AsRef<ExId>>(
1999 &self,
2000 obj: O,
2001 heads: Option<&[ChangeHash]>,
2002 ) -> Result<hydrate::Value, AutomergeError> {
2003 let obj = self.exid_to_obj(obj.as_ref())?;
2004 let clock = heads.map(|h| self.clock_at(h));
2005 Ok(match obj.typ {
2006 ObjType::List => self.hydrate_list(&obj.id, clock.as_ref()),
2007 ObjType::Text => self.hydrate_text(&obj.id, clock.as_ref()),
2008 _ => self.hydrate_map(&obj.id, clock.as_ref()),
2009 })
2010 }
2011
2012 fn get_marks<O: AsRef<ExId>>(
2013 &self,
2014 obj: O,
2015 index: usize,
2016 heads: Option<&[ChangeHash]>,
2017 ) -> Result<MarkSet, AutomergeError> {
2018 let clock = heads.map(|h| self.clock_at(h));
2019 self.get_marks_for(obj.as_ref(), index, clock)
2020 }
2021
2022 fn get<O: AsRef<ExId>, P: Into<Prop>>(
2023 &self,
2024 obj: O,
2025 prop: P,
2026 ) -> Result<Option<(Value<'_>, ExId)>, AutomergeError> {
2027 self.get_for(obj.as_ref(), prop.into(), None)
2028 }
2029
2030 fn get_at<O: AsRef<ExId>, P: Into<Prop>>(
2031 &self,
2032 obj: O,
2033 prop: P,
2034 heads: &[ChangeHash],
2035 ) -> Result<Option<(Value<'_>, ExId)>, AutomergeError> {
2036 let clock = Some(self.clock_at(heads));
2037 self.get_for(obj.as_ref(), prop.into(), clock)
2038 }
2039
2040 fn get_all<O: AsRef<ExId>, P: Into<Prop>>(
2041 &self,
2042 obj: O,
2043 prop: P,
2044 ) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError> {
2045 self.get_all_for(obj.as_ref(), prop.into(), None)
2046 }
2047
2048 fn get_all_at<O: AsRef<ExId>, P: Into<Prop>>(
2049 &self,
2050 obj: O,
2051 prop: P,
2052 heads: &[ChangeHash],
2053 ) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError> {
2054 let clock = Some(self.clock_at(heads));
2055 self.get_all_for(obj.as_ref(), prop.into(), clock)
2056 }
2057
2058 fn object_type<O: AsRef<ExId>>(&self, obj: O) -> Result<ObjType, AutomergeError> {
2059 let obj = obj.as_ref();
2060 let opid = self.exid_to_opid(obj)?;
2061 let typ = self.ops.object_type(&ObjId(opid));
2062 typ.ok_or_else(|| AutomergeError::InvalidObjId(obj.to_string()))
2063 }
2064
2065 fn get_missing_deps(&self, heads: &[ChangeHash]) -> Vec<ChangeHash> {
2066 let in_queue: HashSet<_> = self.queue.iter().map(|change| change.hash()).collect();
2067 let mut missing = HashSet::new();
2068
2069 for head in self.queue.iter().flat_map(|change| change.deps()) {
2070 if !self.history_index.contains_key(head) {
2071 missing.insert(head);
2072 }
2073 }
2074
2075 for head in heads {
2076 if !self.history_index.contains_key(head) {
2077 missing.insert(head);
2078 }
2079 }
2080
2081 let mut missing = missing
2082 .into_iter()
2083 .filter(|hash| !in_queue.contains(hash))
2084 .copied()
2085 .collect::<Vec<_>>();
2086 missing.sort();
2087 missing
2088 }
2089
2090 fn get_change_by_hash(&self, hash: &ChangeHash) -> Option<&Change> {
2091 self.history_index
2092 .get(hash)
2093 .and_then(|index| self.history.get(*index))
2094 }
2095
2096 fn stats(&self) -> crate::read::Stats {
2097 crate::read::Stats {
2098 num_changes: self.history.len() as u64,
2099 num_ops: self.ops.len() as u64,
2100 }
2101 }
2102
2103 fn text_encoding(&self) -> TextEncoding {
2104 self.text_encoding
2105 }
2106}
2107
2108impl ReadDocInternal for Automerge {
2109 fn live_obj_paths(&self) -> HashMap<ExId, Vec<(ExId, Prop)>> {
2110 self.visible_obj_paths(None)
2111 }
2112}
2113
2114impl Default for Automerge {
2115 fn default() -> Self {
2116 Self::new()
2117 }
2118}
2119
2120#[derive(Debug)]
2122pub struct SaveOptions {
2123 pub deflate: bool,
2125 pub retain_orphans: bool,
2127}
2128
2129impl std::default::Default for SaveOptions {
2130 fn default() -> Self {
2131 Self {
2132 deflate: true,
2133 retain_orphans: true,
2134 }
2135 }
2136}
2137
2138#[derive(Debug)]
2139pub(crate) struct Isolation {
2140 actor_index: usize,
2141 seq: u64,
2142 clock: Clock,
2143}
2144
2145pub(crate) fn reconstruct_document<'a>(
2146 doc: &'a storage::Document<'a>,
2147 mode: VerificationMode,
2148 text_encoding: TextEncoding,
2149) -> Result<Automerge, AutomergeError> {
2150 let storage::load::ReconOpSet {
2151 changes,
2152 op_set,
2153 heads,
2154 max_op,
2155 } = storage::load::reconstruct_opset(doc, mode, text_encoding)
2156 .map_err(|e| load::Error::InflateDocument(Box::new(e)))?;
2157
2158 let mut hashes_by_index = HashMap::new();
2159 let mut actor_to_history: HashMap<usize, Vec<usize>> = HashMap::new();
2160 let mut change_graph = ChangeGraph::new();
2161 for (index, change) in changes.iter().enumerate() {
2162 let actor_index = op_set.osd.actors.lookup(change.actor_id()).unwrap();
2165 actor_to_history.entry(actor_index).or_default().push(index);
2166 hashes_by_index.insert(index, change.hash());
2167 change_graph.add_change(change, actor_index)?;
2168 }
2169 let history_index = hashes_by_index.into_iter().map(|(k, v)| (v, k)).collect();
2170 Ok(Automerge {
2171 queue: vec![],
2172 history: changes,
2173 history_index,
2174 states: actor_to_history,
2175 change_graph,
2176 ops: op_set,
2177 deps: heads.into_iter().collect(),
2178 actor: Actor::Unused(ActorId::random()),
2179 max_op,
2180 text_encoding,
2181 })
2182}