yrs/types/
mod.rs

1use serde::{Serialize, Serializer};
2use std::borrow::Borrow;
3use std::collections::{HashMap, HashSet, VecDeque};
4use std::fmt::Formatter;
5use std::marker::PhantomData;
6use std::sync::Arc;
7
8pub use map::Map;
9pub use map::MapRef;
10pub use text::Text;
11pub use text::TextRef;
12
13use crate::block::{Item, ItemContent, ItemPtr, Prelim};
14use crate::branch::{Branch, BranchPtr};
15use crate::encoding::read::Error;
16use crate::transaction::TransactionMut;
17use crate::types::array::{ArrayEvent, ArrayRef};
18use crate::types::map::MapEvent;
19use crate::types::text::TextEvent;
20#[cfg(feature = "weak")]
21use crate::types::weak::{LinkSource, WeakEvent, WeakRef};
22use crate::types::xml::{XmlElementRef, XmlEvent, XmlTextEvent, XmlTextRef};
23use crate::updates::decoder::{Decode, Decoder};
24use crate::updates::encoder::{Encode, Encoder};
25use crate::*;
26
27pub mod array;
28pub mod map;
29pub mod text;
30#[cfg(feature = "weak")]
31pub mod weak;
32pub mod xml;
33
34/// Type ref identifier for an [ArrayRef] type.
35pub const TYPE_REFS_ARRAY: u8 = 0;
36
37/// Type ref identifier for a [MapRef] type.
38pub const TYPE_REFS_MAP: u8 = 1;
39
40/// Type ref identifier for a [TextRef] type.
41pub const TYPE_REFS_TEXT: u8 = 2;
42
43/// Type ref identifier for a [XmlElementRef] type.
44pub const TYPE_REFS_XML_ELEMENT: u8 = 3;
45
46/// Type ref identifier for a [XmlFragmentRef] type. Used for compatibility.
47pub const TYPE_REFS_XML_FRAGMENT: u8 = 4;
48
49/// Type ref identifier for a [XmlHookRef] type. Used for compatibility.
50pub const TYPE_REFS_XML_HOOK: u8 = 5;
51
52/// Type ref identifier for a [XmlTextRef] type.
53pub const TYPE_REFS_XML_TEXT: u8 = 6;
54
55/// Type ref identifier for a [WeakRef] type.
56pub const TYPE_REFS_WEAK: u8 = 7;
57
58/// Type ref identifier for a [DocRef] type.
59pub const TYPE_REFS_DOC: u8 = 9;
60
61/// Placeholder type ref identifier for non-specialized AbstractType. Used only for root-level types
62/// which have been integrated from remote peers before they were defined locally.
63pub const TYPE_REFS_UNDEFINED: u8 = 15;
64
65#[repr(u8)]
66#[derive(Debug, Clone, Eq, PartialEq)]
67pub enum TypeRef {
68    Array = TYPE_REFS_ARRAY,
69    Map = TYPE_REFS_MAP,
70    Text = TYPE_REFS_TEXT,
71    XmlElement(Arc<str>) = TYPE_REFS_XML_ELEMENT,
72    XmlFragment = TYPE_REFS_XML_FRAGMENT,
73    XmlHook = TYPE_REFS_XML_HOOK,
74    XmlText = TYPE_REFS_XML_TEXT,
75    SubDoc = TYPE_REFS_DOC,
76    #[cfg(feature = "weak")]
77    WeakLink(Arc<LinkSource>) = TYPE_REFS_WEAK,
78    Undefined = TYPE_REFS_UNDEFINED,
79}
80
81impl TypeRef {
82    pub fn kind(&self) -> u8 {
83        match self {
84            TypeRef::Array => TYPE_REFS_ARRAY,
85            TypeRef::Map => TYPE_REFS_MAP,
86            TypeRef::Text => TYPE_REFS_TEXT,
87            TypeRef::XmlElement(_) => TYPE_REFS_XML_ELEMENT,
88            TypeRef::XmlFragment => TYPE_REFS_XML_FRAGMENT,
89            TypeRef::XmlHook => TYPE_REFS_XML_HOOK,
90            TypeRef::XmlText => TYPE_REFS_XML_TEXT,
91            TypeRef::SubDoc => TYPE_REFS_DOC,
92            #[cfg(feature = "weak")]
93            TypeRef::WeakLink(_) => TYPE_REFS_WEAK,
94            TypeRef::Undefined => TYPE_REFS_UNDEFINED,
95        }
96    }
97
98    #[cfg(feature = "weak")]
99    fn encode_weak_link<E: Encoder>(data: &LinkSource, encoder: &mut E) {
100        encoder.write_type_ref(TYPE_REFS_WEAK);
101        let mut info = 0u8;
102        let is_single = data.is_single();
103        if !is_single {
104            info |= WEAK_REF_FLAGS_QUOTE;
105        };
106        if data.quote_start.is_root() || data.quote_end.is_root() {
107            info |= WEAK_REF_FLAGS_PARENT_ROOT;
108        }
109        if !data.quote_start.is_relative() {
110            info |= WEAK_REF_FLAGS_START_UNBOUNDED;
111        }
112        if !data.quote_end.is_relative() {
113            info |= WEAK_REF_FLAGS_END_UNBOUNDED;
114        }
115        if data.quote_start.assoc == Assoc::After {
116            info |= WEAK_REF_FLAGS_START_ASSOC;
117        }
118        if data.quote_end.assoc == Assoc::After {
119            info |= WEAK_REF_FLAGS_END_ASSOC;
120        }
121        encoder.write_u8(info);
122        match data.quote_start.scope() {
123            IndexScope::Relative(id) | IndexScope::Nested(id) => {
124                encoder.write_var(id.client);
125                encoder.write_var(id.clock);
126            }
127            IndexScope::Root(name) => {
128                encoder.write_string(name);
129            }
130        }
131
132        match data.quote_end.scope() {
133            IndexScope::Relative(id) if !is_single => {
134                encoder.write_var(id.client);
135                encoder.write_var(id.clock);
136            }
137            IndexScope::Relative(id) => {
138                // for single element id is the same as start so we can infer it
139            }
140            IndexScope::Nested(id) => {
141                encoder.write_var(id.client);
142                encoder.write_var(id.clock);
143            }
144            IndexScope::Root(name) => {
145                encoder.write_string(name);
146            }
147        }
148    }
149
150    #[cfg(feature = "weak")]
151    fn decode_weak_link<D: Decoder>(decoder: &mut D) -> Result<Arc<LinkSource>, Error> {
152        let flags = decoder.read_u8()?;
153        let is_single = flags & WEAK_REF_FLAGS_QUOTE == 0;
154        let start_assoc = if flags & WEAK_REF_FLAGS_START_ASSOC == WEAK_REF_FLAGS_START_ASSOC {
155            Assoc::After
156        } else {
157            Assoc::Before
158        };
159        let end_assoc = if flags & WEAK_REF_FLAGS_END_ASSOC == WEAK_REF_FLAGS_END_ASSOC {
160            Assoc::After
161        } else {
162            Assoc::Before
163        };
164        let is_start_unbounded =
165            flags & WEAK_REF_FLAGS_START_UNBOUNDED == WEAK_REF_FLAGS_START_UNBOUNDED;
166        let is_end_unbounded = flags & WEAK_REF_FLAGS_END_UNBOUNDED == WEAK_REF_FLAGS_END_UNBOUNDED;
167        let is_parent_root = flags & WEAK_REF_FLAGS_PARENT_ROOT == WEAK_REF_FLAGS_PARENT_ROOT;
168        let start_scope = if is_start_unbounded {
169            if is_parent_root {
170                let name = decoder.read_string()?;
171                IndexScope::Root(name.into())
172            } else {
173                IndexScope::Nested(ID::new(decoder.read_var()?, decoder.read_var()?))
174            }
175        } else {
176            IndexScope::Relative(ID::new(decoder.read_var()?, decoder.read_var()?))
177        };
178
179        let end_scope = if is_end_unbounded {
180            if is_parent_root {
181                let name = decoder.read_string()?;
182                IndexScope::Root(name.into())
183            } else {
184                IndexScope::Nested(ID::new(decoder.read_var()?, decoder.read_var()?))
185            }
186        } else if is_single {
187            start_scope.clone()
188        } else {
189            IndexScope::Relative(ID::new(decoder.read_var()?, decoder.read_var()?))
190        };
191        let start = StickyIndex::new(start_scope, start_assoc);
192        let end = StickyIndex::new(end_scope, end_assoc);
193        Ok(Arc::new(LinkSource::new(start, end)))
194    }
195}
196
197impl std::fmt::Display for TypeRef {
198    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
199        match self {
200            TypeRef::Array => write!(f, "Array"),
201            TypeRef::Map => write!(f, "Map"),
202            TypeRef::Text => write!(f, "Text"),
203            TypeRef::XmlElement(name) => write!(f, "XmlElement({})", name),
204            TypeRef::XmlFragment => write!(f, "XmlFragment"),
205            TypeRef::XmlHook => write!(f, "XmlHook"),
206            TypeRef::XmlText => write!(f, "XmlText"),
207            TypeRef::SubDoc => write!(f, "Doc"),
208            #[cfg(feature = "weak")]
209            TypeRef::WeakLink(_) => write!(f, "WeakRef"),
210            TypeRef::Undefined => write!(f, "(undefined)"),
211        }
212    }
213}
214
215/// Marks is weak ref is quotation spanning over multiple elements.
216const WEAK_REF_FLAGS_QUOTE: u8 = 0b0000_0001;
217/// Marks is start boundary of weak ref is [Assoc::After].
218const WEAK_REF_FLAGS_START_ASSOC: u8 = 0b0000_0010;
219/// Marks is end boundary of weak ref is [Assoc::After].
220const WEAK_REF_FLAGS_END_ASSOC: u8 = 0b0000_0100;
221/// Marks if start boundary of weak ref is unbounded.
222const WEAK_REF_FLAGS_START_UNBOUNDED: u8 = 0b0000_1000;
223/// Marks if end boundary of weak ref is unbounded.
224const WEAK_REF_FLAGS_END_UNBOUNDED: u8 = 0b0001_0000;
225/// Marks if weak ref references a root type. Only needed for both sides unbounded elements.
226const WEAK_REF_FLAGS_PARENT_ROOT: u8 = 0b0010_0000;
227
228impl Encode for TypeRef {
229    fn encode<E: Encoder>(&self, encoder: &mut E) {
230        match self {
231            TypeRef::Array => encoder.write_type_ref(TYPE_REFS_ARRAY),
232            TypeRef::Map => encoder.write_type_ref(TYPE_REFS_MAP),
233            TypeRef::Text => encoder.write_type_ref(TYPE_REFS_TEXT),
234            TypeRef::XmlElement(name) => {
235                encoder.write_type_ref(TYPE_REFS_XML_ELEMENT);
236                encoder.write_key(&name);
237            }
238            TypeRef::XmlFragment => encoder.write_type_ref(TYPE_REFS_XML_FRAGMENT),
239            TypeRef::XmlHook => encoder.write_type_ref(TYPE_REFS_XML_HOOK),
240            TypeRef::XmlText => encoder.write_type_ref(TYPE_REFS_XML_TEXT),
241            TypeRef::SubDoc => encoder.write_type_ref(TYPE_REFS_DOC),
242            #[cfg(feature = "weak")]
243            TypeRef::WeakLink(data) => Self::encode_weak_link(data, encoder),
244            TypeRef::Undefined => encoder.write_type_ref(TYPE_REFS_UNDEFINED),
245        }
246    }
247}
248
249impl Decode for TypeRef {
250    fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, Error> {
251        let type_ref = decoder.read_type_ref()?;
252        match type_ref {
253            TYPE_REFS_ARRAY => Ok(TypeRef::Array),
254            TYPE_REFS_MAP => Ok(TypeRef::Map),
255            TYPE_REFS_TEXT => Ok(TypeRef::Text),
256            TYPE_REFS_XML_ELEMENT => Ok(TypeRef::XmlElement(decoder.read_key()?)),
257            TYPE_REFS_XML_FRAGMENT => Ok(TypeRef::XmlFragment),
258            TYPE_REFS_XML_HOOK => Ok(TypeRef::XmlHook),
259            TYPE_REFS_XML_TEXT => Ok(TypeRef::XmlText),
260            TYPE_REFS_DOC => Ok(TypeRef::SubDoc),
261            #[cfg(feature = "weak")]
262            TYPE_REFS_WEAK => {
263                let source = Self::decode_weak_link(decoder)?;
264                Ok(TypeRef::WeakLink(source))
265            }
266            TYPE_REFS_UNDEFINED => Ok(TypeRef::Undefined),
267            _ => Err(Error::UnexpectedValue),
268        }
269    }
270}
271
272#[cfg(feature = "sync")]
273pub trait Observable: AsRef<Branch> {
274    type Event;
275
276    /// Subscribes a given callback to be triggered whenever current y-type is changed.
277    /// A callback is triggered whenever a transaction gets committed. This function does not
278    /// trigger if changes have been observed by nested shared collections.
279    ///
280    /// All array-like event changes can be tracked by using [Event::delta] method.
281    /// All map-like event changes can be tracked by using [Event::keys] method.
282    /// All text-like event changes can be tracked by using [TextEvent::delta] method.
283    ///
284    /// Returns a [Subscription] which, when dropped, will unsubscribe current callback.
285    fn observe<F>(&self, f: F) -> Subscription
286    where
287        F: Fn(&TransactionMut, &Self::Event) + Send + Sync + 'static,
288        Event: AsRef<Self::Event>,
289    {
290        let mut branch = BranchPtr::from(self.as_ref());
291        branch.observe(move |txn, e| {
292            let mapped_event = e.as_ref();
293            f(txn, mapped_event)
294        })
295    }
296
297    /// Subscribes a given callback to be triggered whenever current y-type is changed.
298    /// A callback is triggered whenever a transaction gets committed. This function does not
299    /// trigger if changes have been observed by nested shared collections.
300    ///
301    /// All array-like event changes can be tracked by using [Event::delta] method.
302    /// All map-like event changes can be tracked by using [Event::keys] method.
303    /// All text-like event changes can be tracked by using [TextEvent::delta] method.
304    ///
305    /// Provided key may be used later to unsubscribe from the event.
306    fn observe_with<K, F>(&self, key: K, f: F)
307    where
308        K: Into<Origin>,
309        F: Fn(&TransactionMut, &Self::Event) + Send + Sync + 'static,
310        Event: AsRef<Self::Event>,
311    {
312        let mut branch = BranchPtr::from(self.as_ref());
313        branch.observe_with(key.into(), move |txn, e| {
314            let mapped_event = e.as_ref();
315            f(txn, mapped_event)
316        })
317    }
318
319    /// Unsubscribes a given callback identified by key, that was previously subscribed using [Self::observe_with].
320    fn unobserve<K: Into<Origin>>(&self, key: K) -> bool {
321        let mut branch = BranchPtr::from(self.as_ref());
322        branch.unobserve(&key.into())
323    }
324}
325
326#[cfg(not(feature = "sync"))]
327pub trait Observable: AsRef<Branch> {
328    type Event;
329
330    /// Subscribes a given callback to be triggered whenever current y-type is changed.
331    /// A callback is triggered whenever a transaction gets committed. This function does not
332    /// trigger if changes have been observed by nested shared collections.
333    ///
334    /// All array-like event changes can be tracked by using [Event::delta] method.
335    /// All map-like event changes can be tracked by using [Event::keys] method.
336    /// All text-like event changes can be tracked by using [TextEvent::delta] method.
337    ///
338    /// Returns a [Subscription] which, when dropped, will unsubscribe current callback.
339    fn observe<F>(&self, f: F) -> Subscription
340    where
341        F: Fn(&TransactionMut, &Self::Event) + 'static,
342        Event: AsRef<Self::Event>,
343    {
344        let mut branch = BranchPtr::from(self.as_ref());
345        branch.observe(move |txn, e| {
346            let mapped_event = e.as_ref();
347            f(txn, mapped_event)
348        })
349    }
350
351    /// Subscribes a given callback to be triggered whenever current y-type is changed.
352    /// A callback is triggered whenever a transaction gets committed. This function does not
353    /// trigger if changes have been observed by nested shared collections.
354    ///
355    /// All array-like event changes can be tracked by using [Event::delta] method.
356    /// All map-like event changes can be tracked by using [Event::keys] method.
357    /// All text-like event changes can be tracked by using [TextEvent::delta] method.
358    ///
359    /// Provided key may be used later to unsubscribe from the event.
360    fn observe_with<K, F>(&self, key: K, f: F)
361    where
362        K: Into<Origin>,
363        F: Fn(&TransactionMut, &Self::Event) + 'static,
364        Event: AsRef<Self::Event>,
365    {
366        let mut branch = BranchPtr::from(self.as_ref());
367        branch.observe_with(key.into(), move |txn, e| {
368            let mapped_event = e.as_ref();
369            f(txn, mapped_event)
370        })
371    }
372
373    /// Unsubscribes a given callback identified by key, that was previously subscribed using [Self::observe_with].
374    fn unobserve<K: Into<Origin>>(&self, key: K) -> bool {
375        let mut branch = BranchPtr::from(self.as_ref());
376        branch.unobserve(&key.into())
377    }
378}
379
380/// Trait implemented by shared types to display their contents in string format.
381pub trait GetString {
382    /// Displays the content of a current collection in string format.
383    fn get_string<T: ReadTxn>(&self, txn: &T) -> String;
384}
385
386/// A subset of [SharedRef] used to mark collaborative collections that can be used as a
387/// root level collections. This includes common types like [ArrayRef], [MapRef], [TextRef] and
388/// [XmlFragmentRef].
389///
390/// Some types like [XmlTextRef] and [XmlElementRef] are not bound to be used as root-level types
391/// since they have limited capabilities (i.e. cannot propagate XML node name).
392///
393/// Other types like [WeakRef] are not supposed to be used at root-level since they refer to
394/// elements created prior to them, while root-level types are virtually immortal and technically
395/// exist for the whole lifespan of their document.
396pub trait RootRef: SharedRef {
397    fn type_ref() -> TypeRef;
398
399    /// Create a logical collaborative collection reference to a root-level type with a given `name`
400    fn root<N: Into<Arc<str>>>(name: N) -> Root<Self> {
401        Root::new(name)
402    }
403}
404
405/// Common trait for shared collaborative collection types in Yrs.
406pub trait SharedRef: From<BranchPtr> + AsRef<Branch> {
407    /// Returns a logical descriptor of a current shared collection.
408    fn hook(&self) -> Hook<Self> {
409        let branch = self.as_ref();
410        Hook::from(branch.id())
411    }
412}
413
414/// Trait which allows conversion back to a prelim type that can be used to create a new shared
415/// that's a deep copy equivalent of a current type.
416pub trait AsPrelim {
417    type Prelim: Prelim<Return = Self>;
418
419    /// Converts current type contents into a [Prelim] type that can be used to create a new
420    /// type that's a deep copy equivalent of a current type.
421    fn as_prelim<T: ReadTxn>(&self, txn: &T) -> Self::Prelim;
422}
423
424/// Trait which allows to generate a [Prelim]-compatible type that - when integrated - will be
425/// converted into an instance of a current type.
426pub trait DefaultPrelim {
427    type Prelim: Prelim<Return = Self>;
428
429    /// Returns an instance of [Prelim]-compatible type, which will turn into reference of a current
430    /// type after being integrated into the document store.
431    fn default_prelim() -> Self::Prelim;
432}
433
434/// Trait implemented by all Y-types, allowing for observing events which are emitted by
435/// nested types.
436#[cfg(feature = "sync")]
437pub trait DeepObservable: AsRef<Branch> {
438    /// Subscribe a callback `f` for all events emitted by this and nested collaborative types.
439    /// Callback is accepting transaction which triggered that event and event itself, wrapped
440    /// within an [Event] structure.
441    ///
442    /// In case when a nested shared type (e.g. [MapRef],[ArrayRef],[TextRef]) is being removed,
443    /// all of its contents will be removed first. So the observed value will be empty. For example,
444    /// The value wrapped in the [EntryChange::Removed] of the [Event::Map] will be empty.
445    ///
446    /// This method returns a subscription, which will automatically unsubscribe current callback
447    /// when dropped.
448    fn observe_deep<F>(&self, f: F) -> Subscription
449    where
450        F: Fn(&TransactionMut, &Events) + Send + Sync + 'static,
451    {
452        let branch = self.as_ref();
453        branch.deep_observers.subscribe(Box::new(f))
454    }
455
456    /// Subscribe a callback `f` for all events emitted by this and nested collaborative types.
457    /// Callback is accepting transaction which triggered that event and event itself, wrapped
458    /// within an [Event] structure.
459    ///
460    /// In case when a nested shared type (e.g. [MapRef],[ArrayRef],[TextRef]) is being removed,
461    /// all of its contents will be removed first. So the observed value will be empty. For example,
462    /// The value wrapped in the [EntryChange::Removed] of the [Event::Map] will be empty.
463    ///
464    /// This method uses a subscription key, which can be later used to cancel this callback via
465    /// [Self::unobserve_deep].
466    fn observe_deep_with<K, F>(&self, key: K, f: F)
467    where
468        K: Into<Origin>,
469        F: Fn(&TransactionMut, &Events) + Send + Sync + 'static,
470    {
471        let branch = self.as_ref();
472        branch
473            .deep_observers
474            .subscribe_with(key.into(), Box::new(f))
475    }
476
477    /// Unsubscribe a callback identified by a given key, that was previously subscribed using
478    /// [Self::observe_deep_with].
479    fn unobserve_deep<K: Into<Origin>>(&self, key: K) -> bool {
480        let branch = self.as_ref();
481        branch.deep_observers.unsubscribe(&key.into())
482    }
483}
484
485/// Trait implemented by all Y-types, allowing for observing events which are emitted by
486/// nested types.
487#[cfg(not(feature = "sync"))]
488pub trait DeepObservable: AsRef<Branch> {
489    /// Subscribe a callback `f` for all events emitted by this and nested collaborative types.
490    /// Callback is accepting transaction which triggered that event and event itself, wrapped
491    /// within an [Event] structure.
492    ///
493    /// In case when a nested shared type (e.g. [MapRef],[ArrayRef],[TextRef]) is being removed,
494    /// all of its contents will be removed first. So the observed value will be empty. For example,
495    /// The value wrapped in the [EntryChange::Removed] of the [Event::Map] will be empty.
496    ///
497    /// This method returns a subscription, which will automatically unsubscribe current callback
498    /// when dropped.
499    fn observe_deep<F>(&self, f: F) -> Subscription
500    where
501        F: Fn(&TransactionMut, &Events) + 'static,
502    {
503        let branch = self.as_ref();
504        branch.deep_observers.subscribe(Box::new(f))
505    }
506
507    /// Subscribe a callback `f` for all events emitted by this and nested collaborative types.
508    /// Callback is accepting transaction which triggered that event and event itself, wrapped
509    /// within an [Event] structure.
510    ///
511    /// In case when a nested shared type (e.g. [MapRef],[ArrayRef],[TextRef]) is being removed,
512    /// all of its contents will be removed first. So the observed value will be empty. For example,
513    /// The value wrapped in the [EntryChange::Removed] of the [Event::Map] will be empty.
514    ///
515    /// This method uses a subscription key, which can be later used to cancel this callback via
516    /// [Self::unobserve_deep].
517    fn observe_deep_with<K, F>(&self, key: K, f: F)
518    where
519        K: Into<Origin>,
520        F: Fn(&TransactionMut, &Events) + 'static,
521    {
522        let branch = self.as_ref();
523        branch
524            .deep_observers
525            .subscribe_with(key.into(), Box::new(f))
526    }
527
528    /// Unsubscribe a callback identified by a given key, that was previously subscribed using
529    /// [Self::observe_deep_with].
530    fn unobserve_deep<K: Into<Origin>>(&self, key: K) -> bool {
531        let branch = self.as_ref();
532        branch.deep_observers.unsubscribe(&key.into())
533    }
534}
535
536impl std::fmt::Display for Branch {
537    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
538        match self.type_ref() {
539            TypeRef::Array => {
540                if let Some(ptr) = self.start {
541                    write!(f, "YArray(start: {})", ptr)
542                } else {
543                    write!(f, "YArray")
544                }
545            }
546            TypeRef::Map => {
547                write!(f, "YMap(")?;
548                let mut iter = self.map.iter();
549                if let Some((k, v)) = iter.next() {
550                    write!(f, "'{}': {}", k, v)?;
551                }
552                while let Some((k, v)) = iter.next() {
553                    write!(f, ", '{}': {}", k, v)?;
554                }
555                write!(f, ")")
556            }
557            TypeRef::Text => {
558                if let Some(ptr) = self.start.as_ref() {
559                    write!(f, "YText(start: {})", ptr)
560                } else {
561                    write!(f, "YText")
562                }
563            }
564            TypeRef::XmlFragment => {
565                write!(f, "YXmlFragment")?;
566                if let Some(start) = self.start.as_ref() {
567                    write!(f, "(start: {})", start)?;
568                }
569                Ok(())
570            }
571            TypeRef::XmlElement(name) => {
572                write!(f, "YXmlElement('{}',", name)?;
573                if let Some(start) = self.start.as_ref() {
574                    write!(f, "(start: {})", start)?;
575                }
576                if !self.map.is_empty() {
577                    write!(f, " {{")?;
578                    let mut iter = self.map.iter();
579                    if let Some((k, v)) = iter.next() {
580                        write!(f, "'{}': {}", k, v)?;
581                    }
582                    while let Some((k, v)) = iter.next() {
583                        write!(f, ", '{}': {}", k, v)?;
584                    }
585                    write!(f, "}}")?;
586                }
587                Ok(())
588            }
589            TypeRef::XmlHook => {
590                write!(f, "YXmlHook(")?;
591                let mut iter = self.map.iter();
592                if let Some((k, v)) = iter.next() {
593                    write!(f, "'{}': {}", k, v)?;
594                }
595                while let Some((k, v)) = iter.next() {
596                    write!(f, ", '{}': {}", k, v)?;
597                }
598                write!(f, ")")
599            }
600            TypeRef::XmlText => {
601                if let Some(ptr) = self.start {
602                    write!(f, "YXmlText(start: {})", ptr)
603                } else {
604                    write!(f, "YXmlText")
605                }
606            }
607            TypeRef::SubDoc => {
608                write!(f, "Subdoc")
609            }
610            #[cfg(feature = "weak")]
611            TypeRef::WeakLink(w) => {
612                if w.is_single() {
613                    write!(f, "WeakRef({})", w.quote_start)
614                } else {
615                    write!(f, "WeakRef({}..{})", w.quote_start, w.quote_end)
616                }
617            }
618            TypeRef::Undefined => {
619                write!(f, "UnknownRef")?;
620                if let Some(start) = self.start.as_ref() {
621                    write!(f, "(start: {})", start)?;
622                }
623                if !self.map.is_empty() {
624                    write!(f, " {{")?;
625                    let mut iter = self.map.iter();
626                    if let Some((k, v)) = iter.next() {
627                        write!(f, "'{}': {}", k, v)?;
628                    }
629                    while let Some((k, v)) = iter.next() {
630                        write!(f, ", '{}': {}", k, v)?;
631                    }
632                    write!(f, "}}")?;
633                }
634                Ok(())
635            }
636        }
637    }
638}
639
640#[derive(Debug)]
641pub(crate) struct Entries<'a, B, T> {
642    iter: std::collections::hash_map::Iter<'a, Arc<str>, ItemPtr>,
643    txn: B,
644    _marker: PhantomData<T>,
645}
646
647impl<'a, B, T: ReadTxn> Entries<'a, B, T>
648where
649    B: Borrow<T>,
650    T: ReadTxn,
651{
652    pub fn new(source: &'a HashMap<Arc<str>, ItemPtr>, txn: B) -> Self {
653        Entries {
654            iter: source.iter(),
655            txn,
656            _marker: PhantomData::default(),
657        }
658    }
659}
660
661impl<'a, T: ReadTxn> Entries<'a, &'a T, T>
662where
663    T: Borrow<T> + ReadTxn,
664{
665    pub fn from_ref(source: &'a HashMap<Arc<str>, ItemPtr>, txn: &'a T) -> Self {
666        Entries::new(source, txn)
667    }
668}
669
670impl<'a, B, T> Iterator for Entries<'a, B, T>
671where
672    B: Borrow<T>,
673    T: ReadTxn,
674{
675    type Item = (&'a str, &'a Item);
676
677    fn next(&mut self) -> Option<Self::Item> {
678        let (mut key, mut ptr) = self.iter.next()?;
679        while ptr.is_deleted() {
680            (key, ptr) = self.iter.next()?;
681        }
682        Some((key, ptr))
683    }
684}
685
686/// Type pointer - used to localize a complex [Branch] node within a scope of a document store.
687#[derive(Debug, Clone, PartialEq, Eq, Hash)]
688pub(crate) enum TypePtr {
689    /// Temporary value - used only when block is deserialized right away, but had not been
690    /// integrated into block store yet. As part of block integration process, items are
691    /// repaired and their fields (including parent) are being rewired.
692    Unknown,
693
694    /// Pointer to another block. Used in nested data types ie. YMap containing another YMap.
695    Branch(BranchPtr),
696
697    /// Temporary state representing top-level type.
698    Named(Arc<str>),
699
700    /// Temporary state representing nested-level type.
701    ID(ID),
702}
703
704impl TypePtr {
705    pub(crate) fn as_branch(&self) -> Option<&BranchPtr> {
706        if let TypePtr::Branch(ptr) = self {
707            Some(ptr)
708        } else {
709            None
710        }
711    }
712}
713
714impl std::fmt::Display for TypePtr {
715    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
716        match self {
717            TypePtr::Unknown => write!(f, "unknown"),
718            TypePtr::Branch(ptr) => {
719                if let Some(i) = ptr.item {
720                    write!(f, "{}", i.id())
721                } else {
722                    write!(f, "null")
723                }
724            }
725            TypePtr::ID(id) => write!(f, "{}", id),
726            TypePtr::Named(name) => write!(f, "{}", name),
727        }
728    }
729}
730
731/// A path describing nesting structure between shared collections containing each other. It's a
732/// collection of segments which refer to either index (in case of [Array] or [XmlElement]) or
733/// string key (in case of [Map]) where successor shared collection can be found within subsequent
734/// parent types.
735pub type Path = VecDeque<PathSegment>;
736
737/// A single segment of a [Path].
738#[derive(Debug, Clone, PartialEq)]
739pub enum PathSegment {
740    /// Key segments are used to inform how to access child shared collections within a [Map] types.
741    Key(Arc<str>),
742
743    /// Index segments are used to inform how to access child shared collections within an [Array]
744    /// or [XmlElement] types.
745    Index(u32),
746}
747
748impl Serialize for PathSegment {
749    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
750    where
751        S: Serializer,
752    {
753        match self {
754            PathSegment::Key(key) => serializer.serialize_str(&*key),
755            PathSegment::Index(i) => serializer.serialize_u32(*i),
756        }
757    }
758}
759
760pub(crate) struct ChangeSet<D> {
761    added: HashSet<ID>,
762    deleted: HashSet<ID>,
763    delta: Vec<D>,
764}
765
766impl<D> ChangeSet<D> {
767    pub fn new(added: HashSet<ID>, deleted: HashSet<ID>, delta: Vec<D>) -> Self {
768        ChangeSet {
769            added,
770            deleted,
771            delta,
772        }
773    }
774}
775
776/// A single change done over an array-component of shared data type.
777#[derive(Debug, Clone, PartialEq)]
778pub enum Change {
779    /// Determines a change that resulted in adding a consecutive number of new elements:
780    /// - For [Array] it's a range of inserted elements.
781    /// - For [XmlElement] it's a range of inserted child XML nodes.
782    Added(Vec<Out>),
783
784    /// Determines a change that resulted in removing a consecutive range of existing elements,
785    /// either XML child nodes for [XmlElement] or various elements stored in an [Array].
786    Removed(u32),
787
788    /// Determines a number of consecutive unchanged elements. Used to recognize non-edited spaces
789    /// between [Change::Added] and/or [Change::Removed] chunks.
790    Retain(u32),
791}
792
793/// A single change done over a map-component of shared data type.
794#[derive(Clone, PartialEq)]
795pub enum EntryChange {
796    /// Informs about a new value inserted under specified entry.
797    Inserted(Out),
798
799    /// Informs about a change of old value (1st field) to a new one (2nd field) under
800    /// a corresponding entry.
801    Updated(Out, Out),
802
803    /// Informs about a removal of a corresponding entry - contains a removed value.
804    Removed(Out),
805}
806
807impl std::fmt::Debug for EntryChange {
808    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
809        match self {
810            EntryChange::Inserted(out) => write!(f, "Inserted({out:?})"),
811            EntryChange::Updated(old, new) => write!(f, "Updated({old:?}, {new:?})"),
812            EntryChange::Removed(out) => {
813                f.write_str("Removed(")?;
814                // To avoid panicking on removed references, output the type name rather than the reference.
815                match out {
816                    Out::Any(any) => write!(f, "{any:?}")?,
817                    Out::YText(_) => write!(f, "YText")?,
818                    Out::YArray(_) => write!(f, "YArray")?,
819                    Out::YMap(_) => write!(f, "YMap")?,
820                    Out::YXmlElement(_) => write!(f, "YXmlElement")?,
821                    Out::YXmlFragment(_) => write!(f, "YXmlFragment")?,
822                    Out::YXmlText(_) => write!(f, "YXmlText")?,
823                    Out::YDoc(_) => write!(f, "YDoc")?,
824                    #[cfg(feature = "weak")]
825                    Out::YWeakLink(_) => write!(f, "YWeakLink")?,
826                    Out::UndefinedRef(_) => write!(f, "UndefinedRef")?,
827                }
828                f.write_str(")")
829            }
830        }
831    }
832}
833
834/// A single change done over a text-like types: [Text] or [XmlText].
835#[derive(Debug, Clone, PartialEq)]
836pub enum Delta<T = Out> {
837    /// Determines a change that resulted in insertion of a piece of text, which optionally could
838    /// have been formatted with provided set of attributes.
839    Inserted(T, Option<Box<Attrs>>),
840
841    /// Determines a change that resulted in removing a consecutive range of characters.
842    Deleted(u32),
843
844    /// Determines a number of consecutive unchanged characters. Used to recognize non-edited spaces
845    /// between [Delta::Inserted] and/or [Delta::Deleted] chunks. Can contain an optional set of
846    /// attributes, which have been used to format an existing piece of text.
847    Retain(u32, Option<Box<Attrs>>),
848}
849
850impl<T> Delta<T> {
851    pub fn map<U, F>(self, f: F) -> Delta<U>
852    where
853        F: FnOnce(T) -> U,
854    {
855        match self {
856            Delta::Inserted(value, attrs) => Delta::Inserted(f(value), attrs),
857            Delta::Deleted(len) => Delta::Deleted(len),
858            Delta::Retain(len, attrs) => Delta::Retain(len, attrs),
859        }
860    }
861}
862
863impl Delta<In> {
864    pub fn retain(len: u32) -> Self {
865        Delta::Retain(len, None)
866    }
867
868    pub fn insert<T: Into<In>>(value: T) -> Self {
869        Delta::Inserted(value.into(), None)
870    }
871
872    pub fn insert_with<T: Into<In>>(value: T, attrs: Attrs) -> Self {
873        Delta::Inserted(value.into(), Some(Box::new(attrs)))
874    }
875
876    pub fn delete(len: u32) -> Self {
877        Delta::Deleted(len)
878    }
879}
880
881/// An alias for map of attributes used as formatting parameters by [Text] and [XmlText] types.
882pub type Attrs = HashMap<Arc<str>, Any>;
883
884pub(crate) fn event_keys(
885    txn: &TransactionMut,
886    target: BranchPtr,
887    keys_changed: &HashSet<Option<Arc<str>>>,
888) -> HashMap<Arc<str>, EntryChange> {
889    let mut keys = HashMap::new();
890    for opt in keys_changed.iter() {
891        if let Some(key) = opt {
892            let block = target.map.get(key.as_ref()).cloned();
893            if let Some(item) = block.as_deref() {
894                if item.id.clock >= txn.before_state.get(&item.id.client) {
895                    let mut prev = item.left;
896                    while let Some(p) = prev.as_deref() {
897                        if !txn.has_added(&p.id) {
898                            break;
899                        }
900                        prev = p.left;
901                    }
902
903                    if txn.has_deleted(&item.id) {
904                        if let Some(prev) = prev.as_deref() {
905                            if txn.has_deleted(&prev.id) {
906                                let old_value = prev.content.get_last().unwrap_or_default();
907                                keys.insert(key.clone(), EntryChange::Removed(old_value));
908                            }
909                        }
910                    } else {
911                        let new_value = item.content.get_last().unwrap();
912                        if let Some(prev) = prev.as_deref() {
913                            if txn.has_deleted(&prev.id) {
914                                let old_value = prev.content.get_last().unwrap_or_default();
915                                keys.insert(
916                                    key.clone(),
917                                    EntryChange::Updated(old_value, new_value),
918                                );
919
920                                continue;
921                            }
922                        }
923
924                        keys.insert(key.clone(), EntryChange::Inserted(new_value));
925                    }
926                } else if txn.has_deleted(&item.id) {
927                    let old_value = item.content.get_last().unwrap_or_default();
928                    keys.insert(key.clone(), EntryChange::Removed(old_value));
929                }
930            }
931        }
932    }
933
934    keys
935}
936
937pub(crate) fn event_change_set(txn: &TransactionMut, start: Option<ItemPtr>) -> ChangeSet<Change> {
938    let mut added = HashSet::new();
939    let mut deleted = HashSet::new();
940    let mut delta = Vec::new();
941
942    let mut moved_stack = Vec::new();
943    let mut curr_move: Option<ItemPtr> = None;
944    let mut curr_move_is_new = false;
945    let mut curr_move_is_deleted = false;
946    let mut curr_move_end: Option<ItemPtr> = None;
947    let mut last_op = None;
948
949    #[derive(Default)]
950    struct MoveStackItem {
951        end: Option<ItemPtr>,
952        moved: Option<ItemPtr>,
953        is_new: bool,
954        is_deleted: bool,
955    }
956
957    fn is_moved_by_new(ptr: Option<ItemPtr>, txn: &TransactionMut) -> bool {
958        let mut moved = ptr;
959        while let Some(item) = moved.as_deref() {
960            if txn.has_added(&item.id) {
961                return true;
962            } else {
963                moved = item.moved;
964            }
965        }
966
967        false
968    }
969
970    let encoding = txn.store().offset_kind;
971    let mut current = start;
972    loop {
973        if current == curr_move_end && curr_move.is_some() {
974            current = curr_move;
975            let item: MoveStackItem = moved_stack.pop().unwrap_or_default();
976            curr_move_is_new = item.is_new;
977            curr_move_is_deleted = item.is_deleted;
978            curr_move = item.moved;
979            curr_move_end = item.end;
980        } else {
981            if let Some(item) = current {
982                if let ItemContent::Move(m) = &item.content {
983                    if item.moved == curr_move {
984                        moved_stack.push(MoveStackItem {
985                            end: curr_move_end,
986                            moved: curr_move,
987                            is_new: curr_move_is_new,
988                            is_deleted: curr_move_is_deleted,
989                        });
990                        let txn = unsafe {
991                            //TODO: remove this - find a way to work with get_moved_coords
992                            // without need for &mut Transaction
993                            (txn as *const TransactionMut as *mut TransactionMut)
994                                .as_mut()
995                                .unwrap()
996                        };
997                        let (start, end) = m.get_moved_coords(txn);
998                        curr_move = current;
999                        curr_move_end = end;
1000                        curr_move_is_new = curr_move_is_new || txn.has_added(&item.id);
1001                        curr_move_is_deleted = curr_move_is_deleted || item.is_deleted();
1002                        current = start;
1003                        continue; // do not move to item.right
1004                    }
1005                } else if item.moved != curr_move {
1006                    if !curr_move_is_new
1007                        && item.is_countable()
1008                        && (!item.is_deleted() || txn.has_deleted(&item.id))
1009                        && !txn.has_added(&item.id)
1010                        && (item.moved.is_none()
1011                            || curr_move_is_deleted
1012                            || is_moved_by_new(item.moved, txn))
1013                        && (txn.prev_moved.get(&item).cloned() == curr_move)
1014                    {
1015                        match item.moved {
1016                            Some(ptr) if txn.has_added(ptr.id()) => {
1017                                let len = item.content_len(encoding);
1018                                last_op = match last_op.take() {
1019                                    Some(Change::Removed(i)) => Some(Change::Removed(i + len)),
1020                                    Some(op) => {
1021                                        delta.push(op);
1022                                        Some(Change::Removed(len))
1023                                    }
1024                                    None => Some(Change::Removed(len)),
1025                                };
1026                            }
1027                            _ => {}
1028                        }
1029                    }
1030                } else if item.is_deleted() {
1031                    if !curr_move_is_new
1032                        && txn.has_deleted(&item.id)
1033                        && !txn.has_added(&item.id)
1034                        && !txn.prev_moved.contains_key(&item)
1035                    {
1036                        let removed = match last_op.take() {
1037                            None => 0,
1038                            Some(Change::Removed(c)) => c,
1039                            Some(other) => {
1040                                delta.push(other);
1041                                0
1042                            }
1043                        };
1044                        last_op = Some(Change::Removed(removed + item.len()));
1045                        deleted.insert(item.id);
1046                    } // else nop
1047                } else {
1048                    if curr_move_is_new
1049                        || txn.has_added(&item.id)
1050                        || txn.prev_moved.contains_key(&item)
1051                    {
1052                        let mut inserts = match last_op.take() {
1053                            None => Vec::with_capacity(item.len() as usize),
1054                            Some(Change::Added(values)) => values,
1055                            Some(other) => {
1056                                delta.push(other);
1057                                Vec::with_capacity(item.len() as usize)
1058                            }
1059                        };
1060                        inserts.append(&mut item.content.get_content());
1061                        last_op = Some(Change::Added(inserts));
1062                        added.insert(item.id);
1063                    } else {
1064                        let retain = match last_op.take() {
1065                            None => 0,
1066                            Some(Change::Retain(c)) => c,
1067                            Some(other) => {
1068                                delta.push(other);
1069                                0
1070                            }
1071                        };
1072                        last_op = Some(Change::Retain(retain + item.len()));
1073                    }
1074                }
1075            } else {
1076                break;
1077            }
1078        }
1079
1080        current = if let Some(i) = current.as_deref() {
1081            i.right
1082        } else {
1083            None
1084        };
1085    }
1086
1087    match last_op.take() {
1088        None | Some(Change::Retain(_)) => { /* do nothing */ }
1089        Some(change) => delta.push(change),
1090    }
1091
1092    ChangeSet::new(added, deleted, delta)
1093}
1094
1095pub struct Events<'a>(Vec<&'a Event>);
1096
1097impl<'a> Events<'a> {
1098    pub(crate) fn new(events: &Vec<&'a Event>) -> Self {
1099        let mut events = events.clone();
1100        events.sort_by(|&a, &b| {
1101            let path1 = a.path();
1102            let path2 = b.path();
1103            path1.len().cmp(&path2.len())
1104        });
1105        Events(events)
1106    }
1107
1108    pub fn iter(&self) -> EventsIter {
1109        EventsIter(self.0.iter())
1110    }
1111}
1112
1113pub struct EventsIter<'a>(std::slice::Iter<'a, &'a Event>);
1114
1115impl<'a> Iterator for EventsIter<'a> {
1116    type Item = &'a Event;
1117
1118    fn next(&mut self) -> Option<Self::Item> {
1119        let e = self.0.next()?;
1120        Some(e)
1121    }
1122
1123    fn size_hint(&self) -> (usize, Option<usize>) {
1124        self.0.size_hint()
1125    }
1126}
1127
1128impl<'a> ExactSizeIterator for EventsIter<'a> {
1129    fn len(&self) -> usize {
1130        self.0.len()
1131    }
1132}
1133
1134/// Generalized wrapper around events fired by specialized shared data types.
1135pub enum Event {
1136    Text(TextEvent),
1137    Array(ArrayEvent),
1138    Map(MapEvent),
1139    XmlFragment(XmlEvent),
1140    XmlText(XmlTextEvent),
1141    #[cfg(feature = "weak")]
1142    Weak(WeakEvent),
1143}
1144
1145impl AsRef<TextEvent> for Event {
1146    fn as_ref(&self) -> &TextEvent {
1147        if let Event::Text(e) = self {
1148            e
1149        } else {
1150            panic!("subscribed callback expected TextRef collection");
1151        }
1152    }
1153}
1154
1155impl AsRef<ArrayEvent> for Event {
1156    fn as_ref(&self) -> &ArrayEvent {
1157        if let Event::Array(e) = self {
1158            e
1159        } else {
1160            panic!("subscribed callback expected ArrayRef collection");
1161        }
1162    }
1163}
1164
1165impl AsRef<MapEvent> for Event {
1166    fn as_ref(&self) -> &MapEvent {
1167        if let Event::Map(e) = self {
1168            e
1169        } else {
1170            panic!("subscribed callback expected MapRef collection");
1171        }
1172    }
1173}
1174
1175impl AsRef<XmlTextEvent> for Event {
1176    fn as_ref(&self) -> &XmlTextEvent {
1177        if let Event::XmlText(e) = self {
1178            e
1179        } else {
1180            panic!("subscribed callback expected XmlTextRef collection");
1181        }
1182    }
1183}
1184
1185impl AsRef<XmlEvent> for Event {
1186    fn as_ref(&self) -> &XmlEvent {
1187        if let Event::XmlFragment(e) = self {
1188            e
1189        } else {
1190            panic!("subscribed callback expected Xml node");
1191        }
1192    }
1193}
1194
1195#[cfg(feature = "weak")]
1196impl AsRef<WeakEvent> for Event {
1197    fn as_ref(&self) -> &WeakEvent {
1198        if let Event::Weak(e) = self {
1199            e
1200        } else {
1201            panic!("subscribed callback expected WeakRef reference");
1202        }
1203    }
1204}
1205
1206impl Event {
1207    pub(crate) fn set_current_target(&mut self, target: BranchPtr) {
1208        match self {
1209            Event::Text(e) => e.current_target = target,
1210            Event::Array(e) => e.current_target = target,
1211            Event::Map(e) => e.current_target = target,
1212            Event::XmlText(e) => e.current_target = target,
1213            Event::XmlFragment(e) => e.current_target = target,
1214            #[cfg(feature = "weak")]
1215            Event::Weak(e) => e.current_target = target,
1216        }
1217    }
1218
1219    /// Returns a path from root type to a shared type which triggered current [Event]. This path
1220    /// consists of string names or indexes, which can be used to access nested type.
1221    pub fn path(&self) -> Path {
1222        match self {
1223            Event::Text(e) => e.path(),
1224            Event::Array(e) => e.path(),
1225            Event::Map(e) => e.path(),
1226            Event::XmlText(e) => e.path(),
1227            Event::XmlFragment(e) => e.path(),
1228            #[cfg(feature = "weak")]
1229            Event::Weak(e) => e.path(),
1230        }
1231    }
1232
1233    /// Returns a shared data types which triggered current [Event].
1234    pub fn target(&self) -> Out {
1235        match self {
1236            Event::Text(e) => Out::YText(e.target().clone()),
1237            Event::Array(e) => Out::YArray(e.target().clone()),
1238            Event::Map(e) => Out::YMap(e.target().clone()),
1239            Event::XmlText(e) => Out::YXmlText(e.target().clone()),
1240            Event::XmlFragment(e) => match e.target() {
1241                XmlOut::Element(n) => Out::YXmlElement(n.clone()),
1242                XmlOut::Fragment(n) => Out::YXmlFragment(n.clone()),
1243                XmlOut::Text(n) => Out::YXmlText(n.clone()),
1244            },
1245            #[cfg(feature = "weak")]
1246            Event::Weak(e) => Out::YWeakLink(e.as_target().clone()),
1247        }
1248    }
1249}
1250
1251pub trait ToJson {
1252    /// Converts all contents of a current type into a JSON-like representation.
1253    fn to_json<T: ReadTxn>(&self, txn: &T) -> Any;
1254}