oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1use crate::block::{ItemPtr, BLOCK_GC_REF_NUMBER, GC, HAS_ORIGIN, HAS_RIGHT_ORIGIN};
2use crate::types::TypePtr;
3use crate::updates::encoder::Encoder;
4use crate::ID;
5use std::ops::Deref;
6
7#[derive(Debug, Clone, Eq, PartialEq)]
8pub(crate) enum BlockSlice {
9 Item(ItemSlice),
10 GC(GCSlice),
11}
12
13impl BlockSlice {
14 pub fn clock_start(&self) -> u32 {
15 match self {
16 BlockSlice::Item(s) => s.clock_start(),
17 BlockSlice::GC(s) => s.clock_start(),
18 }
19 }
20
21 pub fn clock_end(&self) -> u32 {
22 match self {
23 BlockSlice::Item(s) => s.clock_end(),
24 BlockSlice::GC(s) => s.clock_end(),
25 }
26 }
27
28 pub(crate) fn as_item(&self) -> Option<ItemPtr> {
29 if let BlockSlice::Item(s) = self {
30 Some(s.ptr)
31 } else {
32 None
33 }
34 }
35
36 pub fn len(&self) -> u32 {
37 match self {
38 BlockSlice::Item(s) => s.len(),
39 BlockSlice::GC(s) => s.len(),
40 }
41 }
42
43 #[allow(dead_code)]
44 pub fn is_deleted(&self) -> bool {
45 match self {
46 BlockSlice::Item(s) => s.is_deleted(),
47 BlockSlice::GC(_) => true,
48 }
49 }
50
51 /// Trim a number of countable elements from the beginning of a current slice.
52 pub fn trim_start(&mut self, count: u32) {
53 match self {
54 BlockSlice::Item(s) => s.trim_start(count),
55 BlockSlice::GC(s) => s.trim_start(count),
56 }
57 }
58
59 /// Trim a number of countable elements from the end of a current slice.
60 pub fn trim_end(&mut self, count: u32) {
61 match self {
62 BlockSlice::Item(s) => s.trim_end(count),
63 BlockSlice::GC(s) => s.trim_end(count),
64 }
65 }
66
67 pub fn encode<E: Encoder>(&self, encoder: &mut E) {
68 match self {
69 BlockSlice::Item(s) => s.encode(encoder),
70 BlockSlice::GC(s) => s.encode(encoder),
71 }
72 }
73}
74
75impl From<ItemSlice> for BlockSlice {
76 fn from(slice: ItemSlice) -> Self {
77 BlockSlice::Item(slice)
78 }
79}
80
81impl From<GCSlice> for BlockSlice {
82 fn from(slice: GCSlice) -> Self {
83 BlockSlice::GC(slice)
84 }
85}
86
87/// Defines a logical slice of an underlying [Item]. Yrs blocks define a series of sequential
88/// updates performed by a single peer, while [ItemSlice]s enable to refer to a sub-range of these
89/// blocks without need to splice them.
90///
91/// If an underlying [Item] needs to be spliced to fit the boundaries defined by a corresponding
92/// [ItemSlice], this can be done with help of transaction (see: [Store::materialize]).
93#[derive(Debug, Clone, Eq, PartialEq)]
94pub(crate) struct ItemSlice {
95 pub ptr: ItemPtr,
96 pub start: u32,
97 pub end: u32,
98}
99
100impl ItemSlice {
101 pub fn new(ptr: ItemPtr, start: u32, end: u32) -> Self {
102 debug_assert!(start <= end);
103 ItemSlice { ptr, start, end }
104 }
105 pub fn clock_start(&self) -> u32 {
106 self.ptr.id.clock + self.start
107 }
108
109 pub fn clock_end(&self) -> u32 {
110 self.ptr.id.clock + self.end
111 }
112
113 /// Returns the number of elements (counted as Yjs ID clock length) of the block range described
114 /// by current [ItemSlice].
115 pub fn len(&self) -> u32 {
116 self.end - self.start + 1
117 }
118
119 /// Returns the first [ID] covered by this slice (inclusive).
120 pub fn id(&self) -> ID {
121 let mut id = self.ptr.id;
122 id.clock += self.start;
123 id
124 }
125
126 /// Returns the last [ID] covered by this slice (inclusive).
127 pub fn last_id(&self) -> ID {
128 let mut id = self.ptr.id;
129 id.clock += self.end;
130 id
131 }
132
133 /// Trim a number of countable elements from the beginning of a current slice.
134 pub(crate) fn trim_start(&mut self, count: u32) {
135 debug_assert!(count <= self.len());
136 self.start += count;
137 }
138
139 /// Trim a number of countable elements from the end of a current slice.
140 pub(crate) fn trim_end(&mut self, count: u32) {
141 debug_assert!(count <= self.len());
142 self.end -= count;
143 }
144
145 /// Returns true when current [ItemSlice] left boundary is equal to the boundary of the
146 /// [ItemPtr] this slice wraps.
147 pub fn adjacent_left(&self) -> bool {
148 self.start == 0
149 }
150
151 /// Returns true when current [ItemSlice] right boundary is equal to the boundary of the
152 /// [ItemPtr] this slice wraps.
153 pub fn adjacent_right(&self) -> bool {
154 self.end == self.ptr.len() - 1
155 }
156
157 /// Returns true when boundaries marked by the current [ItemSlice] match the boundaries
158 /// of the underlying [ItemPtr].
159 pub fn adjacent(&self) -> bool {
160 self.adjacent_left() && self.adjacent_right()
161 }
162
163 /// Checks if an underlying [Item] has been marked as deleted.
164 pub fn is_deleted(&self) -> bool {
165 self.ptr.is_deleted()
166 }
167
168 /// Checks if an underlying [Item] has been marked as countable.
169 pub fn is_countable(&self) -> bool {
170 self.ptr.is_countable()
171 }
172
173 /// Checks if provided `id` exists within the bounds described by current [ItemSlice].
174 pub fn contains_id(&self, id: &ID) -> bool {
175 let myself = self.ptr.id();
176 myself.client == id.client
177 && id.clock >= myself.clock + self.start
178 && id.clock <= myself.clock + self.end
179 }
180
181 pub fn encode<E: Encoder>(&self, encoder: &mut E) {
182 let item = self.ptr.deref();
183 let mut info = item.info();
184 let origin = if self.adjacent_left() {
185 item.origin
186 } else {
187 Some(ID::new(item.id.client, item.id.clock + self.start - 1))
188 };
189 if origin.is_some() {
190 info |= HAS_ORIGIN;
191 }
192 let cant_copy_parent_info = info & (HAS_ORIGIN | HAS_RIGHT_ORIGIN) == 0;
193 encoder.write_info(info);
194 if let Some(origin_id) = origin {
195 encoder.write_left_id(&origin_id);
196 }
197 if self.adjacent_right() {
198 if let Some(right_origin_id) = item.right_origin.as_ref() {
199 encoder.write_right_id(right_origin_id);
200 }
201 }
202 if cant_copy_parent_info {
203 match &item.parent {
204 TypePtr::Branch(branch) => {
205 if let Some(block) = branch.item {
206 encoder.write_parent_info(false);
207 encoder.write_left_id(block.id());
208 } else if let Some(name) = branch.name.as_deref() {
209 encoder.write_parent_info(true);
210 encoder.write_string(name);
211 } else {
212 unreachable!("Could not get parent branch info for item")
213 }
214 }
215 TypePtr::Named(name) => {
216 encoder.write_parent_info(true);
217 encoder.write_string(name);
218 }
219 TypePtr::ID(id) => {
220 encoder.write_parent_info(false);
221 encoder.write_left_id(id);
222 }
223 TypePtr::Unknown => {
224 panic!("Couldn't get item's parent")
225 }
226 }
227
228 if let Some(parent_sub) = item.parent_sub.as_ref() {
229 encoder.write_string(parent_sub.as_ref());
230 }
231 }
232 item.content.encode_slice(encoder, self.start, self.end);
233 }
234
235 /// Returns a [ItemSlice] wrapper for a [Item] identified as a right neighbor of this slice.
236 /// This method doesn't have to be equivalent of [Item::right]: if current slices's end range
237 /// is not an equivalent to the end of underlying [Item], a returned slice will contain the
238 /// same block that starts when the current ends.
239 ///
240 /// # Example
241 ///
242 /// If an underlying block is responsible for clock range of [0..10) and current slice is [2..8)
243 /// then right slice returned by this method will be [8..10).
244 pub fn right(&self) -> Option<ItemSlice> {
245 let last_clock = self.ptr.len() - 1;
246 if self.end == last_clock {
247 let item = self.ptr.deref();
248 let right_ptr = item.right?;
249 Some(ItemSlice::from(right_ptr))
250 } else {
251 Some(ItemSlice::new(self.ptr, self.end + 1, last_clock))
252 }
253 }
254
255 /// Returns a [ItemSlice] wrapper for a [Item] identified as a left neighbor of this slice.
256 /// This method doesn't have to be equivalent of [Item::right]: if current slices's start range
257 /// is not an equivalent to the start of underlying [Item], a returned slice will contain the
258 /// range that starts with current underlying block start and end where this slice starts.
259 ///
260 /// # Example
261 ///
262 /// If an underlying block is responsible for clock range of [0..10) and current slice is [2..8)
263 /// then right slice returned by this method will be [0..2).
264 pub fn left(&self) -> Option<ItemSlice> {
265 if self.start == 0 {
266 let item = self.ptr.deref();
267 let left_ptr = item.left?;
268 Some(ItemSlice::from(left_ptr))
269 } else {
270 Some(ItemSlice::new(self.ptr, 0, self.start - 1))
271 }
272 }
273}
274
275impl From<ItemPtr> for ItemSlice {
276 fn from(ptr: ItemPtr) -> Self {
277 ItemSlice::new(ptr, 0, ptr.len() - 1)
278 }
279}
280
281#[derive(Debug, Clone, Eq, PartialEq)]
282pub(crate) struct GCSlice {
283 pub start: u32,
284 pub end: u32,
285}
286
287impl GCSlice {
288 pub fn clock_start(&self) -> u32 {
289 self.start
290 }
291
292 pub fn clock_end(&self) -> u32 {
293 self.end
294 }
295
296 /// Trim a number of countable elements from the beginning of a current slice.
297 pub(crate) fn trim_start(&mut self, count: u32) {
298 debug_assert!(count <= self.len());
299 self.start += count;
300 }
301
302 /// Trim a number of countable elements from the end of a current slice.
303 pub(crate) fn trim_end(&mut self, count: u32) {
304 debug_assert!(count <= self.len());
305 self.end -= count;
306 }
307
308 pub fn len(&self) -> u32 {
309 self.end - self.start + 1
310 }
311
312 pub fn encode<E: Encoder>(&self, encoder: &mut E) {
313 encoder.write_info(BLOCK_GC_REF_NUMBER);
314 encoder.write_len(self.len());
315 }
316}
317
318impl From<GC> for GCSlice {
319 fn from(gc: GC) -> Self {
320 GCSlice {
321 start: gc.start,
322 end: gc.end,
323 }
324 }
325}
326