//! The document as it was at given heads: every read of `ReadDoc` made at them (its //! `*_at` variant), so whatever reads a document (`store`) reads it as it was then. use std::ops::RangeBounds; use automerge::iter::{DocIter, Keys, ListRange, MapRange, Spans, Values}; use automerge::marks::{Mark, MarkSet}; use automerge::{ AutomergeError, Change, ChangeHash, Cursor, CursorPosition, MoveCursor, ObjId, ObjType, Parents, Prop, ReadDoc, Stats, TextEncoding, Value, hydrate, }; use super::Document; pub(crate) struct At<'a> { doc: &'a Document, heads: Vec, } impl<'a> At<'a> { /// `doc` at `heads`; None if it lacks one of them (it hasn't synced it yet, or /// never will: of another epoch, or no change at all). pub(crate) fn new(doc: &'a Document, heads: &[ChangeHash]) -> Option { heads .iter() .all(|head| doc.get_change_by_hash(head).is_some()) .then(|| Self { doc, heads: heads.to_vec(), }) } fn or_ours<'h>(&'h self, heads: Option<&'h [ChangeHash]>) -> Option<&'h [ChangeHash]> { Some(heads.unwrap_or(&self.heads)) } } impl ReadDoc for At<'_> { fn parents>(&self, obj: O) -> Result, AutomergeError> { self.doc.parents_at(obj, &self.heads) } fn parents_at>( &self, obj: O, heads: &[ChangeHash], ) -> Result, AutomergeError> { self.doc.parents_at(obj, heads) } fn keys>(&self, obj: O) -> Keys<'_> { self.doc.keys_at(obj, &self.heads) } fn keys_at>(&self, obj: O, heads: &[ChangeHash]) -> Keys<'_> { self.doc.keys_at(obj, heads) } fn iter_at>(&self, obj: O, heads: Option<&[ChangeHash]>) -> DocIter<'_> { self.doc.iter_at(obj, self.or_ours(heads)) } fn map_range<'b, O: AsRef, R: RangeBounds + 'b>( &'b self, obj: O, range: R, ) -> MapRange<'b> { self.doc.map_range_at(obj, range, &self.heads) } fn map_range_at<'b, O: AsRef, R: RangeBounds + 'b>( &'b self, obj: O, range: R, heads: &[ChangeHash], ) -> MapRange<'b> { self.doc.map_range_at(obj, range, heads) } fn list_range, R: RangeBounds>( &self, obj: O, range: R, ) -> ListRange<'_> { self.doc.list_range_at(obj, range, &self.heads) } fn list_range_at, R: RangeBounds>( &self, obj: O, range: R, heads: &[ChangeHash], ) -> ListRange<'_> { self.doc.list_range_at(obj, range, heads) } fn values>(&self, obj: O) -> Values<'_> { self.doc.values_at(obj, &self.heads) } fn values_at>(&self, obj: O, heads: &[ChangeHash]) -> Values<'_> { self.doc.values_at(obj, heads) } fn length>(&self, obj: O) -> usize { self.doc.length_at(obj, &self.heads) } fn length_at>(&self, obj: O, heads: &[ChangeHash]) -> usize { self.doc.length_at(obj, heads) } fn object_type>(&self, obj: O) -> Result { // An object's type is fixed when it is made. self.doc.object_type(obj) } fn marks>(&self, obj: O) -> Result, AutomergeError> { self.doc.marks_at(obj, &self.heads) } fn marks_at>( &self, obj: O, heads: &[ChangeHash], ) -> Result, AutomergeError> { self.doc.marks_at(obj, heads) } fn get_marks>( &self, obj: O, index: usize, heads: Option<&[ChangeHash]>, ) -> Result { self.doc.get_marks(obj, index, self.or_ours(heads)) } fn text>(&self, obj: O) -> Result { self.doc.text_at(obj, &self.heads) } fn text_at>( &self, obj: O, heads: &[ChangeHash], ) -> Result { self.doc.text_at(obj, heads) } fn spans>(&self, obj: O) -> Result, AutomergeError> { self.doc.spans_at(obj, &self.heads) } fn spans_at>( &self, obj: O, heads: &[ChangeHash], ) -> Result, AutomergeError> { self.doc.spans_at(obj, heads) } fn get_cursor, I: Into>( &self, obj: O, position: I, at: Option<&[ChangeHash]>, ) -> Result { self.doc.get_cursor(obj, position, self.or_ours(at)) } fn get_cursor_moving, I: Into>( &self, obj: O, position: I, at: Option<&[ChangeHash]>, move_cursor: MoveCursor, ) -> Result { self.doc .get_cursor_moving(obj, position, self.or_ours(at), move_cursor) } fn get_cursor_position>( &self, obj: O, cursor: &Cursor, at: Option<&[ChangeHash]>, ) -> Result { self.doc.get_cursor_position(obj, cursor, self.or_ours(at)) } fn get, P: Into>( &self, obj: O, prop: P, ) -> Result, ObjId)>, AutomergeError> { self.doc.get_at(obj, prop, &self.heads) } fn get_at, P: Into>( &self, obj: O, prop: P, heads: &[ChangeHash], ) -> Result, ObjId)>, AutomergeError> { self.doc.get_at(obj, prop, heads) } fn hydrate>( &self, obj: O, heads: Option<&[ChangeHash]>, ) -> Result { ReadDoc::hydrate(self.doc, obj, self.or_ours(heads)) } fn get_all, P: Into>( &self, obj: O, prop: P, ) -> Result, ObjId)>, AutomergeError> { self.doc.get_all_at(obj, prop, &self.heads) } fn get_all_at, P: Into>( &self, obj: O, prop: P, heads: &[ChangeHash], ) -> Result, ObjId)>, AutomergeError> { self.doc.get_all_at(obj, prop, heads) } fn get_missing_deps(&self, heads: &[ChangeHash]) -> Vec { self.doc.get_missing_deps(heads) } fn get_change_by_hash(&self, hash: &ChangeHash) -> Option { self.doc.get_change_by_hash(hash) } fn stats(&self) -> Stats { self.doc.stats() } fn text_encoding(&self) -> TextEncoding { self.doc.text_encoding() } }