cola/text_edit.rs
1use core::ops::Range;
2
3use crate::*;
4
5/// A range of text inserted into a [`Replica`].
6///
7/// Despite the name, this type does not contain the text string itself, only
8/// the [`ReplicaId`] of the [`Replica`] that inserted it and its temporal
9/// range in it. These can be accessed via the
10/// [`inserted_by`](Text::inserted_by) and
11/// [`temporal_range`](Text::temporal_range) methods respectively.
12#[derive(Clone, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "encode", derive(serde::Serialize, serde::Deserialize))]
14pub struct Text {
15 pub(crate) inserted_by: ReplicaId,
16 pub(crate) range: Range<Length>,
17}
18
19impl core::fmt::Debug for Text {
20 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
21 write!(f, "{:x}.{:?}", self.inserted_by, self.range)
22 }
23}
24
25impl Text {
26 #[inline]
27 pub(crate) fn end(&self) -> Length {
28 self.range.end
29 }
30
31 /// Returns the [`ReplicaId`] of the [`Replica`] that inserted this text.
32 ///
33 /// # Examples
34 ///
35 /// ```
36 /// # use cola::Replica;
37 /// let mut replica1 = Replica::new(1, 0);
38 ///
39 /// let insertion = replica1.inserted(0, 1);
40 ///
41 /// assert_eq!(insertion.text().inserted_by(), replica1.id());
42 /// ```
43 #[inline]
44 pub fn inserted_by(&self) -> ReplicaId {
45 self.inserted_by
46 }
47
48 #[inline]
49 pub(crate) fn len(&self) -> Length {
50 self.range.len()
51 }
52
53 #[inline]
54 pub(crate) fn new(inserted_by: ReplicaId, range: Range<Length>) -> Self {
55 Self { inserted_by, range }
56 }
57
58 #[inline]
59 pub(crate) fn start(&self) -> Length {
60 self.range.start
61 }
62
63 /// Returns the temporal range of this text in the `Replica` that inserted
64 /// it.
65 ///
66 /// Each `Replica` keeps an internal character clock that starts at zero
67 /// and is incremented each time the [`inserted`](crate::Replica::inserted)
68 /// method is called by an amount equal to the length of the inserted text.
69 ///
70 /// Since the insertion history of *a single* `Replica` is linear and
71 /// immutable, this clock can be used to uniquely identify each character
72 /// in the document without knowing what the actual text associated with
73 /// its insertion is.
74 ///
75 /// Note that this range has absolutely nothing to do with the *spatial
76 /// offset* at which the text was inserted. Its start and end simply refer
77 /// to the values of the character clock of the `Replica` that inserted the
78 /// `Text` before and after the insertion.
79 ///
80 /// It's up to you to decide how to map these temporal ranges to the actual
81 /// text contents inserted by the various peers.
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// # use cola::Replica;
87 /// let mut replica1 = Replica::new(1, 0);
88 ///
89 /// // Peer 1 inserts 1, 2, 3 and 4 characters at the start of the
90 /// // document.
91 /// let insertion1 = replica1.inserted(0, 1);
92 /// let insertion2 = replica1.inserted(0, 2);
93 /// let insertion3 = replica1.inserted(0, 3);
94 /// let insertion4 = replica1.inserted(0, 4);
95 ///
96 /// // Notice how:
97 /// // - the temporal range of the first insertion starts at zero;
98 /// // - the start of each range is equal to the end of the previous one;
99 /// // - the length of each range matches the one passed to
100 /// // `replica1.inserted`.
101 ///
102 /// assert_eq!(insertion1.text().temporal_range(), 0..1);
103 /// assert_eq!(insertion2.text().temporal_range(), 1..3);
104 /// assert_eq!(insertion3.text().temporal_range(), 3..6);
105 /// assert_eq!(insertion4.text().temporal_range(), 6..10);
106 /// ```
107 #[inline]
108 pub fn temporal_range(&self) -> Range<Length> {
109 self.range.clone()
110 }
111}