automerge/
automerge.rs

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/// What to do when loading a document partially succeeds
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum OnPartialLoad {
46    /// Ignore the error and return the loaded changes
47    Ignore,
48    /// Fail the entire load
49    Error,
50}
51
52/// Whether to convert [`ScalarValue::Str`]s in the loaded document to [`ObjType::Text`]
53#[derive(Debug)]
54pub enum StringMigration {
55    /// Don't convert anything
56    NoMigration,
57    /// Convert all strings to text
58    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    /// What to do when loading a document partially succeeds
76    ///
77    /// The default is [`OnPartialLoad::Error`]
78    pub fn on_partial_load(self, on_partial_load: OnPartialLoad) -> Self {
79        Self {
80            on_partial_load,
81            ..self
82        }
83    }
84
85    /// Whether to verify the head hashes after loading
86    ///
87    /// The default is [`VerificationMode::Check`]
88    pub fn verification_mode(self, verification_mode: VerificationMode) -> Self {
89        Self {
90            verification_mode,
91            ..self
92        }
93    }
94
95    /// A [`PatchLog`] to log the changes required to materialize the current state of the
96    ///
97    /// The default is to not log patches
98    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    /// Whether to convert [`ScalarValue::Str`]s in the loaded document to [`ObjType::Text`]
106    ///
107    /// Until version 2.1.0 of the javascript library strings (as in, the native string of the JS
108    /// runtime) were represented in the document as [`ScalarValue::Str`] and there was a special
109    /// JS class called `Text` which users were expected to use for [`ObjType::Text`]. In `2.1.0`
110    /// we changed this so that native strings were represented as [`ObjType::Text`] and
111    /// [`ScalarValue::Str`] was represented as a special `RawString` class. This means
112    /// that upgrading the application code to use the new API would require either
113    ///
114    /// a) Maintaining two code paths in the application to deal with both `string` and `RawString`
115    ///    types
116    /// b) Writing a migration script to convert all `RawString` types to `string`
117    ///
118    /// The latter is logic which is the same for all applications so we implement it in the
119    /// library for convenience. The way this works is that after loading the document we iterate
120    /// through all visible [`ScalarValue::Str`] values and emit a change which creates a new
121    /// [`ObjType::Text`] at the same path with the same content.
122    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/// An automerge document which does not manage transactions for you.
150///
151/// ## Creating, loading, merging and forking documents
152///
153/// A new document can be created with [`Self::new()`], which will create a document with a random
154/// [`ActorId`]. Existing documents can be loaded with [`Self::load()`], or [`Self::load_with()`].
155///
156/// If you have two documents and you want to merge the changes from one into the other you can use
157/// [`Self::merge()`] or [`Self::merge_and_log_patches()`].
158///
159/// If you have a document you want to split into two concurrent threads of execution you can use
160/// [`Self::fork()`]. If you want to split a document from ealier in its history you can use
161/// [`Self::fork_at()`].
162///
163/// ## Reading values
164///
165/// [`Self`] implements [`ReadDoc`], which provides methods for reading values from the document.
166///
167/// ## Modifying a document (Transactions)
168///
169/// [`Automerge`] provides an interface for viewing and modifying automerge documents which does
170/// not manage transactions for you. To create changes you use either [`Automerge::transaction()`] or
171/// [`Automerge::transact()`] (or the `_with` variants).
172///
173/// ## Sync
174///
175/// This type implements [`crate::sync::SyncDoc`]
176///
177#[derive(Debug, Clone)]
178pub struct Automerge {
179    /// The list of unapplied changes that are not causally ready.
180    queue: Vec<Change>,
181    /// The history of changes that form this document, topologically sorted too.
182    history: Vec<Change>,
183    /// Mapping from change hash to index into the history list.
184    history_index: HashMap<ChangeHash, usize>,
185    /// Graph of changes
186    change_graph: ChangeGraph,
187    /// Mapping from actor index to list of seqs seen for them.
188    states: HashMap<usize, Vec<usize>>,
189    /// Current dependencies of this document (heads hashes).
190    deps: HashSet<ChangeHash>,
191    /// The set of operations that form this document.
192    ops: OpSet,
193    /// The current actor.
194    actor: Actor,
195    /// The maximum operation counter this document has seen.
196    max_op: u64,
197    /// How we are calculating text widths
198    text_encoding: TextEncoding,
199}
200
201impl Automerge {
202    /// Create a new document with a random actor id.
203    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    /// Whether this document has any operations
246    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    /// Set the actor id for this document.
258    pub fn with_actor(mut self, actor: ActorId) -> Self {
259        self.actor = Actor::Unused(actor);
260        self
261    }
262
263    /// Set the actor id for this document.
264    pub fn set_actor(&mut self, actor: ActorId) -> &mut Self {
265        self.actor = Actor::Unused(actor);
266        self
267    }
268
269    /// Get the current actor id of this document.
270    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    /// Start a transaction.
293    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    /// Start a transaction which records changes in a [`PatchLog`]
303    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    /// Start a transaction isolated at a given heads
309    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        // SAFETY: this unwrap is safe as we always add 1
342        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    /// Run a transaction on this document in a closure, automatically handling commit or rollback
356    /// afterwards.
357    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    /// Like [`Self::transact()`] but with a function for generating the commit options.
365    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        // FIXME
371        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    /// Run a transaction on this document in a closure, collecting patches, automatically handling commit or rollback
403    /// afterwards.
404    ///
405    /// The collected patches are available in the return value of [`Transaction::commit()`]
406    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    /// Like [`Self::transact_and_log_patches()`] but with a function for generating the commit options
418    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    /// Generate an empty change
465    ///
466    /// The main reason to do this is if you want to create a "merge commit", which is a change
467    /// that has all the current heads of the document as dependencies.
468    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    /// Fork this document at the current point for use by a different actor.
474    ///
475    /// This will create a new actor ID for the forked document
476    pub fn fork(&self) -> Self {
477        let mut f = self.clone();
478        f.set_actor(ActorId::random());
479        f
480    }
481
482    /// Fork this document at the given heads
483    ///
484    /// This will create a new actor ID for the forked document
485    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    /// Load a document.
564    pub fn load(data: &[u8]) -> Result<Self, AutomergeError> {
565        Self::load_with_options(data, Default::default())
566    }
567
568    /// Load a document without verifying the head hashes
569    ///
570    /// This is useful for debugging as it allows you to examine a corrupted document.
571    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    /// Load a document, with options
582    ///
583    /// # Arguments
584    /// * `data` - The data to load
585    /// * `on_error` - What to do if the document is only partially loaded. This can happen if some
586    ///                prefix of `data` contains valid data.
587    /// * `mode` - Whether to verify the head hashes after loading
588    /// * `patch_log` - A [`PatchLog`] to log the changes required to materialize the current state of
589    ///                 the document once loaded
590    #[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    /// Load a document, with options
608    ///
609    /// # Arguments
610    /// * `data` - The data to load
611    /// * `options` - The options to use when loading
612    #[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                // Only allow missing deps if the first chunk was a document chunk
661                // See https://github.com/automerge/automerge/pull/599#issuecomment-1549667472
662                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    /// Create the patches from a [`PatchLog`]
687    ///
688    /// See the documentation for [`PatchLog`] for more details on this
689    pub fn make_patches(&self, patch_log: &mut PatchLog) -> Vec<Patch> {
690        patch_log.make_patches(self)
691    }
692
693    /// Get a set of [`Patch`]es which materialize the current state of the document
694    ///
695    /// This is a convienence method for [`doc.diff(&[], current_heads)`][diff]
696    ///
697    /// [diff]: Self::diff()
698    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    /// Load an incremental save of a document.
705    ///
706    /// Unlike [`Self::load()`] this imports changes into an existing document. It will work with
707    /// both the output of [`Self::save()`] and [`Self::save_after()`]
708    ///
709    /// The return value is the number of ops which were applied, this is not useful and will
710    /// change in future.
711    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    /// Like [`Self::load_incremental()`] but log the changes to the current state of the document
719    /// to [`PatchLog`]
720    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    /// Apply changes to this document.
764    ///
765    /// This is idempotent in the sense that if a change has already been applied it will be
766    /// ignored.
767    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    /// Like [`Self::apply_changes()`] but log the resulting changes to the current state of the
778    /// document to `patch_log`
779    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        // Record this so we can avoid observing each individual change and instead just observe
785        // the final state after all the changes have been applied. We can only do this for an
786        // empty document right now, once we have logic to produce the diffs between arbitrary
787        // states of the OpSet we can make this cleaner.
788        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    /// Takes all the changes in `other` which are not in `self` and applies them
898    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    /// Takes all the changes in `other` which are not in `self` and applies them whilst logging
906    /// the resulting changes to the current state of the document to `patch_log`
907    pub fn merge_and_log_patches(
908        &mut self,
909        other: &mut Self,
910        patch_log: &mut PatchLog,
911    ) -> Result<Vec<ChangeHash>, AutomergeError> {
912        // TODO: Make this fallible and figure out how to do this transactionally
913        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    /// Save the entirety of this document in a compact form.
924    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    /// Save the entirety of this document in a compact form.
949    pub fn save(&self) -> Vec<u8> {
950        self.save_with_options(SaveOptions::default())
951    }
952
953    /// Save the document and attempt to load it before returning - slow!
954    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    /// Save this document, but don't run it through `DEFLATE` afterwards
961    pub fn save_nocompress(&self) -> Vec<u8> {
962        self.save_with_options(SaveOptions {
963            deflate: false,
964            ..Default::default()
965        })
966    }
967
968    /// Save the changes since the given heads
969    ///
970    /// The output of this will not be a compressed document format, but a series of individual
971    /// changes. This is useful if you know you have only made a small change since the last
972    /// [`Self::save()`] and you want to immediately send it somewhere (e.g. you've inserted a
973    /// single character in a text object).
974    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    /// Filter the changes down to those that are not transitive dependencies of the heads.
984    ///
985    /// Thus a graph with these heads has not seen the remaining changes.
986    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    /// Get the changes since `have_deps` in this document using a clock internally.
1003    fn get_changes_clock(&self, have_deps: &[ChangeHash]) -> Vec<&Change> {
1004        // get the clock for the given deps
1005        let clock = self.clock_at(have_deps);
1006
1007        // get the documents current clock
1008
1009        let mut change_indexes: Vec<usize> = Vec::new();
1010        // walk the state from the given deps clock and add them into the vec
1011        for (actor_index, actor_changes) in &self.states {
1012            if let Some(clock_data) = clock.get_for_actor(actor_index) {
1013                // find the change in this actors sequence of changes that corresponds to the max_op
1014                // recorded for them in the clock
1015                change_indexes.extend(&actor_changes[clock_data.seq as usize..]);
1016            } else {
1017                change_indexes.extend(&actor_changes[..]);
1018            }
1019        }
1020
1021        // ensure the changes are still in sorted order
1022        change_indexes.sort_unstable();
1023
1024        change_indexes
1025            .into_iter()
1026            .map(|i| &self.history[i])
1027            .collect()
1028    }
1029
1030    /// Get the last change this actor made to the document.
1031    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    /// Return a graphviz representation of the opset.
1219    ///
1220    /// # Arguments
1221    ///
1222    /// * objects: An optional list of object IDs to display, if not specified all objects are
1223    ///            visualised
1224    #[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    /// Create patches representing the change in the current state of the document between the
1270    /// `before` and `after` heads.  If the arguments are reverse it will observe the same changes
1271    /// in the opposite order.
1272    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    /// Get the heads of this document.
1287    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    /// Get changes in `other` that are not in `self`
1298    pub fn get_changes_added<'a>(&self, other: &'a Self) -> Vec<&'a Change> {
1299        // Depth-first traversal from the heads through the dependency graph,
1300        // until we reach a change that is already present in other
1301        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        // Return those changes in the reverse of the order in which the depth-first search
1315        // found them. This is not necessarily a topological sort, but should usually be close.
1316        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    /// Get the hash of the change that contains the given `opid`.
1324    ///
1325    /// Returns [`None`] if the `opid`:
1326    /// - is the root object id
1327    /// - does not exist in this document
1328    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        // FIXME - now that we have blocks a correct text_rep is relevent
1432        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        // FIXME - is doc.length() for a text always the string length?
1486        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` mimics the original behavior of cursors.
1582                    //
1583                    // The original behavior was to just return the `FoundOpId::index` found by
1584                    // `OpSetInternal::seek_list_opid()`.
1585                    //
1586                    // This index always corresponds to the:
1587                    // - index of the item itself (if it's visible at `clock`)
1588                    // - next index of visible item that **was also visible at the time of cursor creation**
1589                    //   (if the item is not visible at `clock`).
1590                    // - or `sequence.length` if none of the next items are visible at `clock`.
1591                    MoveCursor::After => Ok(found.index),
1592                    MoveCursor::Before => {
1593                        // `MoveCursor::Before` behaves like `MoveCursor::After` but in the opposite direction:
1594                        //
1595                        // - if the item is visible at `clock`, just return its index
1596                        // - if the item isn't visible at `clock`, find the index of the **previous** item
1597                        //   that's visible at `clock` that was also visible at the time of cursor creation.
1598                        // - if none of the previous items are visible (or the index of the original item is 0),
1599                        //   our index is `0`.
1600                        if found.visible || found.index == 0 {
1601                            Ok(found.index)
1602                        } else {
1603                            // FIXME: this should probably be an `OpSet` query
1604                            // also this implementation is likely very inefficient
1605
1606                            // current implementation walks upwards through `key` of op pointed to by cursor
1607                            // and checks if `key` is visible by using `seek_list_opid()`.
1608
1609                            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                                    // reached when we've gone before the beginning of the sequence
1641                                    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        // this is a test to make sure opid and exid are always sorting the same way
1701        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            // Note that this works because the OpSet iterates in causal order,
1800            // which means that we have already seen the operation which
1801            // creates the object and added it to the visible_objs set if it
1802            // is visible.
1803            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    /// Whether the peer represented by `other` has all the changes we have
1842    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/// Options to pass to [`Automerge::save_with_options()`] and [`crate::AutoCommit::save_with_options()`]
2121#[derive(Debug)]
2122pub struct SaveOptions {
2123    /// Whether to apply DEFLATE compression to the RLE encoded columns in the document
2124    pub deflate: bool,
2125    /// Whether to save changes which we do not have the dependencies for
2126    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        // SAFETY: This should be fine because we just constructed an opset containing
2163        // all the changes
2164        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}