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::{Item, ItemContent, ItemPtr, Prelim};
2use crate::branch::BranchPtr;
3use crate::moving::{Move, StickyIndex};
4use crate::transaction::{ReadTxn, TransactionMut};
5use crate::types::TypePtr;
6use crate::{Assoc, Out, ID};
7
8/// Struct used for iterating over the sequence of item's values with respect to a potential
9/// [Move] markers that may change their order.
10#[derive(Debug, Clone)]
11pub(crate) struct BlockIter {
12 branch: BranchPtr,
13 index: u32,
14 rel: u32,
15 next_item: Option<ItemPtr>,
16 curr_move: Option<ItemPtr>,
17 curr_move_start: Option<ItemPtr>,
18 curr_move_end: Option<ItemPtr>,
19 moved_stack: Vec<StackItem>,
20 reached_end: bool,
21}
22
23impl BlockIter {
24 pub fn new(branch: BranchPtr) -> Self {
25 let next_item = branch.start;
26 let reached_end = branch.start.is_none();
27 BlockIter {
28 branch,
29 next_item,
30 reached_end,
31 curr_move: None,
32 curr_move_start: None,
33 curr_move_end: None,
34 index: 0,
35 rel: 0,
36 moved_stack: Vec::default(),
37 }
38 }
39
40 #[inline]
41 pub fn rel(&self) -> u32 {
42 self.rel
43 }
44
45 #[inline]
46 pub fn finished(&self) -> bool {
47 (self.reached_end && self.curr_move.is_none()) || self.index == self.branch.content_len
48 }
49
50 #[inline]
51 pub fn next_item(&self) -> Option<ItemPtr> {
52 self.next_item
53 }
54
55 pub fn left(&self) -> Option<ItemPtr> {
56 if self.reached_end {
57 self.next_item
58 } else if let Some(item) = self.next_item.as_deref() {
59 item.left
60 } else {
61 None
62 }
63 }
64
65 pub fn right(&self) -> Option<ItemPtr> {
66 if self.reached_end {
67 None
68 } else {
69 self.next_item
70 }
71 }
72
73 pub fn move_to(&mut self, index: u32, txn: &mut TransactionMut) {
74 if index > self.index {
75 if !self.try_forward(txn, index - self.index) {
76 panic!("Block iter couldn't move forward");
77 }
78 } else if index < self.index {
79 self.backward(txn, self.index - index)
80 }
81 }
82
83 fn can_forward(&self, ptr: Option<ItemPtr>, len: u32) -> bool {
84 if !self.reached_end || self.curr_move.is_some() {
85 if len > 0 {
86 return true;
87 } else if let Some(item) = ptr.as_deref() {
88 return !item.is_countable()
89 || item.is_deleted()
90 || ptr == self.curr_move_end
91 || (self.reached_end && self.curr_move_end.is_none())
92 || item.moved != self.curr_move;
93 }
94 }
95
96 false
97 }
98
99 pub fn forward<T: ReadTxn>(&mut self, txn: &T, len: u32) {
100 if !self.try_forward(txn, len) {
101 panic!("Length exceeded")
102 }
103 }
104
105 pub fn try_forward<T: ReadTxn>(&mut self, txn: &T, mut len: u32) -> bool {
106 if len == 0 && self.next_item.is_none() {
107 return true;
108 }
109
110 if self.index + len > self.branch.content_len() || self.next_item.is_none() {
111 return false;
112 }
113
114 let mut item = self.next_item;
115 self.index += len;
116 if self.rel != 0 {
117 len += self.rel;
118 self.rel = 0;
119 }
120
121 let encoding = txn.store().offset_kind;
122 while self.can_forward(item, len) {
123 if item == self.curr_move_end
124 || (self.reached_end && self.curr_move_end.is_none() && self.curr_move.is_some())
125 {
126 item = self.curr_move; // we iterate to the right after the current condition
127 self.pop(txn);
128 } else if item.is_none() {
129 return false;
130 } else if let Some(i) = item.as_deref() {
131 if i.is_countable() && !i.is_deleted() && i.moved == self.curr_move && len > 0 {
132 let item_len = i.content_len(encoding);
133 if item_len > len {
134 self.rel = len;
135 len = 0;
136 break;
137 } else {
138 len -= item_len;
139 }
140 } else if let ItemContent::Move(m) = &i.content {
141 if i.moved == self.curr_move {
142 if let Some(ptr) = self.curr_move {
143 self.moved_stack.push(StackItem::new(
144 self.curr_move_start,
145 self.curr_move_end,
146 ptr,
147 ));
148 }
149
150 let (start, end) = m.get_moved_coords(txn);
151 self.curr_move = item;
152 self.curr_move_start = start;
153 self.curr_move_end = end;
154 item = start;
155 continue;
156 }
157 }
158 }
159
160 if self.reached_end {
161 return false;
162 }
163
164 match item.as_deref() {
165 Some(i) if i.right.is_some() => item = i.right,
166 _ => self.reached_end = true, //TODO: we need to ensure to iterate further if this.currMoveEnd === null
167 }
168 }
169
170 self.index -= len;
171 self.next_item = item;
172 true
173 }
174
175 fn reduce_moves(&mut self, txn: &mut TransactionMut) {
176 let mut item = self.next_item;
177 if item.is_some() {
178 while item == self.curr_move_start {
179 item = self.curr_move;
180 self.pop(txn);
181 }
182 self.next_item = item;
183 }
184 }
185
186 pub fn backward<T: ReadTxn>(&mut self, txn: &mut T, mut len: u32) {
187 if self.index < len {
188 panic!("Length exceeded");
189 }
190 self.index -= len;
191 let encoding = txn.store().offset_kind;
192 if self.reached_end {
193 if let Some(next_item) = self.next_item.as_deref() {
194 self.rel = if next_item.is_countable() && !next_item.is_deleted() {
195 next_item.content_len(encoding)
196 } else {
197 0
198 };
199 }
200 }
201 if self.rel >= len {
202 self.rel -= len;
203 return;
204 }
205 let mut item = self.next_item;
206 if let Some(i) = item.as_deref() {
207 if let ItemContent::Move(_) = &i.content {
208 item = i.left;
209 } else {
210 len += if i.is_countable() && !i.is_deleted() && i.moved == self.curr_move {
211 i.content_len(encoding)
212 } else {
213 0
214 };
215 len -= self.rel;
216 }
217 }
218 self.rel = 0;
219 while let Some(i) = item.as_deref() {
220 if len == 0 {
221 break;
222 }
223
224 if i.is_countable() && !i.is_deleted() && i.moved == self.curr_move {
225 let item_len = i.content_len(encoding);
226 if len < item_len {
227 self.rel = item_len - len;
228 len = 0;
229 } else {
230 len -= item_len;
231 }
232 if len == 0 {
233 break;
234 }
235 } else if let ItemContent::Move(m) = &i.content {
236 if i.moved == self.curr_move {
237 if let Some(curr_move) = self.curr_move {
238 self.moved_stack.push(StackItem::new(
239 self.curr_move_start,
240 self.curr_move_end,
241 curr_move,
242 ));
243 }
244 let (start, end) = m.get_moved_coords(txn);
245 self.curr_move = item;
246 self.curr_move_start = start;
247 self.curr_move_end = end;
248 item = start;
249 continue;
250 }
251 }
252
253 if item == self.curr_move_start {
254 item = self.curr_move; // we iterate to the left after the current condition
255 self.pop(txn);
256 }
257
258 item = if let Some(i) = item.as_deref() {
259 i.left
260 } else {
261 None
262 };
263 }
264 self.next_item = item;
265 }
266
267 /// We keep the moved-stack across several transactions. Local or remote changes can invalidate
268 /// "moved coords" on the moved-stack.
269 ///
270 /// The reason for this is that if assoc < 0, then getMovedCoords will return the target.right
271 /// item. While the computed item is on the stack, it is possible that a user inserts something
272 /// between target and the item on the stack. Then we expect that the newly inserted item
273 /// is supposed to be on the new computed item.
274 fn pop<T: ReadTxn>(&mut self, txn: &T) {
275 let mut start = None;
276 let mut end = None;
277 let mut moved = None;
278 if let Some(stack_item) = self.moved_stack.pop() {
279 moved = Some(stack_item.moved_to);
280 start = stack_item.start;
281 end = stack_item.end;
282
283 let moved_item = stack_item.moved_to;
284 if let ItemContent::Move(m) = &moved_item.content {
285 if m.start.assoc == Assoc::Before && (m.start.within_range(start))
286 || (m.end.within_range(end))
287 {
288 let (s, e) = m.get_moved_coords(txn);
289 start = s;
290 end = e;
291 }
292 }
293 }
294 self.curr_move = moved;
295 self.curr_move_start = start;
296 self.curr_move_end = end;
297 self.reached_end = false;
298 }
299
300 pub fn delete(&mut self, txn: &mut TransactionMut, mut len: u32) {
301 let mut item = self.next_item;
302 if self.index + len > self.branch.content_len() {
303 panic!("Length exceeded");
304 }
305
306 let encoding = txn.store().offset_kind;
307 let mut i: &Item;
308 while len > 0 {
309 while let Some(block) = item.as_deref() {
310 i = block;
311 if !i.is_deleted()
312 && i.is_countable()
313 && !self.reached_end
314 && len > 0
315 && i.moved == self.curr_move
316 && item != self.curr_move_end
317 {
318 if self.rel > 0 {
319 let mut id = i.id.clone();
320 id.clock += self.rel;
321 let store = txn.store_mut();
322 item = store
323 .blocks
324 .get_item_clean_start(&id)
325 .map(|s| store.materialize(s));
326 i = item.as_deref().unwrap();
327 self.rel = 0;
328 }
329 if len < i.content_len(encoding) {
330 let mut id = i.id.clone();
331 id.clock += len;
332 let store = txn.store_mut();
333 store
334 .blocks
335 .get_item_clean_start(&id)
336 .map(|s| store.materialize(s));
337 }
338 len -= i.content_len(encoding);
339 txn.delete(item.unwrap());
340 if i.right.is_some() {
341 item = i.right;
342 } else {
343 self.reached_end = true;
344 }
345 } else {
346 break;
347 }
348 }
349 if len > 0 {
350 self.next_item = item;
351 if self.try_forward(txn, 0) {
352 item = self.next_item;
353 } else {
354 panic!("Block iter couldn't move forward");
355 }
356 }
357 }
358 self.next_item = item;
359 }
360
361 pub(crate) fn slice<T: ReadTxn>(&mut self, txn: &T, buf: &mut [Out]) -> u32 {
362 let mut len = buf.len() as u32;
363 if self.index + len > self.branch.content_len() {
364 return 0;
365 }
366 self.index += len;
367 let mut next_item = self.next_item;
368 let encoding = txn.store().offset_kind;
369 let mut read = 0u32;
370 while len > 0 {
371 if !self.reached_end {
372 while let Some(item) = next_item {
373 if Some(item) != self.curr_move_end
374 && item.is_countable()
375 && !self.reached_end
376 && len > 0
377 {
378 if !item.is_deleted() && item.moved == self.curr_move {
379 // we're iterating inside of a block
380 let r = item
381 .content
382 .read(self.rel as usize, &mut buf[read as usize..])
383 as u32;
384 read += r;
385 len -= r;
386 if self.rel + r == item.content_len(encoding) {
387 self.rel = 0;
388 } else {
389 self.rel += r;
390 continue; // do not iterate to item.right
391 }
392 }
393
394 if item.right.is_some() {
395 next_item = item.right;
396 } else {
397 self.reached_end = true;
398 }
399 } else {
400 break;
401 }
402 }
403 if (!self.reached_end || self.curr_move.is_some()) && len > 0 {
404 // always set nextItem before any method call
405 self.next_item = next_item;
406 if !self.try_forward(txn, 0) || self.next_item.is_none() {
407 return read;
408 }
409 next_item = self.next_item;
410 }
411 } else if self.curr_move.is_some() {
412 // reached end but move stack still has some items,
413 // so we try to pop move frames and move on the
414 // first non-null right neighbor of the popped move block
415 while let Some(mov) = self.curr_move.as_deref() {
416 next_item = mov.right;
417 self.pop(txn);
418 if next_item.is_some() {
419 self.reached_end = false;
420 break;
421 }
422 }
423 } else {
424 // reached end and move stack is empty
425 next_item = None;
426 break;
427 }
428 }
429 self.next_item = next_item;
430 self.index -= len;
431 read
432 }
433
434 fn split_rel(&mut self, txn: &mut TransactionMut) {
435 if self.rel > 0 {
436 if let Some(ptr) = self.next_item {
437 let mut item_id = ptr.id().clone();
438 item_id.clock += self.rel;
439 let store = txn.store_mut();
440 self.next_item = store
441 .blocks
442 .get_item_clean_start(&item_id)
443 .map(|s| store.materialize(s));
444 self.rel = 0;
445 }
446 }
447 }
448
449 pub(crate) fn read_value<T: ReadTxn>(&mut self, txn: &T) -> Option<Out> {
450 let mut buf = [Out::default()];
451 if self.slice(txn, &mut buf) != 0 {
452 Some(std::mem::replace(&mut buf[0], Out::default()))
453 } else {
454 None
455 }
456 }
457
458 pub fn insert_contents<V: Prelim>(
459 &mut self,
460 txn: &mut TransactionMut,
461 value: V,
462 ) -> Option<ItemPtr> {
463 self.reduce_moves(txn);
464 self.split_rel(txn);
465 let id = {
466 let store = txn.store();
467 let client_id = store.client_id;
468 let clock = store.blocks.get_clock(&client_id);
469 ID::new(client_id, clock)
470 };
471 let parent = TypePtr::Branch(self.branch);
472 let right = self.right();
473 let left = self.left();
474 let (mut content, remainder) = value.into_content(txn);
475 let inner_ref = if let ItemContent::Type(inner_ref) = &mut content {
476 Some(BranchPtr::from(inner_ref))
477 } else {
478 None
479 };
480 let mut block = Item::new(
481 id,
482 left,
483 left.map(|ptr| ptr.last_id()),
484 right,
485 right.map(|r| *r.id()),
486 parent,
487 None,
488 content,
489 )?;
490 let mut block_ptr = ItemPtr::from(&mut block);
491
492 block_ptr.integrate(txn, 0);
493
494 txn.store_mut().blocks.push_block(block);
495
496 if let Some(remainder) = remainder {
497 remainder.integrate(txn, inner_ref.unwrap().into())
498 }
499
500 if let Some(item) = right.as_deref() {
501 self.next_item = item.right;
502 } else {
503 self.next_item = left;
504 self.reached_end = true;
505 }
506
507 Some(block_ptr)
508 }
509
510 pub fn insert_move(&mut self, txn: &mut TransactionMut, start: StickyIndex, end: StickyIndex) {
511 self.insert_contents(txn, Move::new(start, end, -1));
512 }
513
514 pub fn values<'a, 'txn, T: ReadTxn>(
515 &'a mut self,
516 txn: &'txn mut TransactionMut<'txn>,
517 ) -> Values<'a, 'txn> {
518 Values::new(self, txn)
519 }
520}
521
522pub struct Values<'a, 'txn> {
523 iter: &'a mut BlockIter,
524 txn: &'txn mut TransactionMut<'txn>,
525}
526
527impl<'a, 'txn> Values<'a, 'txn> {
528 fn new(iter: &'a mut BlockIter, txn: &'txn mut TransactionMut<'txn>) -> Self {
529 Values { iter, txn }
530 }
531}
532
533impl<'a, 'txn> Iterator for Values<'a, 'txn> {
534 type Item = Out;
535
536 fn next(&mut self) -> Option<Self::Item> {
537 if self.iter.reached_end || self.iter.index == self.iter.branch.content_len() {
538 None
539 } else {
540 let mut buf = [Out::default()];
541 if self.iter.slice(self.txn, &mut buf) != 0 {
542 Some(std::mem::replace(&mut buf[0], Out::default()))
543 } else {
544 None
545 }
546 }
547 }
548}
549
550#[derive(Debug, Clone)]
551struct StackItem {
552 start: Option<ItemPtr>,
553 end: Option<ItemPtr>,
554 moved_to: ItemPtr,
555}
556
557impl StackItem {
558 fn new(start: Option<ItemPtr>, end: Option<ItemPtr>, moved_to: ItemPtr) -> Self {
559 StackItem {
560 start,
561 end,
562 moved_to,
563 }
564 }
565}
566