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