1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
use crate::{
cursor::{CursorPosition, MoveCursor},
error::AutomergeError,
exid::ExId,
hydrate,
marks::{Mark, MarkSet},
op_set2::Parents,
Change, ChangeHash, Cursor, ObjType, Prop, TextEncoding, Value, ROOT,
};
use crate::iter::{DocIter, Keys, ListRange, MapRange, Spans, Values};
use std::ops::RangeBounds;
/// Methods for reading values from an automerge document
///
/// Many of the methods on this trait have an alternate `*_at` version which
/// takes an additional argument of `&[ChangeHash]`. This allows you to retrieve
/// the value at a particular point in the document history identified by the
/// given change hashes.
pub trait ReadDoc {
/// Get the parents of an object in the document tree.
///
/// See the documentation for [`Parents`] for more details.
///
/// ### Errors
///
/// Returns an error when the id given is not the id of an object in this document.
/// This function does not get the parents of scalar values contained within objects.
///
/// ### Experimental
///
/// This function may in future be changed to allow getting the parents from the id of a scalar
/// value.
fn parents<O: AsRef<ExId>>(&self, obj: O) -> Result<Parents<'_>, AutomergeError>;
/// Get the parents of the object `obj` as at `heads`
///
/// See [`Self::parents()`]
fn parents_at<O: AsRef<ExId>>(
&self,
obj: O,
heads: &[ChangeHash],
) -> Result<Parents<'_>, AutomergeError>;
/// Get the keys of the object `obj`.
///
/// For a map this returns the keys of the map.
/// For a list this returns the element ids (opids) encoded as strings.
fn keys<O: AsRef<ExId>>(&self, obj: O) -> Keys<'_>;
/// Get the keys of the object `obj` as at `heads`
///
/// See [`Self::keys()`]
fn keys_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> Keys<'_>;
/// Iterate over the object `obj` as at `heads`
///
/// See [`Self::iter()`]
fn iter_at<O: AsRef<ExId>>(&self, obj: O, heads: Option<&[ChangeHash]>) -> DocIter<'_>;
/// Iterate over all the objects in the document
///
/// The returned iterator will iterate over
/// [`DocObjItem`](crate::iter::DocObjItem)s, which are basically an (object
/// ID, property) pair. The property is represented by either a
/// [`MapRangeItem`](crate::iter::MapRangeItem),
/// [`ListRangeItem`](crate::iter::ListRangeItem), or a text span
/// represented by a [`ValueRef`](crate::ValueRef) depending on the type of
/// the object. The iterator iterates in "causal" order, which means that
/// objects which were created "first" in the documents history are visited
/// first, which in turn means that parent objects are visited before their
/// children.
fn iter(&self) -> DocIter<'_> {
self.iter_at(&ROOT, None)
}
/// Iterate over the keys and values of the map `obj` in the given range.
///
/// If the object correspoding to `obj` is a list then this will return an empty iterator
///
/// The returned iterator yields `(key, value, exid)` tuples, where the
/// third element is the ID of the operation which created the value.
fn map_range<'a, O: AsRef<ExId>, R: RangeBounds<String> + 'a>(
&'a self,
obj: O,
range: R,
) -> MapRange<'a>;
/// Iterate over the keys and values of the map `obj` in the given range as
/// at `heads`
///
/// If the object correspoding to `obj` is a list then this will return an empty iterator
///
/// The returned iterator yields `(key, value, exid)` tuples, where the
/// third element is the ID of the operation which created the value.
///
/// See [`Self::map_range()`]
fn map_range_at<'a, O: AsRef<ExId>, R: RangeBounds<String> + 'a>(
&'a self,
obj: O,
range: R,
heads: &[ChangeHash],
) -> MapRange<'a>;
/// Iterate over the indexes and values of the list or text `obj` in the given range.
///
/// The reuturned iterator yields `(index, value, exid)` tuples, where the third
/// element is the ID of the operation which created the value.
fn list_range<O: AsRef<ExId>, R: RangeBounds<usize>>(&self, obj: O, range: R) -> ListRange<'_>;
/// Iterate over the indexes and values of the list or text `obj` in the given range as at `heads`
///
/// The returned iterator yields `(index, value, exid)` tuples, where the third
/// element is the ID of the operation which created the value.
///
/// See [`Self::list_range()`]
fn list_range_at<O: AsRef<ExId>, R: RangeBounds<usize>>(
&self,
obj: O,
range: R,
heads: &[ChangeHash],
) -> ListRange<'_>;
/// Iterate over the values in a map, list, or text object
///
/// The returned iterator yields `(value, exid)` tuples, where the second element
/// is the ID of the operation which created the value.
fn values<O: AsRef<ExId>>(&self, obj: O) -> Values<'_>;
/// Iterate over the values in a map, list, or text object as at `heads`
///
/// The returned iterator yields `(value, exid)` tuples, where the second element
/// is the ID of the operation which created the value.
///
/// See [`Self::values()`]
fn values_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> Values<'_>;
/// Get the length of the given object.
///
/// If the given object is not in this document this method will return `0`
fn length<O: AsRef<ExId>>(&self, obj: O) -> usize;
/// Get the length of the given object as at `heads`
///
/// If the given object is not in this document this method will return `0`
///
/// See [`Self::length()`]
fn length_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> usize;
/// Get the type of this object, if it is an object.
fn object_type<O: AsRef<ExId>>(&self, obj: O) -> Result<ObjType, AutomergeError>;
/// Get all marks on a current sequence
fn marks<O: AsRef<ExId>>(&self, obj: O) -> Result<Vec<Mark>, AutomergeError>;
/// Get all marks on a sequence at a given heads
fn marks_at<O: AsRef<ExId>>(
&self,
obj: O,
heads: &[ChangeHash],
) -> Result<Vec<Mark>, AutomergeError>;
fn get_marks<O: AsRef<ExId>>(
&self,
obj: O,
index: usize,
heads: Option<&[ChangeHash]>,
) -> Result<MarkSet, AutomergeError>;
/// Get the string represented by the given text object.
fn text<O: AsRef<ExId>>(&self, obj: O) -> Result<String, AutomergeError>;
/// Get the string represented by the given text object as at `heads`, see
/// [`Self::text()`]
fn text_at<O: AsRef<ExId>>(
&self,
obj: O,
heads: &[ChangeHash],
) -> Result<String, AutomergeError>;
/// Return the sequence of text and block markers in the text object `obj`
fn spans<O: AsRef<ExId>>(&self, obj: O) -> Result<Spans<'_>, AutomergeError>;
/// Return the sequence of text and block markers in the text object `obj` as at `heads`
fn spans_at<O: AsRef<ExId>>(
&self,
obj: O,
heads: &[ChangeHash],
) -> Result<Spans<'_>, AutomergeError>;
/// Obtain the stable address (Cursor) for a [`usize`] position in a Sequence (either [`ObjType::List`] or [`ObjType::Text`]).
///
/// **This is equivalent to [`Self::get_cursor_moving()`] with `move_cursor` = `MoveCursor::After`.**
fn get_cursor<O: AsRef<ExId>, I: Into<CursorPosition>>(
&self,
obj: O,
position: I,
at: Option<&[ChangeHash]>,
) -> Result<Cursor, AutomergeError>;
/// Obtain the stable address (Cursor) for a [`usize`] position in a Sequence (either [`ObjType::List`] or [`ObjType::Text`]).
///
/// # Use cases
/// - User cursor tracking, to maintain contextual position while merging remote changes.
/// - Indexing sentences in a text field.
///
/// # Cursor movement
///
/// `move_cursor` determines how the cursor resolves its position if the item originally referenced at the given position is **removed** in later versions of the document. See [`MoveCursor`] for more details.
///
/// # Start/end cursors
/// If you'd like a cursor which follows the start (`position = 0`) or end (`position = sequence.length`) of the sequence, pass `CursorPosition::Start` or `CursorPosition::End` respectively.
///
/// Conceptually, start cursors behaves like a cursor pointed an index of `-1`. End cursors behave like a cursor pointed at `sequence.length`.
///
/// Note that `move_cursor` does not affect start/end cursors, as the start/end positions can never be removed.
///
/// To translate a cursor into a position, see [`Self::get_cursor_position()`].
fn get_cursor_moving<O: AsRef<ExId>, I: Into<CursorPosition>>(
&self,
obj: O,
position: I,
at: Option<&[ChangeHash]>,
move_cursor: MoveCursor,
) -> Result<Cursor, AutomergeError>;
/// Translate Cursor in a Sequence into an absolute position of type [`usize`].
///
/// Applicable only for Sequences (either [`ObjType::List`] or [`ObjType::Text`]).
///
/// To reverse the operation, see [`Self::get_cursor()`].
fn get_cursor_position<O: AsRef<ExId>>(
&self,
obj: O,
cursor: &Cursor,
at: Option<&[ChangeHash]>,
) -> Result<usize, AutomergeError>;
/// Get a value out of the document.
///
/// This returns a tuple of `(value, object ID)`. This is for two reasons:
///
/// 1. If `value` is an object (represented by [`Value::Object`]) then the ID
/// is the ID of that object. This can then be used to retrieve nested
/// values from the document.
/// 2. Even if `value` is a scalar, the ID represents the operation which
/// created the value. This is useful if there are conflicting values for
/// this key as each value is tagged with the ID.
///
/// In the case of a key which has conflicting values, this method will
/// return a single arbitrarily chosen value. This value will be chosen
/// deterministically on all nodes. If you want to get all the values for a
/// key use [`Self::get_all()`].
fn get<O: AsRef<ExId>, P: Into<Prop>>(
&self,
obj: O,
prop: P,
) -> Result<Option<(Value<'_>, ExId)>, AutomergeError>;
/// Get the value of the given key as at `heads`, see [`Self::get()`]
fn get_at<O: AsRef<ExId>, P: Into<Prop>>(
&self,
obj: O,
prop: P,
heads: &[ChangeHash],
) -> Result<Option<(Value<'_>, ExId)>, AutomergeError>;
fn hydrate<O: AsRef<ExId>>(
&self,
obj: O,
heads: Option<&[ChangeHash]>,
) -> Result<hydrate::Value, AutomergeError>;
/// Get all conflicting values out of the document at this prop that conflict.
///
/// If there are multiple conflicting values for a given key this method
/// will return all of them, with each value tagged by the ID of the
/// operation which created it.
fn get_all<O: AsRef<ExId>, P: Into<Prop>>(
&self,
obj: O,
prop: P,
) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError>;
/// Get all possibly conflicting values for a key as at `heads`
///
/// See [`Self::get_all()`]
fn get_all_at<O: AsRef<ExId>, P: Into<Prop>>(
&self,
obj: O,
prop: P,
heads: &[ChangeHash],
) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError>;
/// Get the hashes of the changes in this document that aren't transitive dependencies of the
/// given `heads`.
fn get_missing_deps(&self, heads: &[ChangeHash]) -> Vec<ChangeHash>;
/// Get a change by its hash.
fn get_change_by_hash(&self, hash: &ChangeHash) -> Option<Change>;
/// Return some statistics about the document
fn stats(&self) -> Stats;
fn text_encoding(&self) -> TextEncoding;
}
/// Statistics about the document
///
/// This is returned by [`ReadDoc::stats()`]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Stats {
/// The number of operations in the document
pub num_ops: u64,
/// The number of changes in the change graph for the document
pub num_changes: u64,
/// The number of actors in the document
pub num_actors: u64,
/// package name from cargo.toml ("automerge");
pub cargo_package_name: &'static str,
/// package version from cargo.toml
pub cargo_package_version: &'static str,
/// version of rustc used to compile this
pub rustc_version: &'static str,
}