yrs/
block.rs

1use crate::branch::{Branch, BranchPtr};
2use crate::doc::{DocAddr, OffsetKind};
3use crate::encoding::read::Error;
4use crate::error::UpdateError;
5use crate::gc::GCCollector;
6use crate::moving::Move;
7use crate::slice::{BlockSlice, GCSlice, ItemSlice};
8use crate::store::Store;
9use crate::transaction::TransactionMut;
10use crate::types::text::update_current_attributes;
11use crate::types::{Attrs, TypePtr, TypeRef};
12use crate::undo::UndoStack;
13use crate::updates::decoder::{Decode, Decoder};
14use crate::updates::encoder::{Encode, Encoder};
15use crate::utils::OptionExt;
16use crate::{Any, DeleteSet, Doc, Options, Out, Transact};
17use serde::{Deserialize, Serialize};
18use smallstr::SmallString;
19use std::collections::HashSet;
20use std::convert::TryFrom;
21use std::fmt::Formatter;
22use std::hash::Hash;
23use std::ops::{Deref, DerefMut};
24use std::panic;
25use std::ptr::NonNull;
26use std::sync::Arc;
27
28/// Bit flag used to identify [Item::GC].
29pub const BLOCK_GC_REF_NUMBER: u8 = 0;
30
31/// Bit flag used to identify items with content of type [ItemContent::Deleted].
32pub const BLOCK_ITEM_DELETED_REF_NUMBER: u8 = 1;
33
34/// Bit flag used to identify items with content of type [ItemContent::JSON].
35pub const BLOCK_ITEM_JSON_REF_NUMBER: u8 = 2;
36
37/// Bit flag used to identify items with content of type [ItemContent::Binary].
38pub const BLOCK_ITEM_BINARY_REF_NUMBER: u8 = 3;
39
40/// Bit flag used to identify items with content of type [ItemContent::String].
41pub const BLOCK_ITEM_STRING_REF_NUMBER: u8 = 4;
42
43/// Bit flag used to identify items with content of type [ItemContent::Embed].
44pub const BLOCK_ITEM_EMBED_REF_NUMBER: u8 = 5;
45
46/// Bit flag used to identify items with content of type [ItemContent::Format].
47pub const BLOCK_ITEM_FORMAT_REF_NUMBER: u8 = 6;
48
49/// Bit flag used to identify items with content of type [ItemContent::Number].
50pub const BLOCK_ITEM_TYPE_REF_NUMBER: u8 = 7;
51
52/// Bit flag used to identify items with content of type [ItemContent::Any].
53pub const BLOCK_ITEM_ANY_REF_NUMBER: u8 = 8;
54
55/// Bit flag used to identify items with content of type [ItemContent::Doc].
56pub const BLOCK_ITEM_DOC_REF_NUMBER: u8 = 9;
57
58/// Bit flag used to identify [Item::Skip].
59pub const BLOCK_SKIP_REF_NUMBER: u8 = 10;
60
61/// Bit flag used to identify items with content of type [ItemContent::Move].
62pub const BLOCK_ITEM_MOVE_REF_NUMBER: u8 = 11;
63
64/// Bit flag used to tell if encoded item has right origin defined.
65pub const HAS_RIGHT_ORIGIN: u8 = 0b01000000;
66
67/// Bit flag used to tell if encoded item has left origin defined.
68pub const HAS_ORIGIN: u8 = 0b10000000;
69
70/// Bit flag used to tell if encoded item has a parent subtitle defined. Subtitles are used only
71/// for blocks which act as map-like types entries.
72pub const HAS_PARENT_SUB: u8 = 0b00100000;
73
74/// Globally unique client identifier. No two active peers are allowed to share the same [ClientID].
75/// If that happens, following updates may cause document store to be corrupted and desync in a result.
76pub type ClientID = u64;
77
78/// Block identifier, which allows to uniquely identify any element insertion in a global scope
79/// (across different replicas of the same document). It consists of client ID (which is a unique
80/// document replica identifier) and monotonically incrementing clock value.
81///
82/// [ID] corresponds to a [Lamport timestamp](https://en.wikipedia.org/wiki/Lamport_timestamp) in
83/// terms of its properties and guarantees.
84#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize)]
85pub struct ID {
86    /// Unique identifier of a client.
87    pub client: ClientID,
88
89    /// Monotonically incrementing sequence number, which informs about order of inserted item
90    /// operation in a scope of a given `client`. This value doesn't have to increase by 1, but
91    /// instead is increased by number of countable elements which make a content of an inserted
92    /// block.
93    pub clock: u32,
94}
95
96impl ID {
97    pub fn new(client: ClientID, clock: u32) -> Self {
98        ID { client, clock }
99    }
100}
101
102pub(crate) enum BlockCell {
103    GC(GC),
104    Block(Box<Item>),
105}
106
107impl PartialEq for BlockCell {
108    fn eq(&self, other: &Self) -> bool {
109        match (self, other) {
110            (BlockCell::GC(a), BlockCell::GC(b)) => a == b,
111            (BlockCell::Block(a), BlockCell::Block(b)) => a.id == b.id,
112            _ => false,
113        }
114    }
115}
116
117impl std::fmt::Debug for BlockCell {
118    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
119        match self {
120            BlockCell::GC(gc) => write!(f, "gc({}..={})", gc.start, gc.end),
121            BlockCell::Block(item) => item.fmt(f),
122        }
123    }
124}
125
126impl BlockCell {
127    /// Returns the first clock sequence number of a current block.
128    pub fn clock_start(&self) -> u32 {
129        match self {
130            BlockCell::GC(gc) => gc.start,
131            BlockCell::Block(item) => item.id.clock,
132        }
133    }
134
135    /// Returns the last clock sequence number of a current block.
136    pub fn clock_end(&self) -> u32 {
137        match self {
138            BlockCell::GC(gc) => gc.end,
139            BlockCell::Block(item) => item.id.clock + item.len - 1,
140        }
141    }
142
143    /// Returns a range of first and the last clock sequence numbers that belong to a current block.
144    #[inline]
145    pub fn clock_range(&self) -> (u32, u32) {
146        match self {
147            BlockCell::GC(gc) => (gc.start, gc.end),
148            BlockCell::Block(block) => block.clock_range(),
149        }
150    }
151
152    pub fn is_deleted(&self) -> bool {
153        match self {
154            BlockCell::GC(_) => true,
155            BlockCell::Block(item) => item.is_deleted(),
156        }
157    }
158
159    pub fn len(&self) -> u32 {
160        match self {
161            BlockCell::GC(gc) => gc.end - gc.start + 1,
162            BlockCell::Block(block) => block.len(),
163        }
164    }
165
166    pub fn as_slice(&self) -> BlockSlice {
167        match self {
168            BlockCell::GC(gc) => BlockSlice::GC(GCSlice::from(gc.clone())),
169            BlockCell::Block(item) => {
170                let ptr = ItemPtr::from(item);
171                BlockSlice::Item(ItemSlice::from(ptr))
172            }
173        }
174    }
175
176    pub fn as_item(&self) -> Option<ItemPtr> {
177        if let BlockCell::Block(item) = self {
178            Some(ItemPtr::from(item))
179        } else {
180            None
181        }
182    }
183}
184
185impl From<Box<Item>> for BlockCell {
186    fn from(value: Box<Item>) -> Self {
187        BlockCell::Block(value)
188    }
189}
190
191impl From<GC> for BlockCell {
192    fn from(gc: GC) -> Self {
193        BlockCell::GC(gc)
194    }
195}
196
197#[derive(Debug, Copy, Clone, PartialEq)]
198pub(crate) struct GC {
199    pub start: u32,
200    pub end: u32,
201}
202
203impl GC {
204    #[inline]
205    pub fn new(start: u32, end: u32) -> Self {
206        GC { start, end }
207    }
208
209    pub fn len(&self) -> u32 {
210        self.end - self.start + 1
211    }
212}
213
214impl From<BlockRange> for GC {
215    fn from(value: BlockRange) -> Self {
216        let start = value.id.clock;
217        let end = start + value.len - 1;
218        GC { start, end }
219    }
220}
221
222impl Encode for GC {
223    fn encode<E: Encoder>(&self, encoder: &mut E) {
224        encoder.write_info(BLOCK_GC_REF_NUMBER);
225        encoder.write_len(self.len());
226    }
227}
228
229/// A raw [Item] pointer. As the underlying block doesn't move it's in-memory location, [ItemPtr]
230/// can be considered a pinned object.
231#[repr(transparent)]
232#[derive(Clone, Copy, Hash)]
233pub struct ItemPtr(NonNull<Item>);
234
235unsafe impl Send for ItemPtr {}
236unsafe impl Sync for ItemPtr {}
237
238impl ItemPtr {
239    pub(crate) fn redo<M>(
240        &mut self,
241        txn: &mut TransactionMut,
242        redo_items: &HashSet<ItemPtr>,
243        items_to_delete: &DeleteSet,
244        s1: &UndoStack<M>,
245        s2: &UndoStack<M>,
246    ) -> Option<ItemPtr> {
247        let self_ptr = self.clone();
248        let item = self.deref_mut();
249        if let Some(redone) = item.redone.as_ref() {
250            let slice = txn.store.blocks.get_item_clean_start(redone)?;
251            return Some(txn.store.materialize(slice));
252        }
253
254        let mut parent_block = item.parent.as_branch().and_then(|b| b.item);
255        // make sure that parent is redone
256        if let Some(mut parent) = parent_block.clone() {
257            if parent.is_deleted() {
258                // try to undo parent if it will be undone anyway
259                if parent.redone.is_none()
260                    && (!redo_items.contains(&parent)
261                        || parent
262                            .redo(txn, redo_items, items_to_delete, s1, s2)
263                            .is_none())
264                {
265                    return None;
266                }
267                let mut redone = parent.redone;
268                while let Some(id) = redone.as_ref() {
269                    parent_block = txn
270                        .store
271                        .blocks
272                        .get_item_clean_start(id)
273                        .map(|slice| txn.store.materialize(slice));
274                    redone = parent_block.and_then(|ptr| ptr.redone);
275                }
276            }
277        }
278        let parent_branch = BranchPtr::from(if let Some(item) = parent_block.as_deref() {
279            if let ItemContent::Type(b) = &item.content {
280                b.as_ref()
281            } else {
282                item.parent.as_branch().unwrap()
283            }
284        } else {
285            item.parent.as_branch().unwrap()
286        });
287
288        let mut left = None;
289        let mut right = None;
290        if let Some(sub) = item.parent_sub.as_ref() {
291            if item.right.is_some() {
292                left = Some(self_ptr);
293                // Iterate right while is in itemsToDelete
294                // If it is intended to delete right while item is redone,
295                // we can expect that item should replace right.
296                while let Some(left_item) = left.as_deref() {
297                    if let Some(left_right) = left_item.right {
298                        let id = left_right.id();
299                        if left_right.redone.is_some()
300                            || items_to_delete.is_deleted(id)
301                            || s1.is_deleted(id)
302                            || s2.is_deleted(id)
303                        {
304                            // follow redone
305                            left = Some(left_right);
306                            while let Some(item) = left.as_deref() {
307                                if let Some(id) = item.redone.as_ref() {
308                                    left = match txn.store.blocks.get_item_clean_start(id) {
309                                        None => break,
310                                        Some(slice) => {
311                                            let ptr = txn.store.materialize(slice);
312                                            txn.merge_blocks.push(ptr.id().clone());
313                                            Some(ptr)
314                                        }
315                                    };
316                                } else {
317                                    break;
318                                }
319                            }
320                            continue;
321                        }
322                    }
323                    break;
324                }
325
326                if let Some(left_item) = left.as_deref() {
327                    if left_item.right.is_some() {
328                        // It is not possible to redo this item because it conflicts with a
329                        // change from another client
330                        return None;
331                    }
332                }
333            } else {
334                left = parent_branch.map.get(sub).cloned();
335            }
336        } else {
337            // Is an array item. Insert at the old position
338            left = item.left;
339            right = Some(self_ptr);
340            // find next cloned_redo items
341            while let Some(left_item) = left.clone().as_deref() {
342                let mut left_trace = left;
343                while let Some(trace) = left_trace.as_deref() {
344                    let p = trace.parent.as_branch().and_then(|p| p.item);
345                    if parent_block != p {
346                        left_trace = if let Some(redone) = trace.redone.as_ref() {
347                            let slice = txn.store.blocks.get_item_clean_start(redone);
348                            slice.map(|s| txn.store.materialize(s))
349                        } else {
350                            None
351                        };
352                    } else {
353                        break;
354                    }
355                }
356                if let Some(trace) = left_trace.as_deref() {
357                    let p = trace.parent.as_branch().and_then(|p| p.item);
358                    if parent_block == p {
359                        left = left_trace;
360                        break;
361                    }
362                }
363                left = left_item.left.clone();
364            }
365
366            while let Some(right_item) = right.clone().as_deref() {
367                let mut right_trace = right;
368                // trace redone until parent matches
369                while let Some(trace) = right_trace.as_deref() {
370                    let p = trace.parent.as_branch().and_then(|p| p.item);
371                    if parent_block != p {
372                        right_trace = if let Some(redone) = trace.redone.as_ref() {
373                            let slice = txn.store.blocks.get_item_clean_start(redone);
374                            slice.map(|s| txn.store.materialize(s))
375                        } else {
376                            None
377                        };
378                    } else {
379                        break;
380                    }
381                }
382                if let Some(trace) = right_trace.as_deref() {
383                    let p = trace.parent.as_branch().and_then(|p| p.item);
384                    if parent_block == p {
385                        right = right_trace;
386                        break;
387                    }
388                }
389                right = right_item.right.clone();
390            }
391        }
392
393        let next_clock = txn.store.get_local_state();
394        let next_id = ID::new(txn.store.client_id, next_clock);
395        let mut redone_item = Item::new(
396            next_id,
397            left,
398            left.map(|p| p.last_id()),
399            right,
400            right.map(|p| *p.id()),
401            TypePtr::Branch(parent_branch),
402            item.parent_sub.clone(),
403            item.content.clone(),
404        )?;
405        item.redone = Some(*redone_item.id());
406        redone_item.info.set_keep();
407        let mut block_ptr = ItemPtr::from(&mut redone_item);
408
409        block_ptr.integrate(txn, 0);
410
411        txn.store_mut().blocks.push_block(redone_item);
412        Some(block_ptr)
413    }
414
415    pub(crate) fn keep(&self, keep: bool) {
416        let mut curr = Some(*self);
417        while let Some(item) = curr.as_deref_mut() {
418            if item.info.is_keep() == keep {
419                break;
420            } else {
421                if keep {
422                    item.info.set_keep();
423                } else {
424                    item.info.clear_keep();
425                }
426                curr = item.parent.as_branch().and_then(|b| b.item);
427            }
428        }
429    }
430
431    pub(crate) fn delete_as_cleanup(&self, txn: &mut TransactionMut, is_local: bool) {
432        txn.delete(*self);
433        if is_local {
434            txn.delete_set.insert(*self.id(), self.len());
435        }
436    }
437
438    pub(crate) fn splice(&mut self, offset: u32, encoding: OffsetKind) -> Option<Box<Item>> {
439        let self_ptr = self.clone();
440        if offset == 0 {
441            None
442        } else {
443            let item = self.deref_mut();
444            let client = item.id.client;
445            let clock = item.id.clock;
446            let len = item.len;
447            let content = item.content.splice(offset as usize, encoding).unwrap();
448            item.len = offset;
449            let mut new = Box::new(Item {
450                id: ID::new(client, clock + offset),
451                len: len - offset,
452                left: Some(self_ptr),
453                right: item.right.clone(),
454                origin: Some(ID::new(client, clock + offset - 1)),
455                right_origin: item.right_origin.clone(),
456                content,
457                parent: item.parent.clone(),
458                moved: item.moved.clone(),
459                parent_sub: item.parent_sub.clone(),
460                info: item.info.clone(),
461                redone: item.redone.map(|id| ID::new(id.client, id.clock + offset)),
462            });
463            let new_ptr = ItemPtr::from(&mut new);
464
465            if let Some(right) = item.right.as_deref_mut() {
466                right.left = Some(new_ptr);
467            }
468
469            if let Some(parent_sub) = item.parent_sub.as_ref() {
470                if item.right.is_none() {
471                    // update parent.map
472                    if let TypePtr::Branch(mut branch) = item.parent {
473                        branch.map.insert(parent_sub.clone(), new_ptr);
474                    }
475                }
476            }
477
478            item.right = Some(new_ptr);
479
480            Some(new)
481        }
482    }
483
484    /// Integrates current block into block store.
485    /// If it returns true, it means that the block should be deleted after being added to a block store.
486    pub(crate) fn integrate(&mut self, txn: &mut TransactionMut, offset: u32) -> bool {
487        let self_ptr = self.clone();
488        let this = self.deref_mut();
489        let store = txn.store_mut();
490        let encoding = store.offset_kind;
491        if offset > 0 {
492            // offset could be > 0 only in context of Update::integrate,
493            // is such case offset kind in use always means Yjs-compatible offset (utf-16)
494            this.id.clock += offset;
495            this.left = store
496                .blocks
497                .get_item_clean_end(&ID::new(this.id.client, this.id.clock - 1))
498                .map(|slice| store.materialize(slice));
499            this.origin = this.left.as_deref().map(|b: &Item| b.last_id());
500            this.content = this
501                .content
502                .splice(offset as usize, OffsetKind::Utf16)
503                .unwrap();
504            this.len -= offset;
505        }
506
507        let parent = match &this.parent {
508            TypePtr::Branch(branch) => Some(*branch),
509            TypePtr::Named(name) => {
510                let branch = store.get_or_create_type(name.clone(), TypeRef::Undefined);
511                this.parent = TypePtr::Branch(branch);
512                Some(branch)
513            }
514            TypePtr::ID(id) => {
515                if let Some(item) = store.blocks.get_item(id) {
516                    if let Some(branch) = item.as_branch() {
517                        this.parent = TypePtr::Branch(branch);
518                        Some(branch)
519                    } else {
520                        None
521                    }
522                } else {
523                    None
524                }
525            }
526            TypePtr::Unknown => return true,
527        };
528
529        let left: Option<&Item> = this.left.as_deref();
530        let right: Option<&Item> = this.right.as_deref();
531
532        let right_is_null_or_has_left = match right {
533            None => true,
534            Some(i) => i.left.is_some(),
535        };
536        let left_has_other_right_than_self = match left {
537            Some(i) => i.right != this.right,
538            _ => false,
539        };
540
541        if let Some(mut parent_ref) = parent {
542            if (left.is_none() && right_is_null_or_has_left) || left_has_other_right_than_self {
543                // set the first conflicting item
544                let mut o = if let Some(left) = left {
545                    left.right
546                } else if let Some(sub) = &this.parent_sub {
547                    let mut o = parent_ref.map.get(sub).cloned();
548                    while let Some(item) = o.as_deref() {
549                        if item.left.is_some() {
550                            o = item.left.clone();
551                            continue;
552                        }
553                        break;
554                    }
555                    o.clone()
556                } else {
557                    parent_ref.start
558                };
559
560                let mut left = this.left.clone();
561                let mut conflicting_items = HashSet::new();
562                let mut items_before_origin = HashSet::new();
563
564                // Let c in conflicting_items, b in items_before_origin
565                // ***{origin}bbbb{this}{c,b}{c,b}{o}***
566                // Note that conflicting_items is a subset of items_before_origin
567                while let Some(item) = o {
568                    if Some(item) == this.right {
569                        break;
570                    }
571
572                    items_before_origin.insert(item);
573                    conflicting_items.insert(item);
574                    if this.origin == item.origin {
575                        // case 1
576                        if item.id.client < this.id.client {
577                            left = Some(item.clone());
578                            conflicting_items.clear();
579                        } else if this.right_origin == item.right_origin {
580                            // `self` and `item` are conflicting and point to the same integration
581                            // points. The id decides which item comes first. Since `self` is to
582                            // the left of `item`, we can break here.
583                            break;
584                        }
585                    } else {
586                        if let Some(origin_ptr) = item
587                            .origin
588                            .as_ref()
589                            .and_then(|id| store.blocks.get_item(id))
590                        {
591                            if items_before_origin.contains(&origin_ptr) {
592                                if !conflicting_items.contains(&origin_ptr) {
593                                    left = Some(item.clone());
594                                    conflicting_items.clear();
595                                }
596                            } else {
597                                break;
598                            }
599                        } else {
600                            break;
601                        }
602                    }
603                    o = item.right.clone();
604                }
605                this.left = left;
606            }
607
608            if this.parent_sub.is_none() {
609                if let Some(item) = this.left.as_deref() {
610                    if item.parent_sub.is_some() {
611                        this.parent_sub = item.parent_sub.clone();
612                    } else if let Some(item) = this.right.as_deref() {
613                        this.parent_sub = item.parent_sub.clone();
614                    }
615                }
616            }
617
618            // reconnect left/right
619            if let Some(left) = this.left.as_deref_mut() {
620                this.right = left.right.replace(self_ptr);
621            } else {
622                let r = if let Some(parent_sub) = &this.parent_sub {
623                    // update parent map/start if necessary
624                    let mut r = parent_ref.map.get(parent_sub).cloned();
625                    while let Some(item) = r {
626                        if item.left.is_some() {
627                            r = item.left;
628                        } else {
629                            break;
630                        }
631                    }
632                    r
633                } else {
634                    let start = parent_ref.start.replace(self_ptr);
635                    start
636                };
637                this.right = r;
638            }
639
640            if let Some(right) = this.right.as_deref_mut() {
641                right.left = Some(self_ptr);
642            } else if let Some(parent_sub) = &this.parent_sub {
643                // set as current parent value if right === null and this is parentSub
644                parent_ref.map.insert(parent_sub.clone(), self_ptr);
645                if let Some(mut left) = this.left {
646                    #[cfg(feature = "weak")]
647                    {
648                        if left.info.is_linked() {
649                            // inherit links from the block we're overriding
650                            left.info.clear_linked();
651                            this.info.set_linked();
652                            let all_links = &mut txn.store.linked_by;
653                            if let Some(linked_by) = all_links.remove(&left) {
654                                all_links.insert(self_ptr, linked_by);
655                                // since left is being deleted, it will remove
656                                // its links from store.linkedBy anyway
657                            }
658                        }
659                    }
660                    // this is the current attribute value of parent. delete right
661                    txn.delete(left);
662                }
663            }
664
665            // adjust length of parent
666            if this.parent_sub.is_none() && !this.is_deleted() {
667                if this.is_countable() {
668                    // adjust length of parent
669                    parent_ref.block_len += this.len;
670                    parent_ref.content_len += this.content_len(encoding);
671                }
672                #[cfg(feature = "weak")]
673                match (this.left, this.right) {
674                    (Some(l), Some(r)) if l.info.is_linked() || r.info.is_linked() => {
675                        crate::types::weak::join_linked_range(self_ptr, txn)
676                    }
677                    _ => {}
678                }
679            }
680
681            // check if this item is in a moved range
682            let left_moved = this.left.and_then(|i| i.moved);
683            let right_moved = this.right.and_then(|i| i.moved);
684            if left_moved.is_some() || right_moved.is_some() {
685                if left_moved == right_moved {
686                    this.moved = left_moved;
687                } else {
688                    #[inline]
689                    fn try_integrate(mut item: ItemPtr, txn: &mut TransactionMut) {
690                        let ptr = item.clone();
691                        if let ItemContent::Move(m) = &mut item.content {
692                            if !m.is_collapsed() {
693                                m.integrate_block(txn, ptr);
694                            }
695                        }
696                    }
697
698                    if let Some(ptr) = left_moved {
699                        try_integrate(ptr, txn);
700                    }
701
702                    if let Some(ptr) = right_moved {
703                        try_integrate(ptr, txn);
704                    }
705                }
706            }
707
708            match &mut this.content {
709                ItemContent::Deleted(len) => {
710                    txn.delete_set.insert(this.id, *len);
711                    this.mark_as_deleted();
712                }
713                ItemContent::Move(m) => m.integrate_block(txn, self_ptr),
714                ItemContent::Doc(parent_doc, doc) => {
715                    *parent_doc = Some(txn.doc().clone());
716                    {
717                        let mut child_txn = doc.transact_mut();
718                        child_txn.store.parent = Some(self_ptr);
719                    }
720                    let subdocs = txn.subdocs.get_or_init();
721                    subdocs.added.insert(DocAddr::new(doc), doc.clone());
722                    if doc.should_load() {
723                        subdocs.loaded.insert(doc.addr(), doc.clone());
724                    }
725                }
726                ItemContent::Format(_, _) => {
727                    // @todo searchmarker are currently unsupported for rich text documents
728                    // /** @type {AbstractType<any>} */ (item.parent)._searchMarker = null
729                }
730                ItemContent::Type(branch) => {
731                    let ptr = BranchPtr::from(branch);
732                    #[cfg(feature = "weak")]
733                    if let TypeRef::WeakLink(source) = &ptr.type_ref {
734                        source.materialize(txn, ptr);
735                    }
736                }
737                _ => {
738                    // other types don't define integration-specific actions
739                }
740            }
741            txn.add_changed_type(parent_ref, this.parent_sub.clone());
742            if this.info.is_linked() {
743                if let Some(links) = txn.store.linked_by.get(&self_ptr).cloned() {
744                    // notify links about changes
745                    for link in links.iter() {
746                        txn.add_changed_type(*link, this.parent_sub.clone());
747                    }
748                }
749            }
750            let parent_deleted = if let TypePtr::Branch(ptr) = &this.parent {
751                if let Some(block) = ptr.item {
752                    block.is_deleted()
753                } else {
754                    false
755                }
756            } else {
757                false
758            };
759            if parent_deleted || (this.parent_sub.is_some() && this.right.is_some()) {
760                // delete if parent is deleted or if this is not the current attribute value of parent
761                true
762            } else {
763                false
764            }
765        } else {
766            true
767        }
768    }
769
770    /// Squashes two blocks together. Returns true if it succeeded. Squashing is possible only if
771    /// blocks are of the same type, their contents are of the same type, they belong to the same
772    /// parent data structure, their IDs are sequenced directly one after another and they point to
773    /// each other as their left/right neighbors respectively.
774    pub(crate) fn try_squash(&mut self, other: ItemPtr) -> bool {
775        if self.id.client == other.id.client
776            && self.id.clock + self.len() == other.id.clock
777            && other.origin == Some(self.last_id())
778            && self.right_origin == other.right_origin
779            && self.right == Some(other)
780            && self.is_deleted() == other.is_deleted()
781            && (self.redone.is_none() && other.redone.is_none())
782            && (!self.info.is_linked() && !other.info.is_linked()) // linked items cannot be merged
783            && self.moved == other.moved
784            && self.content.try_squash(&other.content)
785        {
786            self.len = self.content.len(OffsetKind::Utf16);
787            if let Some(mut right_right) = other.right {
788                right_right.left = Some(*self);
789            }
790            if other.info.is_keep() {
791                self.info.set_keep();
792            }
793            self.right = other.right;
794            true
795        } else {
796            false
797        }
798    }
799
800    pub(crate) fn as_branch(self) -> Option<BranchPtr> {
801        if let ItemContent::Type(branch) = &self.content {
802            Some(BranchPtr::from(branch))
803        } else {
804            None
805        }
806    }
807}
808
809impl Deref for ItemPtr {
810    type Target = Item;
811
812    fn deref(&self) -> &Self::Target {
813        unsafe { self.0.as_ref() }
814    }
815}
816
817impl DerefMut for ItemPtr {
818    fn deref_mut(&mut self) -> &mut Self::Target {
819        unsafe { self.0.as_mut() }
820    }
821}
822
823impl<'a> From<&'a mut Box<Item>> for ItemPtr {
824    fn from(block: &'a mut Box<Item>) -> Self {
825        ItemPtr(NonNull::from(block.as_mut()))
826    }
827}
828
829impl<'a> From<&'a Box<Item>> for ItemPtr {
830    fn from(block: &'a Box<Item>) -> Self {
831        ItemPtr(unsafe { NonNull::new_unchecked(block.as_ref() as *const Item as *mut Item) })
832    }
833}
834
835impl Eq for ItemPtr {}
836
837impl PartialEq for ItemPtr {
838    fn eq(&self, other: &Self) -> bool {
839        // BlockPtr.pivot may differ, but logically it doesn't affect block equality
840        self.id() == other.id()
841    }
842}
843
844impl TryFrom<ItemPtr> for Any {
845    type Error = ItemPtr;
846
847    fn try_from(item: ItemPtr) -> Result<Self, Self::Error> {
848        match &item.content {
849            ItemContent::Any(v) => Ok(v[0].clone()),
850            ItemContent::Embed(v) => Ok(v.clone()),
851            ItemContent::Binary(v) => Ok(v.clone().into()),
852            ItemContent::JSON(v) => Ok(v[0].clone().into()),
853            ItemContent::String(v) => Ok(v.to_string().into()),
854            _ => Err(item),
855        }
856    }
857}
858
859impl Item {
860    #[inline]
861    pub(crate) fn clock_range(&self) -> (u32, u32) {
862        let start = self.id.clock;
863        let end = start + self.len - 1;
864        (start, end)
865    }
866
867    pub fn encode<E: Encoder>(&self, encoder: &mut E) {
868        let info = self.info();
869        let cant_copy_parent_info = info & (HAS_ORIGIN | HAS_RIGHT_ORIGIN) == 0;
870        encoder.write_info(info);
871        if let Some(origin_id) = self.origin.as_ref() {
872            encoder.write_left_id(origin_id);
873        }
874        if let Some(right_origin_id) = self.right_origin.as_ref() {
875            encoder.write_right_id(right_origin_id);
876        }
877        if cant_copy_parent_info {
878            match &self.parent {
879                TypePtr::Branch(branch) => {
880                    if let Some(block) = branch.item {
881                        encoder.write_parent_info(false);
882                        encoder.write_left_id(block.id());
883                    } else if let Some(name) = branch.name.as_deref() {
884                        encoder.write_parent_info(true);
885                        encoder.write_string(name);
886                    } else {
887                        unreachable!("Could not get parent branch info for item")
888                    }
889                }
890                TypePtr::Named(name) => {
891                    encoder.write_parent_info(true);
892                    encoder.write_string(name);
893                }
894                TypePtr::ID(id) => {
895                    encoder.write_parent_info(false);
896                    encoder.write_left_id(id);
897                }
898                TypePtr::Unknown => {
899                    panic!("Couldn't get item's parent")
900                }
901            }
902            if let Some(parent_sub) = self.parent_sub.as_ref() {
903                encoder.write_string(parent_sub.as_ref());
904            }
905        }
906        self.content.encode(encoder);
907    }
908
909    /// Returns a unique identifier of a first update contained by a current [Item].
910    pub fn id(&self) -> &ID {
911        &self.id
912    }
913}
914
915/// A helper structure that's used to precisely describe a location of an [Item] to be inserted in
916/// relation to its neighbors and parent.
917#[derive(Debug)]
918pub(crate) struct ItemPosition {
919    pub parent: TypePtr,
920    pub left: Option<ItemPtr>,
921    pub right: Option<ItemPtr>,
922    pub index: u32,
923    pub current_attrs: Option<Box<Attrs>>,
924}
925
926impl ItemPosition {
927    pub fn forward(&mut self) -> bool {
928        if let Some(right) = self.right.as_deref() {
929            if !right.is_deleted() {
930                match &right.content {
931                    ItemContent::String(_) | ItemContent::Embed(_) => {
932                        self.index += right.len();
933                    }
934                    ItemContent::Format(key, value) => {
935                        let attrs = self.current_attrs.get_or_init();
936                        update_current_attributes(attrs, key, value.as_ref());
937                    }
938                    _ => {}
939                }
940            }
941
942            let new = right.right.clone();
943            self.left = self.right.take();
944            self.right = new;
945
946            return true;
947        }
948        false
949    }
950
951    /// If current `attributes` don't confirm the same keys as the formatting wrapping
952    /// current insert position, they should be unset.
953    pub fn unset_missing(&self, attributes: &mut Attrs) {
954        if let Some(attrs) = self.current_attrs.as_ref() {
955            // if current `attributes` don't confirm the same keys as the formatting wrapping
956            // current insert position, they should be unset
957            for (k, _) in attrs.iter() {
958                if !attributes.contains_key(k) {
959                    attributes.insert(k.clone(), Any::Null);
960                }
961            }
962        }
963    }
964}
965
966/// Bit flag (9st bit) for item that is linked by Weak Link references
967const ITEM_FLAG_LINKED: u16 = 0b0001_0000_0000;
968
969/// Bit flag (4th bit) for a marked item - not used atm.
970const ITEM_FLAG_MARKED: u16 = 0b0000_1000;
971
972/// Bit flag (3rd bit) for a tombstoned (deleted) item.
973const ITEM_FLAG_DELETED: u16 = 0b0000_0100;
974
975/// Bit flag (2nd bit) for an item, which contents are considered countable.
976const ITEM_FLAG_COUNTABLE: u16 = 0b0000_0010;
977
978/// Bit flag (1st bit) used for an item which should be kept - not used atm.
979const ITEM_FLAG_KEEP: u16 = 0b0000_0001;
980
981/// Collection of flags attached to an [Item] - most of them are serializable and define specific
982/// properties of an associated [Item], like:
983///
984/// - Has item been deleted?
985/// - Is item countable (should its content add to the length/offset calculation of containing collection)?
986/// - Should item be kept untouched eg. because it's being tracked by [UndoManager].
987#[repr(transparent)]
988#[derive(Debug, Copy, Clone, PartialEq, Eq)]
989pub struct ItemFlags(u16);
990
991impl ItemFlags {
992    pub fn new(source: u16) -> Self {
993        ItemFlags(source)
994    }
995
996    #[inline]
997    fn set(&mut self, value: u16) {
998        self.0 |= value
999    }
1000
1001    #[inline]
1002    fn clear(&mut self, value: u16) {
1003        self.0 &= !value
1004    }
1005
1006    #[inline]
1007    fn check(&self, value: u16) -> bool {
1008        self.0 & value == value
1009    }
1010
1011    #[inline]
1012    pub fn is_keep(&self) -> bool {
1013        self.check(ITEM_FLAG_KEEP)
1014    }
1015
1016    #[inline]
1017    pub fn set_keep(&mut self) {
1018        self.set(ITEM_FLAG_KEEP)
1019    }
1020
1021    #[inline]
1022    pub fn clear_keep(&mut self) {
1023        self.clear(ITEM_FLAG_KEEP)
1024    }
1025
1026    #[inline]
1027    pub fn set_countable(&mut self) {
1028        self.set(ITEM_FLAG_COUNTABLE)
1029    }
1030
1031    #[inline]
1032    pub fn clear_countable(&mut self) {
1033        self.clear(ITEM_FLAG_COUNTABLE)
1034    }
1035
1036    #[inline]
1037    pub fn is_countable(&self) -> bool {
1038        self.check(ITEM_FLAG_COUNTABLE)
1039    }
1040
1041    #[inline]
1042    pub fn set_deleted(&mut self) {
1043        self.set(ITEM_FLAG_DELETED)
1044    }
1045
1046    #[inline]
1047    pub fn is_deleted(&self) -> bool {
1048        self.check(ITEM_FLAG_DELETED)
1049    }
1050
1051    #[inline]
1052    pub fn is_marked(&self) -> bool {
1053        self.check(ITEM_FLAG_MARKED)
1054    }
1055
1056    #[inline]
1057    pub fn is_linked(&self) -> bool {
1058        self.check(ITEM_FLAG_LINKED)
1059    }
1060
1061    #[inline]
1062    pub fn set_linked(&mut self) {
1063        self.set(ITEM_FLAG_LINKED)
1064    }
1065
1066    #[inline]
1067    pub fn clear_linked(&mut self) {
1068        self.clear(ITEM_FLAG_LINKED)
1069    }
1070}
1071
1072impl Into<u16> for ItemFlags {
1073    #[inline]
1074    fn into(self) -> u16 {
1075        self.0
1076    }
1077}
1078
1079/// Block defines a range of consecutive updates performed by the same peer. While individual
1080/// updates are always uniquely defined by their corresponding [ID]s, they may contain a lot of
1081/// additional metadata. Block representation here is crucial, since it optimizes memory usage,
1082/// available when multiple updates have been performed one after another (eg. *when user is writing
1083/// a sentence, individual key strokes are independent updates but they can be compresses into a
1084/// single block containing an entire sentence for as long as another piece of data is not being
1085/// inserted in the middle it*).
1086#[derive(PartialEq)]
1087pub struct Item {
1088    /// Unique identifier of the first update described by the current [Item].
1089    pub(crate) id: ID,
1090
1091    /// A number of splittable updates within a current [Item].
1092    pub(crate) len: u32,
1093
1094    /// Pointer to left neighbor of this item. Used in sequenced collections.
1095    /// If `None`, then current item is the first one on its [parent](Item::parent) collection.
1096    pub(crate) left: Option<ItemPtr>,
1097
1098    /// Pointer to right neighbor of this item. Used in sequenced collections.
1099    /// If `None`, then current item is the last one on its [parent](Item::parent) collection.
1100    ///
1101    /// For map-like CRDTs if this field is `None`, it means that a current item also contains
1102    /// the most recent update for an individual key-value entry.
1103    pub(crate) right: Option<ItemPtr>,
1104
1105    /// Used for concurrent insert conflict resolution. An ID of a left-side neighbor at the moment
1106    /// of insertion of current block.
1107    pub(crate) origin: Option<ID>,
1108
1109    /// Used for concurrent insert conflict resolution. An ID of a right-side neighbor at the moment
1110    /// of insertion of current block.
1111    pub(crate) right_origin: Option<ID>,
1112
1113    /// A user data stored inside of a current item.
1114    pub(crate) content: ItemContent,
1115
1116    /// Pointer to a parent collection containing current item.
1117    pub(crate) parent: TypePtr,
1118
1119    /// Used by [UndoManager] to track another block that reverts the effects of deletion of current
1120    /// item.
1121    pub(crate) redone: Option<ID>,
1122
1123    /// Used only when current item is used by map-like types. In such case this item works as a
1124    /// key-value entry of a map, and this field contains a key used by map.
1125    pub(crate) parent_sub: Option<Arc<str>>,
1126
1127    /// This property is reused by the moved prop. In this case this property refers to an Item.
1128    pub(crate) moved: Option<ItemPtr>,
1129
1130    /// Bit flag field which contains information about specifics of this item.
1131    pub(crate) info: ItemFlags,
1132}
1133
1134/// Describes a consecutive range of updates (identified by their [ID]s).
1135#[derive(PartialEq, Eq, Clone)]
1136pub struct BlockRange {
1137    /// [ID] of the first update stored within current [BlockRange] bounds.
1138    pub id: ID,
1139    /// Number of splittable updates stored within this [BlockRange].
1140    pub len: u32,
1141}
1142
1143impl BlockRange {
1144    pub fn new(id: ID, len: u32) -> Self {
1145        BlockRange { id, len }
1146    }
1147
1148    /// Returns an [ID] of the last update fitting into the bounds of current [BlockRange]
1149    pub fn last_id(&self) -> ID {
1150        ID::new(self.id.client, self.id.clock + self.len)
1151    }
1152
1153    /// Returns a slice of a current [BlockRange], which starts at a given offset (relative to
1154    /// current range).
1155    ///
1156    /// # Example:
1157    ///
1158    /// ```rust
1159    /// use yrs::block::BlockRange;
1160    /// use yrs::ID;
1161    /// let a = BlockRange::new(ID::new(1, 2), 8); // range of clocks [2..10)
1162    /// let b = a.slice(3); // range of clocks [5..10)
1163    ///
1164    /// assert_eq!(b.id, ID::new(1, 5));
1165    /// assert_eq!(b.last_id(), ID::new(1, 10));
1166    /// ```
1167    pub fn slice(&self, offset: u32) -> Self {
1168        let mut next = self.clone();
1169        next.id.clock += offset;
1170        next.len -= offset;
1171        next
1172    }
1173
1174    pub(crate) fn integrate(&mut self, pivot: u32) -> bool {
1175        if pivot > 0 {
1176            self.id.clock += pivot;
1177            self.len -= pivot;
1178        }
1179
1180        false
1181    }
1182
1183    #[inline]
1184    pub(crate) fn merge(&mut self, other: &Self) {
1185        self.len += other.len;
1186    }
1187
1188    /// Checks if provided `id` fits inside of boundaries defined by current [BlockRange].
1189    pub fn contains(&self, id: &ID) -> bool {
1190        self.id.client == id.client
1191            && id.clock >= self.id.clock
1192            && id.clock < self.id.clock + self.len
1193    }
1194}
1195
1196impl std::fmt::Debug for BlockRange {
1197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1198        std::fmt::Display::fmt(self, f)
1199    }
1200}
1201
1202impl std::fmt::Display for BlockRange {
1203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1204        write!(f, "({}-{})", self.id, self.len)
1205    }
1206}
1207
1208impl Item {
1209    pub(crate) fn new(
1210        id: ID,
1211        left: Option<ItemPtr>,
1212        origin: Option<ID>,
1213        right: Option<ItemPtr>,
1214        right_origin: Option<ID>,
1215        parent: TypePtr,
1216        parent_sub: Option<Arc<str>>,
1217        content: ItemContent,
1218    ) -> Option<Box<Item>> {
1219        let info = ItemFlags::new(if content.is_countable() {
1220            ITEM_FLAG_COUNTABLE
1221        } else {
1222            0
1223        });
1224        let len = content.len(OffsetKind::Utf16);
1225        if len == 0 {
1226            return None;
1227        }
1228        let root_name = if let TypePtr::Named(root) = &parent {
1229            Some(root.clone())
1230        } else {
1231            None
1232        };
1233        let mut item = Box::new(Item {
1234            id,
1235            len,
1236            left,
1237            right,
1238            origin,
1239            right_origin,
1240            content,
1241            parent,
1242            parent_sub,
1243            info,
1244            moved: None,
1245            redone: None,
1246        });
1247        let item_ptr = ItemPtr::from(&mut item);
1248        if let ItemContent::Type(branch) = &mut item.content {
1249            branch.item = Some(item_ptr);
1250            if branch.name.is_none() {
1251                branch.name = root_name;
1252            }
1253        }
1254        Some(item)
1255    }
1256
1257    /// Checks if provided `id` fits inside of updates defined within bounds of current [Item].
1258    pub fn contains(&self, id: &ID) -> bool {
1259        self.id.client == id.client
1260            && id.clock >= self.id.clock
1261            && id.clock < self.id.clock + self.len()
1262    }
1263
1264    /// Checks if current item is marked as deleted (tombstoned).
1265    /// Yrs uses soft item deletion mechanism, which means that deleted values are not physically
1266    /// erased from memory, but just marked as deleted.
1267    pub fn is_deleted(&self) -> bool {
1268        self.info.is_deleted()
1269    }
1270
1271    /// Checks if item content can be considered countable. Countable elements can be split
1272    /// and joined together.
1273    pub fn is_countable(&self) -> bool {
1274        self.info.is_countable()
1275    }
1276
1277    pub(crate) fn mark_as_deleted(&mut self) {
1278        self.info.set_deleted()
1279    }
1280
1281    /// Assign left/right neighbors of the block. This may require for origin/right_origin
1282    /// blocks to be already present in block store - which may not be the case during block
1283    /// decoding. We decode entire update first, and apply individual blocks second, hence
1284    /// repair function is called before applying the block rather than on decode.
1285    pub(crate) fn repair(&mut self, store: &mut Store) -> Result<(), UpdateError> {
1286        if let Some(origin) = self.origin.as_ref() {
1287            self.left = store
1288                .blocks
1289                .get_item_clean_end(origin)
1290                .map(|slice| store.materialize(slice));
1291        }
1292
1293        if let Some(origin) = self.right_origin.as_ref() {
1294            self.right = store
1295                .blocks
1296                .get_item_clean_start(origin)
1297                .map(|slice| store.materialize(slice));
1298        }
1299
1300        // We have all missing ids, now find the items
1301
1302        // In the original Y.js algorithm we decoded items as we go and attached them to client
1303        // block list. During that process if we had right origin but no left, we made a lookup for
1304        // right origin's parent and attach it as a parent of current block.
1305        //
1306        // Here since we decode all blocks first, then apply them, we might not find them in
1307        // the block store during decoding. Therefore we retroactively reattach it here.
1308
1309        self.parent = match &self.parent {
1310            TypePtr::Branch(branch_ptr) => TypePtr::Branch(*branch_ptr),
1311            TypePtr::Unknown => match (self.left, self.right) {
1312                (Some(item), _) if item.parent != TypePtr::Unknown => {
1313                    self.parent_sub = item.parent_sub.clone();
1314                    item.parent.clone()
1315                }
1316                (_, Some(item)) if item.parent != TypePtr::Unknown => {
1317                    self.parent_sub = item.parent_sub.clone();
1318                    item.parent.clone()
1319                }
1320                _ => TypePtr::Unknown,
1321            },
1322            TypePtr::Named(name) => {
1323                let branch = store.get_or_create_type(name.clone(), TypeRef::Undefined);
1324                TypePtr::Branch(branch)
1325            }
1326            TypePtr::ID(id) => {
1327                let ptr = store.blocks.get_item(id);
1328                if let Some(item) = ptr {
1329                    match &item.content {
1330                        ItemContent::Type(branch) => {
1331                            TypePtr::Branch(BranchPtr::from(branch.as_ref()))
1332                        }
1333                        ItemContent::Deleted(_) => TypePtr::Unknown,
1334                        other => {
1335                            return Err(UpdateError::InvalidParent(
1336                                id.clone(),
1337                                other.get_ref_number(),
1338                            ))
1339                        }
1340                    }
1341                } else {
1342                    TypePtr::Unknown
1343                }
1344            }
1345        };
1346
1347        Ok(())
1348    }
1349
1350    /// Returns a length of a block. For most situation it works like [Item::content_len] with a
1351    /// difference to a [Text]/[XmlText] contents - in order to achieve compatibility with
1352    /// Yjs we need to calculate string length in terms of UTF-16 character encoding.
1353    /// However depending on used [Encoding] scheme we may calculate string length/offsets
1354    /// differently.
1355    pub fn len(&self) -> u32 {
1356        self.len
1357    }
1358
1359    pub fn content_len(&self, kind: OffsetKind) -> u32 {
1360        self.content.len(kind)
1361    }
1362
1363    /// Returns an ID of the last element that can be considered a part of this item.
1364    pub fn last_id(&self) -> ID {
1365        ID::new(self.id.client, self.id.clock + self.len() - 1)
1366    }
1367
1368    pub fn info(&self) -> u8 {
1369        let info = if self.origin.is_some() { HAS_ORIGIN } else { 0 } // is left null
1370            | if self.right_origin.is_some() { HAS_RIGHT_ORIGIN } else { 0 } // is right null
1371            | if self.parent_sub.is_some() { HAS_PARENT_SUB } else { 0 }
1372            | (self.content.get_ref_number() & 0b1111);
1373        info
1374    }
1375
1376    pub(crate) fn gc(&mut self, collector: &mut GCCollector, parent_gc: bool) {
1377        if self.is_deleted() && !self.info.is_keep() {
1378            self.content.gc(collector);
1379            let len = self.len();
1380            if parent_gc {
1381                collector.mark(&self.id);
1382            } else {
1383                self.content = ItemContent::Deleted(len);
1384                self.info.clear_countable();
1385            }
1386        }
1387    }
1388}
1389
1390#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone)]
1391pub struct SplittableString {
1392    content: SmallString<[u8; 8]>,
1393}
1394
1395impl SplittableString {
1396    pub fn len(&self, kind: OffsetKind) -> usize {
1397        let len = self.content.len();
1398        if len == 1 {
1399            len // quite often strings are single-letter, so we don't care about OffsetKind
1400        } else {
1401            match kind {
1402                OffsetKind::Bytes => len,
1403                OffsetKind::Utf16 => self.utf16_len(),
1404            }
1405        }
1406    }
1407
1408    #[inline(always)]
1409    pub fn as_str(&self) -> &str {
1410        self.content.as_str()
1411    }
1412
1413    #[inline(always)]
1414    pub fn utf16_len(&self) -> usize {
1415        self.encode_utf16().count()
1416    }
1417
1418    /// Maps given offset onto block offset. This means, that given an `offset` provided
1419    /// in given `encoding` we want the output as a UTF-16 compatible offset (required
1420    /// by Yjs for compatibility reasons).
1421    pub(crate) fn block_offset(&self, offset: u32, kind: OffsetKind) -> u32 {
1422        match kind {
1423            OffsetKind::Utf16 => offset,
1424            OffsetKind::Bytes => {
1425                let mut remaining = offset;
1426                let mut i = 0;
1427                // since this offset is used to splitting later on - and we can only split entire
1428                // characters - we're computing by characters
1429                for c in self.content.chars() {
1430                    if remaining == 0 {
1431                        break;
1432                    }
1433                    remaining -= c.len_utf8() as u32;
1434                    i += c.len_utf16() as u32;
1435                }
1436                i
1437            }
1438        }
1439    }
1440
1441    pub fn push_str(&mut self, str: &str) {
1442        self.content.push_str(str);
1443    }
1444}
1445
1446impl std::fmt::Display for SplittableString {
1447    #[inline(always)]
1448    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1449        self.content.fmt(f)
1450    }
1451}
1452
1453impl Into<SmallString<[u8; 8]>> for SplittableString {
1454    #[inline(always)]
1455    fn into(self) -> SmallString<[u8; 8]> {
1456        self.content
1457    }
1458}
1459
1460impl Into<Box<str>> for SplittableString {
1461    #[inline(always)]
1462    fn into(self) -> Box<str> {
1463        self.content.into_string().into_boxed_str()
1464    }
1465}
1466
1467impl From<SmallString<[u8; 8]>> for SplittableString {
1468    fn from(content: SmallString<[u8; 8]>) -> Self {
1469        SplittableString { content }
1470    }
1471}
1472
1473impl<'a> From<&'a str> for SplittableString {
1474    fn from(str: &'a str) -> Self {
1475        Self::from(SmallString::from_str(str))
1476    }
1477}
1478
1479impl Deref for SplittableString {
1480    type Target = str;
1481
1482    #[inline(always)]
1483    fn deref(&self) -> &Self::Target {
1484        &self.content
1485    }
1486}
1487
1488pub(crate) fn split_str(str: &str, offset: usize, kind: OffsetKind) -> (&str, &str) {
1489    fn map_utf16_offset(str: &str, offset: u32) -> u32 {
1490        let mut off = 0;
1491        let mut i = 0;
1492        for c in str.chars() {
1493            if i >= offset {
1494                break;
1495            }
1496            off += c.len_utf8() as u32;
1497            i += c.len_utf16() as u32;
1498        }
1499        off
1500    }
1501
1502    let off = match kind {
1503        OffsetKind::Bytes => offset,
1504        OffsetKind::Utf16 => map_utf16_offset(str, offset as u32) as usize,
1505    };
1506    str.split_at(off)
1507}
1508
1509/// An enum describing the type of a user data content stored as part of one or more
1510/// (if items were squashed) insert operations.
1511#[derive(Debug, PartialEq)]
1512pub enum ItemContent {
1513    /// Collection of consecutively inserted JSON-like primitive values.
1514    Any(Vec<Any>),
1515
1516    /// A BLOB data eg. images. Binaries are treated as a single objects (they are not subjects to splits).
1517    Binary(Vec<u8>),
1518
1519    /// A marker for delete item data, which describes a number of deleted elements.
1520    /// Deleted elements also don't contribute to an overall length of containing collection type.
1521    Deleted(u32),
1522
1523    /// Sub-document container. Contains weak reference to a parent document and a child document.
1524    Doc(Option<Doc>, Doc),
1525
1526    /// Obsolete: collection of consecutively inserted stringified JSON values.
1527    JSON(Vec<String>),
1528
1529    /// A single embedded JSON-like primitive value.
1530    Embed(Any),
1531
1532    /// Formatting attribute entry. Format attributes are not considered countable and don't
1533    /// contribute to an overall length of a collection they are applied to.
1534    Format(Arc<str>, Box<Any>),
1535
1536    /// A chunk of text, usually applied by collaborative text insertion.
1537    String(SplittableString),
1538
1539    /// A reference of a branch node. Branch nodes define a complex collection types, such as
1540    /// arrays, maps or XML elements.
1541    Type(Box<Branch>),
1542
1543    /// Marker for destination location of move operation. Move is used to change position of
1544    /// previously inserted element in a sequence with respect to other operations that may happen
1545    /// concurrently on other peers.
1546    Move(Box<Move>),
1547}
1548
1549impl ItemContent {
1550    /// Returns a reference number used to determine a content type.
1551    /// It's used during encoding/decoding of a containing block.
1552    pub fn get_ref_number(&self) -> u8 {
1553        match self {
1554            ItemContent::Any(_) => BLOCK_ITEM_ANY_REF_NUMBER,
1555            ItemContent::Binary(_) => BLOCK_ITEM_BINARY_REF_NUMBER,
1556            ItemContent::Deleted(_) => BLOCK_ITEM_DELETED_REF_NUMBER,
1557            ItemContent::Doc(_, _) => BLOCK_ITEM_DOC_REF_NUMBER,
1558            ItemContent::JSON(_) => BLOCK_ITEM_JSON_REF_NUMBER,
1559            ItemContent::Embed(_) => BLOCK_ITEM_EMBED_REF_NUMBER,
1560            ItemContent::Format(_, _) => BLOCK_ITEM_FORMAT_REF_NUMBER,
1561            ItemContent::String(_) => BLOCK_ITEM_STRING_REF_NUMBER,
1562            ItemContent::Type(_) => BLOCK_ITEM_TYPE_REF_NUMBER,
1563            ItemContent::Move(_) => BLOCK_ITEM_MOVE_REF_NUMBER,
1564        }
1565    }
1566
1567    /// Checks if item content can be considered countable. Countable elements contribute to
1568    /// a length of the block they are contained by. Most of the item content variants are countable
1569    /// with exception for [ItemContent::Deleted] (which length describes number of removed
1570    /// elements) and [ItemContent::Format] (which is used for storing text formatting tags).
1571    pub fn is_countable(&self) -> bool {
1572        match self {
1573            ItemContent::Any(_) => true,
1574            ItemContent::Binary(_) => true,
1575            ItemContent::Doc(_, _) => true,
1576            ItemContent::JSON(_) => true,
1577            ItemContent::Embed(_) => true,
1578            ItemContent::String(_) => true,
1579            ItemContent::Type(_) => true,
1580            ItemContent::Deleted(_) => false,
1581            ItemContent::Format(_, _) => false,
1582            ItemContent::Move(_) => false,
1583        }
1584    }
1585
1586    /// Returns a number of separate elements contained within current item content struct.
1587    ///
1588    /// Separate elements can be split in order to put another block in between them. Definition of
1589    /// separation depends on a item content kin, eg. [ItemContent::String], [ItemContent::Any],
1590    /// [ItemContent::JSON] and [ItemContent::Deleted] can have variable length as they may be split
1591    /// by other insert operations. Other variants (eg. [ItemContent::Binary]) are considered as
1592    /// a single element and therefore their length is always 1 and are not considered as subject of
1593    /// splitting.
1594    ///
1595    /// In cases of counting number of visible elements, `len` method should be used together with
1596    /// [ItemContent::is_countable].
1597    pub fn len(&self, kind: OffsetKind) -> u32 {
1598        match self {
1599            ItemContent::Deleted(deleted) => *deleted,
1600            ItemContent::String(str) => str.len(kind) as u32,
1601            ItemContent::Any(v) => v.len() as u32,
1602            ItemContent::JSON(v) => v.len() as u32,
1603            _ => 1,
1604        }
1605    }
1606
1607    /// Reads a contents of current [ItemContent] into a given `buf`, starting from provided
1608    /// `offset`. Returns a number of elements read this way (it cannot be longer than `buf`'s len.
1609    pub fn read(&self, offset: usize, buf: &mut [Out]) -> usize {
1610        if buf.is_empty() {
1611            0
1612        } else {
1613            match self {
1614                ItemContent::Any(values) => {
1615                    let mut i = offset;
1616                    let mut j = 0;
1617                    while i < values.len() && j < buf.len() {
1618                        let any = &values[i];
1619                        buf[j] = Out::Any(any.clone());
1620                        i += 1;
1621                        j += 1;
1622                    }
1623                    j
1624                }
1625                ItemContent::String(v) => {
1626                    let chars = v.chars().skip(offset).take(buf.len());
1627                    let mut j = 0;
1628                    for c in chars {
1629                        buf[j] = Out::Any(Any::from(c.to_string()));
1630                        j += 1;
1631                    }
1632                    j
1633                }
1634                ItemContent::JSON(elements) => {
1635                    let mut i = offset;
1636                    let mut j = 0;
1637                    while i < elements.len() && j < buf.len() {
1638                        let elem = elements[i].as_str();
1639                        buf[j] = Out::Any(Any::from(elem));
1640                        i += 1;
1641                        j += 1;
1642                    }
1643                    j
1644                }
1645                ItemContent::Binary(v) => {
1646                    buf[0] = Out::Any(Any::from(v.deref()));
1647                    1
1648                }
1649                ItemContent::Doc(_, doc) => {
1650                    buf[0] = Out::YDoc(doc.clone());
1651                    1
1652                }
1653                ItemContent::Type(c) => {
1654                    let branch_ref = BranchPtr::from(c);
1655                    buf[0] = branch_ref.into();
1656                    1
1657                }
1658                ItemContent::Embed(v) => {
1659                    buf[0] = Out::Any(v.clone());
1660                    1
1661                }
1662                ItemContent::Move(_) => 0,
1663                ItemContent::Deleted(_) => 0,
1664                ItemContent::Format(_, _) => 0,
1665            }
1666        }
1667    }
1668
1669    /// Reads all contents stored in this item and returns them. Use [ItemContent::read] if you need
1670    /// to read only slice of elements from the corresponding item.
1671    pub fn get_content(&self) -> Vec<Out> {
1672        let len = self.len(OffsetKind::Utf16) as usize;
1673        let mut values = vec![Out::default(); len];
1674        let read = self.read(0, &mut values);
1675        if read == len {
1676            values
1677        } else {
1678            Vec::default()
1679        }
1680    }
1681
1682    /// Returns a first value stored in a corresponding item.
1683    pub fn get_first(&self) -> Option<Out> {
1684        match self {
1685            ItemContent::Any(v) => v.first().map(|a| Out::Any(a.clone())),
1686            ItemContent::Binary(v) => Some(Out::Any(Any::from(v.deref()))),
1687            ItemContent::Deleted(_) => None,
1688            ItemContent::Move(_) => None,
1689            ItemContent::Doc(_, v) => Some(Out::YDoc(v.clone())),
1690            ItemContent::JSON(v) => v.first().map(|v| Out::Any(Any::from(v.deref()))),
1691            ItemContent::Embed(v) => Some(Out::Any(v.clone())),
1692            ItemContent::Format(_, _) => None,
1693            ItemContent::String(v) => Some(Out::Any(Any::from(v.clone().as_str()))),
1694            ItemContent::Type(c) => Some(BranchPtr::from(c).into()),
1695        }
1696    }
1697
1698    /// Returns a last value stored in a corresponding item.
1699    pub fn get_last(&self) -> Option<Out> {
1700        match self {
1701            ItemContent::Any(v) => v.last().map(|a| Out::Any(a.clone())),
1702            ItemContent::Binary(v) => Some(Out::Any(Any::from(v.deref()))),
1703            ItemContent::Deleted(_) => None,
1704            ItemContent::Move(_) => None,
1705            ItemContent::Doc(_, v) => Some(Out::YDoc(v.clone())),
1706            ItemContent::JSON(v) => v.last().map(|v| Out::Any(Any::from(v.as_str()))),
1707            ItemContent::Embed(v) => Some(Out::Any(v.clone())),
1708            ItemContent::Format(_, _) => None,
1709            ItemContent::String(v) => Some(Out::Any(Any::from(v.as_str()))),
1710            ItemContent::Type(c) => Some(BranchPtr::from(c).into()),
1711        }
1712    }
1713
1714    /// Encodes a slice of a current [ItemContent] within an index bounds of (start..=end) - both
1715    /// sides inclusive.
1716    pub fn encode_slice<E: Encoder>(&self, encoder: &mut E, start: u32, end: u32) {
1717        match self {
1718            ItemContent::Deleted(_) => encoder.write_len(end - start + 1),
1719            ItemContent::Binary(buf) => encoder.write_buf(buf),
1720            ItemContent::String(s) => {
1721                let slice = if start != 0 {
1722                    let (_, right) = split_str(&s, start as usize, OffsetKind::Utf16);
1723                    right
1724                } else {
1725                    &s
1726                };
1727                let slice = if end != 0 {
1728                    let (left, _) =
1729                        split_str(&slice, (end - start + 1) as usize, OffsetKind::Utf16);
1730                    left
1731                } else {
1732                    slice
1733                };
1734                encoder.write_string(slice)
1735            }
1736            ItemContent::Embed(s) => encoder.write_json(s),
1737            ItemContent::JSON(s) => {
1738                encoder.write_len(end - start + 1);
1739                for i in start..=end {
1740                    encoder.write_string(s[i as usize].as_str())
1741                }
1742            }
1743            ItemContent::Format(k, v) => {
1744                encoder.write_key(k.as_ref());
1745                encoder.write_json(v.as_ref());
1746            }
1747            ItemContent::Type(inner) => {
1748                inner.type_ref.encode(encoder);
1749            }
1750            ItemContent::Any(any) => {
1751                encoder.write_len(end - start + 1);
1752                for i in start..=end {
1753                    encoder.write_any(&any[i as usize]);
1754                }
1755            }
1756            ItemContent::Doc(_, doc) => doc.store().options().encode(encoder),
1757            ItemContent::Move(m) => m.encode(encoder),
1758        }
1759    }
1760
1761    pub fn encode<E: Encoder>(&self, encoder: &mut E) {
1762        match self {
1763            ItemContent::Deleted(len) => encoder.write_len(*len),
1764            ItemContent::Binary(buf) => encoder.write_buf(buf),
1765            ItemContent::String(s) => encoder.write_string(s.as_str()),
1766            ItemContent::Embed(s) => encoder.write_json(s),
1767            ItemContent::JSON(s) => {
1768                encoder.write_len(s.len() as u32);
1769                for json in s.iter() {
1770                    encoder.write_string(json.as_str())
1771                }
1772            }
1773            ItemContent::Format(k, v) => {
1774                encoder.write_key(k.as_ref());
1775                encoder.write_json(v.as_ref());
1776            }
1777            ItemContent::Type(inner) => {
1778                inner.type_ref.encode(encoder);
1779            }
1780            ItemContent::Any(any) => {
1781                encoder.write_len(any.len() as u32);
1782                for a in any.iter() {
1783                    encoder.write_any(a);
1784                }
1785            }
1786            ItemContent::Doc(_, doc) => doc.store().options().encode(encoder),
1787            ItemContent::Move(m) => m.encode(encoder),
1788        }
1789    }
1790
1791    pub fn decode<D: Decoder>(decoder: &mut D, ref_num: u8) -> Result<Self, Error> {
1792        match ref_num & 0b1111 {
1793            BLOCK_ITEM_DELETED_REF_NUMBER => Ok(ItemContent::Deleted(decoder.read_len()?)),
1794            BLOCK_ITEM_JSON_REF_NUMBER => {
1795                let mut remaining = decoder.read_len()? as i32;
1796                let mut buf = Vec::new();
1797                buf.try_reserve(remaining as usize)?;
1798
1799                while remaining >= 0 {
1800                    buf.push(decoder.read_string()?.to_owned());
1801                    remaining -= 1;
1802                }
1803                Ok(ItemContent::JSON(buf))
1804            }
1805            BLOCK_ITEM_BINARY_REF_NUMBER => Ok(ItemContent::Binary(decoder.read_buf()?.to_owned())),
1806            BLOCK_ITEM_STRING_REF_NUMBER => Ok(ItemContent::String(decoder.read_string()?.into())),
1807            BLOCK_ITEM_EMBED_REF_NUMBER => Ok(ItemContent::Embed(decoder.read_json()?.into())),
1808            BLOCK_ITEM_FORMAT_REF_NUMBER => Ok(ItemContent::Format(
1809                decoder.read_key()?,
1810                decoder.read_json()?.into(),
1811            )),
1812            BLOCK_ITEM_TYPE_REF_NUMBER => {
1813                let type_ref = TypeRef::decode(decoder)?;
1814                let inner = Branch::new(type_ref);
1815                Ok(ItemContent::Type(inner))
1816            }
1817            BLOCK_ITEM_ANY_REF_NUMBER => {
1818                let len = decoder.read_len()? as usize;
1819                let mut values = Vec::new();
1820                values.try_reserve(len)?;
1821
1822                let mut i = 0;
1823                while i < len {
1824                    values.push(decoder.read_any()?);
1825                    i += 1;
1826                }
1827                Ok(ItemContent::Any(values))
1828            }
1829            BLOCK_ITEM_MOVE_REF_NUMBER => {
1830                let m = Move::decode(decoder)?;
1831                Ok(ItemContent::Move(Box::new(m)))
1832            }
1833            BLOCK_ITEM_DOC_REF_NUMBER => {
1834                let mut options = Options::decode(decoder)?;
1835                options.should_load = options.should_load || options.auto_load;
1836                Ok(ItemContent::Doc(None, Doc::with_options(options)))
1837            }
1838            _ => Err(Error::UnexpectedValue),
1839        }
1840    }
1841
1842    pub(crate) fn splice(&mut self, offset: usize, encoding: OffsetKind) -> Option<ItemContent> {
1843        match self {
1844            ItemContent::Any(value) => {
1845                let (left, right) = value.split_at(offset);
1846                let left = left.to_vec();
1847                let right = right.to_vec();
1848                *self = ItemContent::Any(left);
1849                Some(ItemContent::Any(right))
1850            }
1851            ItemContent::String(string) => {
1852                // compute offset given in unicode code points into byte position
1853                let (left, right) = split_str(&string, offset, encoding);
1854                let left: SplittableString = left.into();
1855                let right: SplittableString = right.into();
1856
1857                //TODO: do we need that in Rust?
1858                //let split_point = left.chars().last().unwrap();
1859                //if split_point >= 0xD800 as char && split_point <= 0xDBFF as char {
1860                //    // Last character of the left split is the start of a surrogate utf16/ucs2 pair.
1861                //    // We don't support splitting of surrogate pairs because this may lead to invalid documents.
1862                //    // Replace the invalid character with a unicode replacement character (� / U+FFFD)
1863                //    left.replace_range((offset-1)..offset, "�");
1864                //    right.replace_range(0..1, "�");
1865                //}
1866                *self = ItemContent::String(left);
1867
1868                Some(ItemContent::String(right))
1869            }
1870            ItemContent::Deleted(len) => {
1871                let right = ItemContent::Deleted(*len - offset as u32);
1872                *len = offset as u32;
1873                Some(right)
1874            }
1875            ItemContent::JSON(value) => {
1876                let (left, right) = value.split_at(offset);
1877                let left = left.to_vec();
1878                let right = right.to_vec();
1879                *self = ItemContent::JSON(left);
1880                Some(ItemContent::JSON(right))
1881            }
1882            _ => None,
1883        }
1884    }
1885
1886    /// Tries to squash two item content structures together.
1887    /// Returns `true` if this method had any effect on current [ItemContent] (modified it).
1888    /// Otherwise returns `false`.
1889    pub fn try_squash(&mut self, other: &Self) -> bool {
1890        //TODO: change `other` to Self (not ref) and return type to Option<Self> (none if merge suceeded)
1891        match (self, other) {
1892            (ItemContent::Any(v1), ItemContent::Any(v2)) => {
1893                v1.append(&mut v2.clone());
1894                true
1895            }
1896            (ItemContent::Deleted(v1), ItemContent::Deleted(v2)) => {
1897                *v1 = *v1 + *v2;
1898                true
1899            }
1900            (ItemContent::JSON(v1), ItemContent::JSON(v2)) => {
1901                v1.append(&mut v2.clone());
1902                true
1903            }
1904            (ItemContent::String(v1), ItemContent::String(v2)) => {
1905                v1.push_str(v2.as_str());
1906                true
1907            }
1908            _ => false,
1909        }
1910    }
1911
1912    pub(crate) fn gc(&mut self, collector: &mut GCCollector) {
1913        match self {
1914            ItemContent::Type(branch) => {
1915                let mut curr = branch.start.take();
1916                while let Some(mut item) = curr {
1917                    curr = item.right.clone();
1918                    item.gc(collector, true);
1919                }
1920
1921                for (_, ptr) in branch.map.drain() {
1922                    curr = Some(ptr);
1923                    while let Some(mut item) = curr {
1924                        curr = item.left.clone();
1925                        item.gc(collector, true);
1926                        continue;
1927                    }
1928                }
1929            }
1930            _ => {}
1931        }
1932    }
1933}
1934
1935impl Clone for ItemContent {
1936    fn clone(&self) -> Self {
1937        match self {
1938            ItemContent::Any(array) => ItemContent::Any(array.clone()),
1939            ItemContent::Binary(bytes) => ItemContent::Binary(bytes.clone()),
1940            ItemContent::Deleted(len) => ItemContent::Deleted(*len),
1941            ItemContent::Doc(store, doc) => ItemContent::Doc(store.clone(), doc.clone()),
1942            ItemContent::JSON(array) => ItemContent::JSON(array.clone()),
1943            ItemContent::Embed(json) => ItemContent::Embed(json.clone()),
1944            ItemContent::Format(key, value) => ItemContent::Format(key.clone(), value.clone()),
1945            ItemContent::String(chunk) => ItemContent::String(chunk.clone()),
1946            ItemContent::Type(branch) => ItemContent::Type(Branch::new(branch.type_ref.clone())),
1947            ItemContent::Move(range) => ItemContent::Move(range.clone()),
1948        }
1949    }
1950}
1951
1952impl std::fmt::Debug for Item {
1953    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1954        std::fmt::Display::fmt(self, f)
1955    }
1956}
1957
1958impl std::fmt::Display for Item {
1959    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1960        write!(f, "({}, len: {}", self.id, self.len)?;
1961        match &self.parent {
1962            TypePtr::Unknown => {}
1963            TypePtr::Branch(b) => {
1964                if let Some(ptr) = b.item.as_ref() {
1965                    write!(f, ", parent: {}", ptr.id())?;
1966                } else {
1967                    write!(f, ", parent: <root>")?;
1968                }
1969            }
1970            other => {
1971                write!(f, ", parent: {}", other)?;
1972            }
1973        }
1974        if let Some(m) = self.moved {
1975            write!(f, ", moved-to: {}", m)?;
1976        }
1977        if let Some(id) = self.redone.as_ref() {
1978            write!(f, ", redone: {}", id)?;
1979        }
1980        if let Some(origin) = self.origin.as_ref() {
1981            write!(f, ", origin-l: {}", origin)?;
1982        }
1983        if let Some(origin) = self.right_origin.as_ref() {
1984            write!(f, ", origin-r: {}", origin)?;
1985        }
1986        if let Some(left) = self.left.as_ref() {
1987            write!(f, ", left: {}", left.id())?;
1988        }
1989        if let Some(right) = self.right.as_ref() {
1990            write!(f, ", right: {}", right.id())?;
1991        }
1992        if let Some(key) = self.parent_sub.as_ref() {
1993            write!(f, ", '{}' =>", key)?;
1994        } else {
1995            write!(f, ":")?;
1996        }
1997        if self.is_deleted() {
1998            write!(f, " ~{}~", &self.content)?;
1999        } else {
2000            write!(f, " {}", &self.content)?;
2001        }
2002        if self.info.is_linked() {
2003            write!(f, "|linked")?;
2004        }
2005        write!(f, ")")
2006    }
2007}
2008
2009impl std::fmt::Display for ItemContent {
2010    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2011        match self {
2012            ItemContent::String(s) => write!(f, "'{}'", s),
2013            ItemContent::Any(s) => {
2014                write!(f, "[")?;
2015                let mut iter = s.iter();
2016                if let Some(a) = iter.next() {
2017                    write!(f, "{}", a.to_string())?;
2018                }
2019                while let Some(a) = iter.next() {
2020                    write!(f, ", {}", a.to_string())?;
2021                }
2022                write!(f, "]")
2023            }
2024            ItemContent::JSON(s) => {
2025                write!(f, "{{")?;
2026                let mut iter = s.iter();
2027                if let Some(a) = iter.next() {
2028                    write!(f, "{}", a)?;
2029                }
2030                while let Some(a) = iter.next() {
2031                    write!(f, ", {}", a)?;
2032                }
2033                write!(f, "}}")
2034            }
2035            ItemContent::Format(k, v) => write!(f, "<{}={}>", k, v),
2036            ItemContent::Deleted(s) => write!(f, "deleted({})", s),
2037            ItemContent::Binary(s) => write!(f, "{:?}", s),
2038            ItemContent::Type(inner) => match &inner.type_ref {
2039                TypeRef::Array => {
2040                    if let Some(ptr) = inner.start {
2041                        write!(f, "<array(head: {})>", ptr)
2042                    } else {
2043                        write!(f, "<array>")
2044                    }
2045                }
2046                TypeRef::Map => {
2047                    write!(f, "<map({{")?;
2048                    let mut iter = inner.map.iter();
2049                    if let Some((k, ptr)) = iter.next() {
2050                        write!(f, "'{}': {}", k, ptr)?;
2051                    }
2052                    while let Some((k, ptr)) = iter.next() {
2053                        write!(f, ", '{}': {}", k, ptr)?;
2054                    }
2055                    write!(f, "}})>")
2056                }
2057                TypeRef::Text => {
2058                    if let Some(start) = inner.start {
2059                        write!(f, "<text(head: {})>", start)
2060                    } else {
2061                        write!(f, "<text>")
2062                    }
2063                }
2064                TypeRef::XmlElement(name) => {
2065                    write!(f, "<xml element: {}>", name)
2066                }
2067                TypeRef::XmlFragment => write!(f, "<xml fragment>"),
2068                TypeRef::XmlHook => write!(f, "<xml hook>"),
2069                TypeRef::XmlText => write!(f, "<xml text>"),
2070                #[cfg(feature = "weak")]
2071                TypeRef::WeakLink(s) => write!(f, "<weak({}..{})>", s.quote_start, s.quote_end),
2072                _ => write!(f, "<undefined type ref>"),
2073            },
2074            ItemContent::Move(m) => std::fmt::Display::fmt(m.as_ref(), f),
2075            ItemContent::Doc(_, doc) => std::fmt::Display::fmt(doc, f),
2076            _ => Ok(()),
2077        }
2078    }
2079}
2080
2081impl std::fmt::Display for ItemPosition {
2082    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2083        write!(f, "(index: {}", self.index)?;
2084        if let Some(l) = self.left.as_ref() {
2085            write!(f, ", left: {}", l)?;
2086        }
2087        if let Some(r) = self.right.as_ref() {
2088            write!(f, ", right: {}", r)?;
2089        }
2090        write!(f, ")")
2091    }
2092}
2093
2094/// A trait used for preliminary types, that can be inserted into shared Yrs collections.
2095pub trait Prelim: Sized {
2096    /// Type of a value to be returned as a result of inserting this [Prelim] type instance.
2097    /// Use [Unused] if none is necessary.
2098    type Return: TryFrom<ItemPtr>;
2099
2100    /// This method is used to create initial content required in order to create a block item.
2101    /// A supplied `ptr` can be used to identify block that is about to be created to store
2102    /// the returned content.
2103    ///
2104    /// Since this method may decide to consume `self` or not, a second optional return parameter
2105    /// is used when `self` was not consumed - which is the case for complex types creation such as
2106    /// YMap or YArray. In such case it will be passed later on to [Self::integrate] method.
2107    fn into_content(self, txn: &mut TransactionMut) -> (ItemContent, Option<Self>);
2108
2109    /// Method called once an original item filled with content from [Self::into_content] has been
2110    /// added to block store. This method is used by complex types such as maps or arrays to append
2111    /// the original contents of prelim struct into YMap, YArray etc.
2112    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr);
2113}
2114
2115impl<T> Prelim for T
2116where
2117    T: Into<Any>,
2118{
2119    type Return = Unused;
2120
2121    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
2122        let value: Any = self.into();
2123        (ItemContent::Any(vec![value]), None)
2124    }
2125
2126    fn integrate(self, _txn: &mut TransactionMut, _inner_ref: BranchPtr) {}
2127}
2128
2129#[derive(Debug)]
2130pub(crate) struct PrelimString(pub SmallString<[u8; 8]>);
2131
2132impl Prelim for PrelimString {
2133    type Return = Unused;
2134
2135    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
2136        (ItemContent::String(self.0.into()), None)
2137    }
2138
2139    fn integrate(self, _txn: &mut TransactionMut, _inner_ref: BranchPtr) {}
2140}
2141
2142/// Empty type marker, which can be used by a [Prelim] trait implementations when no integrated
2143/// value should be returned after prelim type has been integrated as a result of insertion.
2144#[repr(transparent)]
2145pub struct Unused;
2146
2147impl TryFrom<ItemPtr> for Unused {
2148    type Error = ItemPtr;
2149
2150    #[inline(always)]
2151    fn try_from(_: ItemPtr) -> Result<Self, Self::Error> {
2152        Ok(Unused)
2153    }
2154}
2155
2156/// Prelim container for types passed over to [Text::insert_embed] and [Text::insert_embed_with_attributes] methods.
2157#[derive(Debug)]
2158pub enum EmbedPrelim<T> {
2159    Primitive(Any),
2160    Shared(T),
2161}
2162
2163impl<T> Prelim for EmbedPrelim<T>
2164where
2165    T: Prelim,
2166{
2167    type Return = T::Return;
2168
2169    fn into_content(self, txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
2170        match self {
2171            EmbedPrelim::Primitive(any) => (ItemContent::Embed(any), None),
2172            EmbedPrelim::Shared(prelim) => {
2173                let (branch, content) = prelim.into_content(txn);
2174                let carrier = if let Some(carrier) = content {
2175                    Some(EmbedPrelim::Shared(carrier))
2176                } else {
2177                    None
2178                };
2179                (branch, carrier)
2180            }
2181        }
2182    }
2183
2184    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
2185        if let EmbedPrelim::Shared(carrier) = self {
2186            carrier.integrate(txn, inner_ref)
2187        }
2188    }
2189}
2190
2191impl<T> From<T> for EmbedPrelim<T>
2192where
2193    T: Into<Any>,
2194{
2195    fn from(value: T) -> Self {
2196        EmbedPrelim::Primitive(value.into())
2197    }
2198}
2199
2200impl std::fmt::Display for ID {
2201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2202        write!(f, "<{}#{}>", self.client, self.clock)
2203    }
2204}
2205
2206impl std::fmt::Debug for ItemPtr {
2207    #[inline]
2208    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2209        std::fmt::Display::fmt(self, f)
2210    }
2211}
2212
2213impl std::fmt::Display for ItemPtr {
2214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2215        write!(f, "({})", self.id())
2216    }
2217}
2218
2219#[cfg(test)]
2220mod test {
2221    use crate::block::{split_str, SplittableString};
2222    use crate::doc::OffsetKind;
2223    use std::ops::Deref;
2224
2225    #[test]
2226    fn splittable_string_len() {
2227        let s: SplittableString = "Zażółć gęślą jaźń😀 女".into();
2228
2229        assert_eq!(s.len(OffsetKind::Bytes), 34, "wrong byte length");
2230        assert_eq!(s.len(OffsetKind::Utf16), 21, "wrong UTF-16 length");
2231    }
2232
2233    #[test]
2234    fn splittable_string_push_str() {
2235        let mut s: SplittableString = "Zażółć gęślą jaźń😀".into();
2236        s.push_str("ありがとうございます");
2237
2238        assert_eq!(
2239            s.deref(),
2240            &"Zażółć gęślą jaźń😀ありがとうございます".to_string()
2241        );
2242
2243        assert_eq!(s.len(OffsetKind::Bytes), 60, "wrong byte length");
2244        assert_eq!(s.len(OffsetKind::Utf16), 29, "wrong UTF-16 length");
2245    }
2246
2247    #[test]
2248    fn splittable_string_split_str() {
2249        let s: SplittableString = "Zażółć gęślą jaźń😀ありがとうございます".into();
2250
2251        let (a, b) = split_str(&s, 19, OffsetKind::Utf16);
2252        assert_eq!(a, "Zażółć gęślą jaźń😀");
2253        assert_eq!(b, "ありがとうございます");
2254
2255        let (a, b) = split_str(&s, 30, OffsetKind::Bytes);
2256        assert_eq!(a, "Zażółć gęślą jaźń😀");
2257        assert_eq!(b, "ありがとうございます");
2258    }
2259}