yrs/
branch.rs

1use crate::block::{BlockCell, Item, ItemContent, ItemPosition, ItemPtr, Prelim};
2use crate::types::array::ArrayEvent;
3use crate::types::map::MapEvent;
4use crate::types::text::TextEvent;
5use crate::types::xml::{XmlEvent, XmlTextEvent};
6use crate::types::{
7    Entries, Event, Events, Path, PathSegment, RootRef, SharedRef, TypePtr, TypeRef,
8};
9use crate::{
10    ArrayRef, Doc, MapRef, Observer, Origin, Out, ReadTxn, Subscription, TextRef, TransactionMut,
11    WriteTxn, XmlElementRef, XmlFragmentRef, XmlTextRef, ID,
12};
13use serde::{Deserialize, Serialize};
14use std::borrow::Borrow;
15use std::collections::{HashMap, HashSet, VecDeque};
16use std::convert::TryFrom;
17use std::fmt::Formatter;
18use std::hash::{Hash, Hasher};
19use std::marker::PhantomData;
20use std::ops::{Deref, DerefMut};
21use std::ptr::NonNull;
22use std::sync::Arc;
23
24/// A wrapper around [Branch] cell, supplied with a bunch of convenience methods to operate on both
25/// map-like and array-like contents of a [Branch].
26#[repr(transparent)]
27#[derive(Clone, Copy, Hash)]
28pub struct BranchPtr(NonNull<Branch>);
29
30unsafe impl Send for BranchPtr {}
31unsafe impl Sync for BranchPtr {}
32
33impl BranchPtr {
34    pub(crate) fn trigger(
35        &self,
36        txn: &TransactionMut,
37        subs: HashSet<Option<Arc<str>>>,
38    ) -> Option<Event> {
39        let e = self.make_event(subs)?;
40        self.observers.trigger(|fun| fun(txn, &e));
41        Some(e)
42    }
43
44    pub(crate) fn trigger_deep(&self, txn: &TransactionMut, e: &Events) {
45        self.deep_observers.trigger(|fun| fun(txn, e));
46    }
47}
48
49impl TryFrom<ItemPtr> for BranchPtr {
50    type Error = ItemPtr;
51
52    fn try_from(value: ItemPtr) -> Result<Self, Self::Error> {
53        if let ItemContent::Type(branch) = &value.content {
54            Ok(BranchPtr::from(branch))
55        } else {
56            Err(value)
57        }
58    }
59}
60
61impl Into<TypePtr> for BranchPtr {
62    fn into(self) -> TypePtr {
63        TypePtr::Branch(self)
64    }
65}
66
67impl Into<Origin> for BranchPtr {
68    fn into(self) -> Origin {
69        let addr = self.0.as_ptr() as usize;
70        let bytes = addr.to_be_bytes();
71        Origin::from(bytes.as_ref())
72    }
73}
74
75impl AsRef<Branch> for BranchPtr {
76    fn as_ref(&self) -> &Branch {
77        self.deref()
78    }
79}
80
81impl AsMut<Branch> for BranchPtr {
82    fn as_mut(&mut self) -> &mut Branch {
83        self.deref_mut()
84    }
85}
86
87impl Deref for BranchPtr {
88    type Target = Branch;
89
90    fn deref(&self) -> &Self::Target {
91        unsafe { self.0.as_ref() }
92    }
93}
94
95impl DerefMut for BranchPtr {
96    fn deref_mut(&mut self) -> &mut Self::Target {
97        unsafe { self.0.as_mut() }
98    }
99}
100
101impl<'a> From<&'a mut Box<Branch>> for BranchPtr {
102    fn from(branch: &'a mut Box<Branch>) -> Self {
103        let ptr = NonNull::from(branch.as_ref());
104        BranchPtr(ptr)
105    }
106}
107
108impl<'a> From<&'a Box<Branch>> for BranchPtr {
109    fn from(branch: &'a Box<Branch>) -> Self {
110        let b: &Branch = &*branch;
111
112        let ptr = unsafe { NonNull::new_unchecked(b as *const Branch as *mut Branch) };
113        BranchPtr(ptr)
114    }
115}
116
117impl<'a> From<&'a Branch> for BranchPtr {
118    fn from(branch: &'a Branch) -> Self {
119        let ptr = unsafe { NonNull::new_unchecked(branch as *const Branch as *mut Branch) };
120        BranchPtr(ptr)
121    }
122}
123
124impl Into<Out> for BranchPtr {
125    /// Converts current branch data into a [Out]. It uses a type ref information to resolve,
126    /// which value variant is a correct one for this branch. Since branch represent only complex
127    /// types [Out::Any] will never be returned from this method.
128    fn into(self) -> Out {
129        match self.type_ref() {
130            TypeRef::Array => Out::YArray(ArrayRef::from(self)),
131            TypeRef::Map => Out::YMap(MapRef::from(self)),
132            TypeRef::Text => Out::YText(TextRef::from(self)),
133            TypeRef::XmlElement(_) => Out::YXmlElement(XmlElementRef::from(self)),
134            TypeRef::XmlFragment => Out::YXmlFragment(XmlFragmentRef::from(self)),
135            TypeRef::XmlText => Out::YXmlText(XmlTextRef::from(self)),
136            //TYPE_REFS_XML_HOOK => Value::YXmlHook(XmlHookRef::from(self)),
137            #[cfg(feature = "weak")]
138            TypeRef::WeakLink(_) => Out::YWeakLink(crate::WeakRef::from(self)),
139            _ => Out::UndefinedRef(self),
140        }
141    }
142}
143
144impl Eq for BranchPtr {}
145
146#[cfg(not(test))]
147impl PartialEq for BranchPtr {
148    fn eq(&self, other: &Self) -> bool {
149        std::ptr::eq(self.0.as_ptr(), other.0.as_ptr())
150    }
151}
152
153#[cfg(test)]
154impl PartialEq for BranchPtr {
155    fn eq(&self, other: &Self) -> bool {
156        if NonNull::eq(&self.0, &other.0) {
157            true
158        } else {
159            let a: &Branch = self.deref();
160            let b: &Branch = other.deref();
161            a.eq(b)
162        }
163    }
164}
165
166impl std::fmt::Debug for BranchPtr {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        write!(f, "{:?}", self.id())
169    }
170}
171
172/// Branch describes a content of a complex Yrs data structures, such as arrays or maps.
173pub struct Branch {
174    /// A pointer to a first block of a indexed sequence component of this branch node. If `None`,
175    /// it means that sequence is empty or a branch doesn't act as an indexed sequence. Indexed
176    /// sequences include:
177    ///
178    /// - [Array]: all elements are stored as a double linked list, while the head of the list is
179    ///   kept in this field.
180    /// - [XmlElement]: this field acts as a head to a first child element stored within current XML
181    ///   node.
182    /// - [Text] and [XmlText]: this field point to a first chunk of text appended to collaborative
183    ///   text data structure.
184    pub(crate) start: Option<ItemPtr>,
185
186    /// A map component of this branch node, used by some of the specialized complex types
187    /// including:
188    ///
189    /// - [Map]: all of the map elements are based on this field. The value of each entry points
190    ///   to the last modified value.
191    /// - [XmlElement]: this field stores attributes assigned to a given XML node.
192    pub(crate) map: HashMap<Arc<str>, ItemPtr>,
193
194    /// Unique identifier of a current branch node. It can be contain either a named string - which
195    /// means, this branch is a root-level complex data structure - or a block identifier. In latter
196    /// case it means, that this branch is a complex type (eg. Map or Array) nested inside of
197    /// another complex type.
198    pub(crate) item: Option<ItemPtr>,
199
200    /// For root-level types, this is a name of a branch.
201    pub(crate) name: Option<Arc<str>>,
202
203    /// A length of an indexed sequence component of a current branch node. Map component elements
204    /// are computed on demand.
205    pub block_len: u32,
206
207    pub content_len: u32,
208
209    /// An identifier of an underlying complex data type (eg. is it an Array or a Map).
210    pub(crate) type_ref: TypeRef,
211
212    pub(crate) observers: Observer<ObserveFn>,
213
214    pub(crate) deep_observers: Observer<DeepObserveFn>,
215}
216
217#[cfg(feature = "sync")]
218type ObserveFn = Box<dyn Fn(&TransactionMut, &Event) + Send + Sync + 'static>;
219#[cfg(feature = "sync")]
220type DeepObserveFn = Box<dyn Fn(&TransactionMut, &Events) + Send + Sync + 'static>;
221
222#[cfg(not(feature = "sync"))]
223type ObserveFn = Box<dyn Fn(&TransactionMut, &Event) + 'static>;
224#[cfg(not(feature = "sync"))]
225type DeepObserveFn = Box<dyn Fn(&TransactionMut, &Events) + 'static>;
226
227impl std::fmt::Debug for Branch {
228    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229        std::fmt::Display::fmt(self, f)
230    }
231}
232
233impl Eq for Branch {}
234
235impl PartialEq for Branch {
236    fn eq(&self, other: &Self) -> bool {
237        self.item == other.item
238            && self.start == other.start
239            && self.map == other.map
240            && self.block_len == other.block_len
241            && self.type_ref == other.type_ref
242    }
243}
244
245impl Branch {
246    pub fn new(type_ref: TypeRef) -> Box<Self> {
247        Box::new(Self {
248            start: None,
249            map: HashMap::default(),
250            block_len: 0,
251            content_len: 0,
252            item: None,
253            name: None,
254            type_ref,
255            observers: Observer::default(),
256            deep_observers: Observer::default(),
257        })
258    }
259
260    pub fn is_deleted(&self) -> bool {
261        match self.item {
262            Some(ptr) => ptr.is_deleted(),
263            None => false,
264        }
265    }
266
267    pub fn id(&self) -> BranchID {
268        if let Some(ptr) = self.item {
269            BranchID::Nested(ptr.id)
270        } else if let Some(name) = &self.name {
271            BranchID::Root(name.clone())
272        } else {
273            unreachable!("Could not get ID for branch")
274        }
275    }
276
277    pub fn as_subdoc(&self) -> Option<Doc> {
278        let item = self.item?;
279        if let ItemContent::Doc(_, doc) = &item.content {
280            Some(doc.clone())
281        } else {
282            None
283        }
284    }
285
286    /// Returns an identifier of an underlying complex data type (eg. is it an Array or a Map).
287    pub fn type_ref(&self) -> &TypeRef {
288        &self.type_ref
289    }
290
291    pub(crate) fn repair_type_ref(&mut self, type_ref: TypeRef) {
292        if self.type_ref == TypeRef::Undefined {
293            self.type_ref = type_ref;
294        }
295    }
296
297    /// Returns a length of an indexed sequence component of a current branch node.
298    /// Map component elements are computed on demand.
299    pub fn len(&self) -> u32 {
300        self.block_len
301    }
302
303    pub fn content_len(&self) -> u32 {
304        self.content_len
305    }
306
307    /// Get iterator over (String, Block) entries of a map component of a current root type.
308    /// Deleted blocks are skipped by this iterator.
309    pub(crate) fn entries<'a, T: ReadTxn + 'a>(&'a self, txn: &'a T) -> Entries<'a, &'a T, T> {
310        Entries::from_ref(&self.map, txn)
311    }
312
313    /// Get iterator over Block entries of an array component of a current root type.
314    /// Deleted blocks are skipped by this iterator.
315    pub(crate) fn iter<'a, T: ReadTxn + 'a>(&'a self, txn: &'a T) -> Iter<'a, T> {
316        Iter::new(self.start.as_ref(), txn)
317    }
318
319    /// Returns a materialized value of non-deleted entry under a given `key` of a map component
320    /// of a current root type.
321    pub(crate) fn get<T: ReadTxn>(&self, _txn: &T, key: &str) -> Option<Out> {
322        let item = self.map.get(key)?;
323        if !item.is_deleted() {
324            item.content.get_last()
325        } else {
326            None
327        }
328    }
329
330    /// Given an `index` parameter, returns an item content reference which contains that index
331    /// together with an offset inside of this content, which points precisely to an `index`
332    /// location within wrapping item content.
333    /// If `index` was outside of the array component boundary of current branch node, `None` will
334    /// be returned.
335    pub(crate) fn get_at(&self, mut index: u32) -> Option<(&ItemContent, usize)> {
336        let mut ptr = self.start.as_ref();
337        while let Some(item) = ptr.map(ItemPtr::deref) {
338            let len = item.len();
339            if !item.is_deleted() && item.is_countable() {
340                if index < len {
341                    return Some((&item.content, index as usize));
342                }
343
344                index -= len;
345            }
346            ptr = item.right.as_ref();
347        }
348
349        None
350    }
351
352    /// Removes an entry under given `key` of a map component of a current root type, returning
353    /// a materialized representation of value stored underneath if entry existed prior deletion.
354    pub(crate) fn remove(&self, txn: &mut TransactionMut, key: &str) -> Option<Out> {
355        let item = *self.map.get(key)?;
356        let prev = if !item.is_deleted() {
357            item.content.get_last()
358        } else {
359            None
360        };
361        txn.delete(item);
362        prev
363    }
364
365    /// Returns a first non-deleted item from an array component of a current root type.
366    pub(crate) fn first(&self) -> Option<&Item> {
367        let mut ptr = self.start.as_ref();
368        while let Some(item) = ptr.map(ItemPtr::deref) {
369            if item.is_deleted() {
370                ptr = item.right.as_ref();
371            } else {
372                return Some(item);
373            }
374        }
375
376        None
377    }
378
379    /// Given an `index` and start block `ptr`, returns a pair of block pointers.
380    ///
381    /// If `index` happens to point inside of an existing block content, such block will be split at
382    /// position of an `index`. In such case left tuple value contains end of a block pointer on
383    /// a left side of an `index` and a pointer to a block directly on the right side of an `index`.
384    ///
385    /// If `index` point to the end of a block and no splitting is necessary, tuple will return only
386    /// left side (beginning of a block), while right side will be `None`.
387    ///
388    /// If `index` is outside the range of an array component of current branch node, both tuple
389    /// values will be `None`.
390    fn index_to_ptr(
391        txn: &mut TransactionMut,
392        mut ptr: Option<ItemPtr>,
393        mut index: u32,
394    ) -> (Option<ItemPtr>, Option<ItemPtr>) {
395        let encoding = txn.store.offset_kind;
396        while let Some(item) = ptr {
397            let content_len = item.content_len(encoding);
398            if !item.is_deleted() && item.is_countable() {
399                if index == content_len {
400                    let left = ptr;
401                    let right = item.right.clone();
402                    return (left, right);
403                } else if index < content_len {
404                    let index = if let ItemContent::String(s) = &item.content {
405                        s.block_offset(index, encoding)
406                    } else {
407                        index
408                    };
409                    let right = txn.store.blocks.split_block(item, index, encoding);
410                    if let Some(_) = item.moved {
411                        if let Some(src) = right {
412                            if let Some(&prev_dst) = txn.prev_moved.get(&item) {
413                                txn.prev_moved.insert(src, prev_dst);
414                            }
415                        }
416                    }
417                    return (ptr, right);
418                }
419                index -= content_len;
420            }
421            ptr = item.right.clone();
422        }
423        (None, None)
424    }
425    /// Removes up to a `len` of countable elements from current branch sequence, starting at the
426    /// given `index`. Returns number of removed elements.
427    pub(crate) fn remove_at(&self, txn: &mut TransactionMut, index: u32, len: u32) -> u32 {
428        let mut remaining = len;
429        let start = { self.start };
430        let (_, mut ptr) = if index == 0 {
431            (None, start)
432        } else {
433            Branch::index_to_ptr(txn, start, index)
434        };
435        while remaining > 0 {
436            if let Some(item) = ptr {
437                let encoding = txn.store().offset_kind;
438                if !item.is_deleted() {
439                    let content_len = item.content_len(encoding);
440                    let (l, r) = if remaining < content_len {
441                        let offset = if let ItemContent::String(s) = &item.content {
442                            s.block_offset(remaining, encoding)
443                        } else {
444                            remaining
445                        };
446                        remaining = 0;
447                        let new_right = txn.store.blocks.split_block(item, offset, encoding);
448                        if let Some(_) = item.moved {
449                            if let Some(src) = new_right {
450                                if let Some(&prev_dst) = txn.prev_moved.get(&item) {
451                                    txn.prev_moved.insert(src, prev_dst);
452                                }
453                            }
454                        }
455                        (item, new_right)
456                    } else {
457                        remaining -= content_len;
458                        (item, item.right.clone())
459                    };
460                    txn.delete(l);
461                    ptr = r;
462                } else {
463                    ptr = item.right.clone();
464                }
465            } else {
466                break;
467            }
468        }
469
470        len - remaining
471    }
472
473    /// Inserts a preliminary `value` into a current branch indexed sequence component at the given
474    /// `index`. Returns an item reference created as a result of this operation.
475    pub(crate) fn insert_at<V: Prelim>(
476        &self,
477        txn: &mut TransactionMut,
478        index: u32,
479        value: V,
480    ) -> Option<ItemPtr> {
481        let (start, parent) = {
482            if index <= self.len() {
483                (self.start, BranchPtr::from(self))
484            } else {
485                panic!("Cannot insert item at index over the length of an array")
486            }
487        };
488        let (left, right) = if index == 0 {
489            (None, None)
490        } else {
491            Branch::index_to_ptr(txn, start, index)
492        };
493        let pos = ItemPosition {
494            parent: parent.into(),
495            left,
496            right,
497            index: 0,
498            current_attrs: None,
499        };
500
501        txn.create_item(&pos, value, None)
502    }
503
504    pub(crate) fn path(from: BranchPtr, to: BranchPtr) -> Path {
505        let parent = from;
506        let mut child = to;
507        let mut path = VecDeque::default();
508        while let Some(item) = &child.item {
509            if parent.item == child.item {
510                break;
511            }
512            let item_id = item.id.clone();
513            let parent_sub = item.parent_sub.clone();
514            child = *item.parent.as_branch().unwrap();
515            if let Some(parent_sub) = parent_sub {
516                // parent is map-ish
517                path.push_front(PathSegment::Key(parent_sub));
518            } else {
519                // parent is array-ish
520                let mut i = 0;
521                let mut c = child.start;
522                while let Some(ptr) = c {
523                    if ptr.id() == &item_id {
524                        break;
525                    }
526                    if !ptr.is_deleted() && ptr.is_countable() {
527                        i += ptr.len();
528                    }
529                    c = ptr.right;
530                }
531                path.push_front(PathSegment::Index(i));
532            }
533        }
534        path
535    }
536
537    #[cfg(feature = "sync")]
538    pub fn observe<F>(&mut self, f: F) -> Subscription
539    where
540        F: Fn(&TransactionMut, &Event) + Send + Sync + 'static,
541    {
542        self.observers.subscribe(Box::new(f))
543    }
544
545    #[cfg(not(feature = "sync"))]
546    pub fn observe<F>(&mut self, f: F) -> Subscription
547    where
548        F: Fn(&TransactionMut, &Event) + 'static,
549    {
550        self.observers.subscribe(Box::new(f))
551    }
552
553    #[cfg(feature = "sync")]
554
555    pub fn observe_with<F>(&mut self, key: Origin, f: F)
556    where
557        F: Fn(&TransactionMut, &Event) + Send + Sync + 'static,
558    {
559        self.observers.subscribe_with(key, Box::new(f))
560    }
561
562    #[cfg(not(feature = "sync"))]
563    pub fn observe_with<F>(&mut self, key: Origin, f: F)
564    where
565        F: Fn(&TransactionMut, &Event) + 'static,
566    {
567        self.observers.subscribe_with(key, Box::new(f))
568    }
569
570    pub fn unobserve(&mut self, key: &Origin) -> bool {
571        self.observers.unsubscribe(&key)
572    }
573
574    #[cfg(feature = "sync")]
575    pub fn observe_deep<F>(&self, f: F) -> Subscription
576    where
577        F: Fn(&TransactionMut, &Events) + Send + Sync + 'static,
578    {
579        self.deep_observers.subscribe(Box::new(f))
580    }
581
582    #[cfg(not(feature = "sync"))]
583    pub fn observe_deep<F>(&self, f: F) -> Subscription
584    where
585        F: Fn(&TransactionMut, &Events) + 'static,
586    {
587        self.deep_observers.subscribe(Box::new(f))
588    }
589
590    #[cfg(feature = "sync")]
591    pub fn observe_deep_with<F>(&self, key: Origin, f: F)
592    where
593        F: Fn(&TransactionMut, &Events) + Send + Sync + 'static,
594    {
595        self.deep_observers.subscribe_with(key, Box::new(f))
596    }
597
598    #[cfg(not(feature = "sync"))]
599    pub fn observe_deep_with<F>(&self, key: Origin, f: F)
600    where
601        F: Fn(&TransactionMut, &Events) + 'static,
602    {
603        self.deep_observers.subscribe_with(key, Box::new(f))
604    }
605
606    pub(crate) fn is_parent_of(&self, mut ptr: Option<ItemPtr>) -> bool {
607        while let Some(i) = ptr.as_deref() {
608            if let Some(parent) = i.parent.as_branch() {
609                if parent.deref() == self {
610                    return true;
611                }
612                ptr = parent.item;
613            } else {
614                break;
615            }
616        }
617        false
618    }
619
620    pub(crate) fn make_event(&self, keys: HashSet<Option<Arc<str>>>) -> Option<Event> {
621        let self_ptr = BranchPtr::from(self);
622        let event = match self.type_ref() {
623            TypeRef::Array => Event::Array(ArrayEvent::new(self_ptr)),
624            TypeRef::Map => Event::Map(MapEvent::new(self_ptr, keys)),
625            TypeRef::Text => Event::Text(TextEvent::new(self_ptr)),
626            TypeRef::XmlElement(_) | TypeRef::XmlFragment => {
627                Event::XmlFragment(XmlEvent::new(self_ptr, keys))
628            }
629            TypeRef::XmlText => Event::XmlText(XmlTextEvent::new(self_ptr, keys)),
630            #[cfg(feature = "weak")]
631            TypeRef::WeakLink(_) => Event::Weak(crate::types::weak::WeakEvent::new(self_ptr)),
632            _ => return None,
633        };
634
635        Some(event)
636    }
637}
638
639pub(crate) struct Iter<'a, T> {
640    ptr: Option<&'a ItemPtr>,
641    _txn: &'a T,
642}
643
644impl<'a, T: ReadTxn> Iter<'a, T> {
645    fn new(ptr: Option<&'a ItemPtr>, txn: &'a T) -> Self {
646        Iter { ptr, _txn: txn }
647    }
648}
649
650impl<'a, T: ReadTxn> Iterator for Iter<'a, T> {
651    type Item = &'a Item;
652
653    fn next(&mut self) -> Option<Self::Item> {
654        let item = self.ptr.take()?;
655        self.ptr = item.right.as_ref();
656        Some(item)
657    }
658}
659
660/// A logical reference to a root-level shared collection. It can be shared across different
661/// documents to reference the same logical type.
662///
663/// # Example
664///
665/// ```rust
666/// use yrs::{Doc, RootRef, SharedRef, TextRef, Transact};
667///
668/// let root = TextRef::root("hello");
669///
670/// let doc1 = Doc::new();
671/// let txt1 = root.get_or_create(&mut doc1.transact_mut());
672///
673/// let doc2 = Doc::new();
674/// let txt2 = root.get_or_create(&mut doc2.transact_mut());
675///
676/// // instances of TextRef point to different heap objects
677/// assert_ne!(&txt1 as *const _, &txt2 as *const _);
678///
679/// // logical descriptors of both TextRef are the same as they refer to the
680/// // same logical entity
681/// assert_eq!(txt1.hook(), txt2.hook());
682/// ```
683#[repr(transparent)]
684#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
685pub struct Root<S> {
686    /// Unique identifier of root-level shared collection.
687    pub name: Arc<str>,
688    _tag: PhantomData<S>,
689}
690
691impl<S: RootRef> Root<S> {
692    /// Creates a new logical reference for a root-level shared collection of a given name and type.
693    /// Returned value can be used to resolve instances of root-level types by calling [Root::get]
694    /// or [Root::get_or_create].
695    pub fn new<N: Into<Arc<str>>>(name: N) -> Self {
696        Root {
697            name: name.into(),
698            _tag: PhantomData::default(),
699        }
700    }
701
702    /// Returns a reference to a shared root-level collection current [Root] represents, or creates
703    /// it if it wasn't instantiated before.
704    pub fn get_or_create<T: WriteTxn>(&self, txn: &mut T) -> S {
705        let store = txn.store_mut();
706        let branch = store.get_or_create_type(self.name.clone(), S::type_ref());
707        S::from(branch)
708    }
709}
710
711impl<S: SharedRef> Root<S> {
712    /// Returns a reference to a shared collection current [Root] represents, or returns `None` if
713    /// that collection hasn't been instantiated yet.
714    pub fn get<T: ReadTxn>(&self, txn: &T) -> Option<S> {
715        txn.store().get_type(self.name.clone()).map(S::from)
716    }
717}
718
719impl<S> Into<BranchID> for Root<S> {
720    fn into(self) -> BranchID {
721        BranchID::Root(self.name)
722    }
723}
724
725/// A logical reference used to represent a shared collection nested within another one. Unlike
726/// [Root]-level types which cannot be deleted and exist eternally, [Nested] collections can be
727/// added (therefore don't exist prior their instantiation) and deleted (so that any [SharedRef]
728/// values referencing them become unsafe and can point to objects that no longer exists!).
729///
730/// Use [Nested::get] in order to materialize current nested logical reference into shared ref type.
731///
732/// # Example
733///
734/// ```rust
735/// use yrs::{Doc, Map, Nested, SharedRef, TextPrelim, TextRef, Transact, WriteTxn};
736///
737/// let doc = Doc::new();
738/// let mut txn = doc.transact_mut();
739/// let root = txn.get_or_insert_map("root"); // root-level collection
740/// let text = root.insert(&mut txn, "nested", TextPrelim::new("")); // nested collection
741///
742/// // convert nested TextRef into logical pointer
743/// let nested: Nested<TextRef> = text.hook().into_nested().unwrap();
744///
745/// // logical reference can be used to retrieve accessible TextRef when its alive
746/// assert_eq!(nested.get(&txn), Some(text));
747///
748/// // delete nested collection
749/// root.remove(&mut txn, "nested");
750///
751/// // logical reference cannot resolve shared collections that have been deleted already
752/// assert_eq!(nested.get(&txn), None);
753/// ```
754#[repr(transparent)]
755#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
756pub struct Nested<S> {
757    pub id: ID,
758    _tag: PhantomData<S>,
759}
760
761impl<S> Nested<S> {
762    pub fn new(id: ID) -> Self {
763        Nested {
764            id,
765            _tag: PhantomData::default(),
766        }
767    }
768}
769
770impl<S: SharedRef> Nested<S> {
771    /// If current [Nested] logical reference points to an instantiated and not-deleted shared
772    /// collection, a reference to that collection will be returned.
773    /// If the referenced collection has been deleted or was not yet present in current transaction
774    /// scope i.e. due to missing update, a `None` will be returned.  
775    pub fn get<T: ReadTxn>(&self, txn: &T) -> Option<S> {
776        let store = txn.store();
777        let block = store.blocks.get_block(&self.id)?;
778        if let BlockCell::Block(block) = block {
779            if let ItemContent::Type(branch) = &block.content {
780                if let Some(ptr) = branch.item {
781                    if !ptr.is_deleted() {
782                        return Some(S::from(BranchPtr::from(&*branch)));
783                    }
784                }
785            }
786        }
787        None
788    }
789}
790
791impl<S> Into<BranchID> for Nested<S> {
792    fn into(self) -> BranchID {
793        BranchID::Nested(self.id)
794    }
795}
796
797/// A descriptor used to reference to shared collections by their unique logical identifiers,
798/// which can be either [Root]-level collections or shared collections [Nested] into each other.
799/// It can be resolved from any shared reference using [SharedRef::hook].
800#[derive(Clone, Serialize, Deserialize)]
801pub struct Hook<S> {
802    id: BranchID,
803    _tag: PhantomData<S>,
804}
805
806impl<S> Hook<S> {
807    /// Unique logical identifier of a shared collection.
808    #[inline]
809    pub fn id(&self) -> &BranchID {
810        &self.id
811    }
812}
813
814impl<S> std::fmt::Debug for Hook<S> {
815    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
816        write!(f, "{:?}", self.id)
817    }
818}
819
820impl<S> Eq for Hook<S> {}
821
822impl<S> PartialEq for Hook<S> {
823    fn eq(&self, other: &Self) -> bool {
824        self.id == other.id
825    }
826}
827
828impl<S> Hash for Hook<S> {
829    fn hash<H: Hasher>(&self, state: &mut H) {
830        self.id.hash(state)
831    }
832}
833
834impl<S: SharedRef> Hook<S> {
835    /// Returns a reference to a shared collection current hook points to, if it exists and
836    /// (in case of nested collections) has not been deleted.
837    ///
838    /// # Example
839    ///
840    /// ```rust
841    /// use yrs::{Hook, Doc, Map, MapRef, Nested, SharedRef, TextPrelim, TextRef, Transact, WriteTxn};
842    ///
843    /// let doc = Doc::new();
844    /// let mut txn = doc.transact_mut();
845    /// let root = txn.get_or_insert_map("root"); // root-level collection
846    /// let nested = root.insert(&mut txn, "nested", TextPrelim::new("")); // nested collection
847    ///
848    /// let root_hook: Hook<MapRef> = root.hook();
849    /// let nested_hook: Hook<TextRef> = nested.hook();
850    ///
851    /// // hook can be used to retrieve collection reference as long as its alive
852    /// assert_eq!(nested_hook.get(&txn), Some(nested));
853    ///
854    /// // after nested collection is deleted it can no longer be referenced
855    /// root.remove(&mut txn, "nested");
856    /// assert_eq!(nested_hook.get(&txn), None, "wtf");
857    ///
858    /// // descriptors work also for root types
859    /// assert_eq!(root_hook.get(&txn), Some(root));
860    /// ```
861    pub fn get<T: ReadTxn>(&self, txn: &T) -> Option<S> {
862        let branch = self.id.get_branch(txn)?;
863        match branch.item {
864            Some(ptr) if ptr.is_deleted() => None,
865            _ => Some(S::from(branch)),
866        }
867    }
868
869    /// Attempts to convert current [Hook] type into [Nested] one.
870    /// Returns `None` if current descriptor doesn't reference a nested shared collection.  
871    pub fn into_nested(self) -> Option<Nested<S>> {
872        match self.id {
873            BranchID::Nested(id) => Some(Nested::new(id)),
874            BranchID::Root(_) => None,
875        }
876    }
877}
878
879impl<S: RootRef> Hook<S> {
880    /// Attempts to convert current [Hook] type into [Root] one.
881    /// Returns `None` if current descriptor doesn't reference a root-level shared collection.
882    pub fn into_root(self) -> Option<Root<S>> {
883        match self.id {
884            BranchID::Root(name) => Some(Root::new(name)),
885            BranchID::Nested(_) => None,
886        }
887    }
888}
889
890impl<S> From<Root<S>> for Hook<S> {
891    fn from(root: Root<S>) -> Self {
892        Hook {
893            id: root.into(),
894            _tag: PhantomData::default(),
895        }
896    }
897}
898
899impl<S> From<Nested<S>> for Hook<S> {
900    fn from(nested: Nested<S>) -> Self {
901        Hook {
902            id: nested.into(),
903            _tag: PhantomData::default(),
904        }
905    }
906}
907
908impl<S> From<BranchID> for Hook<S> {
909    fn from(id: BranchID) -> Self {
910        Hook {
911            id,
912            _tag: PhantomData::default(),
913        }
914    }
915}
916
917impl<S> Into<BranchID> for Hook<S> {
918    fn into(self) -> BranchID {
919        self.id
920    }
921}
922
923/// An unique logical identifier of a shared collection. Can be shared across document boundaries
924/// to reference to the same logical entity across different replicas of a document.
925#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
926pub enum BranchID {
927    Nested(ID),
928    Root(Arc<str>),
929}
930
931impl BranchID {
932    #[inline]
933    pub fn get_root<T: ReadTxn, K: Borrow<str>>(txn: &T, name: K) -> Option<BranchPtr> {
934        txn.store().get_type(name)
935    }
936
937    pub fn get_nested<T: ReadTxn>(txn: &T, id: &ID) -> Option<BranchPtr> {
938        let block = txn.store().blocks.get_block(id)?;
939        if let BlockCell::Block(block) = block {
940            if let ItemContent::Type(branch) = &block.content {
941                return Some(BranchPtr::from(&*branch));
942            }
943        }
944        None
945    }
946
947    pub fn get_branch<T: ReadTxn>(&self, txn: &T) -> Option<BranchPtr> {
948        match self {
949            BranchID::Root(name) => Self::get_root(txn, name.as_ref()),
950            BranchID::Nested(id) => Self::get_nested(txn, id),
951        }
952    }
953}
954
955impl std::fmt::Debug for BranchID {
956    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
957        match self {
958            BranchID::Nested(id) => write!(f, "{}", id),
959            BranchID::Root(name) => write!(f, "'{}'", name),
960        }
961    }
962}