yrs/types/
xml.rs

1use std::borrow::Borrow;
2use std::cell::UnsafeCell;
3use std::collections::{HashMap, HashSet};
4use std::convert::{TryFrom, TryInto};
5use std::fmt::Write;
6use std::marker::PhantomData;
7use std::ops::{Deref, DerefMut};
8use std::sync::Arc;
9
10use crate::block::{EmbedPrelim, Item, ItemContent, ItemPosition, ItemPtr, Prelim};
11use crate::block_iter::BlockIter;
12use crate::transaction::TransactionMut;
13use crate::types::text::{diff_between, TextEvent, YChange};
14use crate::types::{
15    event_change_set, event_keys, AsPrelim, Branch, BranchPtr, Change, ChangeSet, DefaultPrelim,
16    Delta, Entries, EntryChange, MapRef, Out, Path, RootRef, SharedRef, ToJson, TypePtr, TypeRef,
17};
18use crate::{
19    Any, ArrayRef, BranchID, DeepObservable, GetString, In, IndexedSequence, Map, Observable,
20    ReadTxn, StickyIndex, Text, TextRef, ID,
21};
22
23pub trait XmlPrelim: Prelim {}
24
25/// Trait shared by preliminary types that can be used as XML nodes: [XmlElementPrelim],
26/// [XmlFragmentPrelim] and [XmlTextPrelim].
27#[derive(Debug, Clone, PartialEq)]
28pub enum XmlIn {
29    Text(XmlDeltaPrelim),
30    Element(XmlElementPrelim),
31    Fragment(XmlFragmentPrelim),
32}
33
34impl From<XmlDeltaPrelim> for XmlIn {
35    #[inline]
36    fn from(value: XmlDeltaPrelim) -> Self {
37        Self::Text(value)
38    }
39}
40
41impl From<XmlTextPrelim> for XmlIn {
42    #[inline]
43    fn from(value: XmlTextPrelim) -> Self {
44        Self::Text(value.into())
45    }
46}
47
48impl From<XmlElementPrelim> for XmlIn {
49    #[inline]
50    fn from(value: XmlElementPrelim) -> Self {
51        Self::Element(value)
52    }
53}
54
55impl From<XmlFragmentPrelim> for XmlIn {
56    #[inline]
57    fn from(value: XmlFragmentPrelim) -> Self {
58        Self::Fragment(value)
59    }
60}
61
62impl XmlPrelim for XmlIn {}
63
64impl Prelim for XmlIn {
65    type Return = XmlOut;
66
67    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
68        let type_ref = match &self {
69            XmlIn::Text(_) => TypeRef::XmlText,
70            XmlIn::Element(prelim) => TypeRef::XmlElement(prelim.tag.clone()),
71            XmlIn::Fragment(_) => TypeRef::XmlFragment,
72        };
73        (ItemContent::Type(Branch::new(type_ref)), Some(self))
74    }
75
76    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
77        match self {
78            XmlIn::Text(prelim) => prelim.integrate(txn, inner_ref),
79            XmlIn::Element(prelim) => prelim.integrate(txn, inner_ref),
80            XmlIn::Fragment(prelim) => prelim.integrate(txn, inner_ref),
81        }
82    }
83}
84
85/// A return type from XML elements retrieval methods. It's an enum of all supported values, that
86/// can be nested inside [XmlElementRef]. These are other [XmlElementRef]s, [XmlFragmentRef]s
87/// or [XmlTextRef] values.
88#[derive(Debug, Clone)]
89pub enum XmlOut {
90    Element(XmlElementRef),
91    Fragment(XmlFragmentRef),
92    Text(XmlTextRef),
93}
94
95impl XmlOut {
96    pub fn as_ptr(&self) -> BranchPtr {
97        match self {
98            XmlOut::Element(n) => n.0,
99            XmlOut::Fragment(n) => n.0,
100            XmlOut::Text(n) => n.0,
101        }
102    }
103
104    pub fn id(&self) -> BranchID {
105        self.as_ptr().id()
106    }
107
108    /// If current underlying [XmlOut] is wrapping a [XmlElementRef], it will be returned.
109    /// Otherwise, a `None` will be returned.
110    pub fn into_xml_element(self) -> Option<XmlElementRef> {
111        match self {
112            XmlOut::Element(n) => Some(n),
113            _ => None,
114        }
115    }
116
117    /// If current underlying [XmlOut] is wrapping a [XmlFragmentRef], it will be returned.
118    /// Otherwise, a `None` will be returned.
119    pub fn into_xml_fragment(self) -> Option<XmlFragmentRef> {
120        match self {
121            XmlOut::Fragment(n) => Some(n),
122            _ => None,
123        }
124    }
125
126    /// If current underlying [XmlOut] is wrapping a [XmlTextRef], it will be returned.
127    /// Otherwise, a `None` will be returned.
128    pub fn into_xml_text(self) -> Option<XmlTextRef> {
129        match self {
130            XmlOut::Text(n) => Some(n),
131            _ => None,
132        }
133    }
134}
135
136impl AsRef<Branch> for XmlOut {
137    fn as_ref(&self) -> &Branch {
138        match self {
139            XmlOut::Element(n) => n.as_ref(),
140            XmlOut::Fragment(n) => n.as_ref(),
141            XmlOut::Text(n) => n.as_ref(),
142        }
143    }
144}
145
146impl TryInto<XmlElementRef> for XmlOut {
147    type Error = XmlOut;
148
149    fn try_into(self) -> Result<XmlElementRef, Self::Error> {
150        match self {
151            XmlOut::Element(xml) => Ok(xml),
152            other => Err(other),
153        }
154    }
155}
156
157impl TryInto<XmlTextRef> for XmlOut {
158    type Error = XmlOut;
159
160    fn try_into(self) -> Result<XmlTextRef, Self::Error> {
161        match self {
162            XmlOut::Text(xml) => Ok(xml),
163            other => Err(other),
164        }
165    }
166}
167
168impl TryInto<XmlFragmentRef> for XmlOut {
169    type Error = XmlOut;
170
171    fn try_into(self) -> Result<XmlFragmentRef, Self::Error> {
172        match self {
173            XmlOut::Fragment(xml) => Ok(xml),
174            other => Err(other),
175        }
176    }
177}
178
179impl TryFrom<BranchPtr> for XmlOut {
180    type Error = BranchPtr;
181
182    fn try_from(value: BranchPtr) -> Result<Self, Self::Error> {
183        match value.type_ref {
184            TypeRef::XmlElement(_) => Ok(XmlOut::Element(XmlElementRef::from(value))),
185            TypeRef::XmlFragment => Ok(XmlOut::Fragment(XmlFragmentRef::from(value))),
186            TypeRef::XmlText => Ok(XmlOut::Text(XmlTextRef::from(value))),
187            _ => Err(value),
188        }
189    }
190}
191
192impl TryFrom<Out> for XmlOut {
193    type Error = Out;
194
195    fn try_from(value: Out) -> Result<Self, Self::Error> {
196        match value {
197            Out::YXmlElement(n) => Ok(XmlOut::Element(n)),
198            Out::YXmlFragment(n) => Ok(XmlOut::Fragment(n)),
199            Out::YXmlText(n) => Ok(XmlOut::Text(n)),
200            other => Err(other),
201        }
202    }
203}
204
205impl From<XmlOut> for Out {
206    fn from(value: XmlOut) -> Self {
207        match value {
208            XmlOut::Element(xml) => Out::YXmlElement(xml),
209            XmlOut::Fragment(xml) => Out::YXmlFragment(xml),
210            XmlOut::Text(xml) => Out::YXmlText(xml),
211        }
212    }
213}
214
215impl TryFrom<ItemPtr> for XmlOut {
216    type Error = ItemPtr;
217
218    fn try_from(value: ItemPtr) -> Result<Self, Self::Error> {
219        if let Some(branch) = value.clone().as_branch() {
220            match branch.type_ref {
221                TypeRef::XmlElement(_) => Ok(XmlOut::Element(XmlElementRef::from(branch))),
222                TypeRef::XmlFragment => Ok(XmlOut::Fragment(XmlFragmentRef::from(branch))),
223                TypeRef::XmlText => Ok(XmlOut::Text(XmlTextRef::from(branch))),
224                _ => return Err(value),
225            }
226        } else {
227            Err(value)
228        }
229    }
230}
231
232/// XML element data type. It represents an XML node, which can contain key-value attributes
233/// (interpreted as strings) as well as other nested XML elements or rich text (represented by
234/// [XmlTextRef] type).
235///
236/// In terms of conflict resolution, [XmlElementRef] uses following rules:
237///
238/// - Attribute updates use logical last-write-wins principle, meaning the past updates are
239///   automatically overridden and discarded by newer ones, while concurrent updates made by
240///   different peers are resolved into a single value using document id seniority to establish
241///   an order.
242/// - Child node insertion uses sequencing rules from other Yrs collections - elements are inserted
243///   using interleave-resistant algorithm, where order of concurrent inserts at the same index
244///   is established using peer's document id seniority.
245#[repr(transparent)]
246#[derive(Debug, Clone)]
247pub struct XmlElementRef(BranchPtr);
248
249impl SharedRef for XmlElementRef {}
250impl Xml for XmlElementRef {}
251impl XmlFragment for XmlElementRef {}
252impl IndexedSequence for XmlElementRef {}
253
254impl AsRef<XmlFragmentRef> for XmlElementRef {
255    #[inline]
256    fn as_ref(&self) -> &XmlFragmentRef {
257        unsafe { std::mem::transmute(self) }
258    }
259}
260
261impl AsRef<ArrayRef> for XmlElementRef {
262    #[inline]
263    fn as_ref(&self) -> &ArrayRef {
264        unsafe { std::mem::transmute(self) }
265    }
266}
267
268impl XmlElementRef {
269    /// A tag name of a current top-level XML node, eg. node `<p></p>` has "p" as it's tag name.
270    pub fn try_tag(&self) -> Option<&Arc<str>> {
271        if let TypeRef::XmlElement(tag) = &self.0.type_ref {
272            Some(tag)
273        } else {
274            // this could happen only if we reinterpret top level type as XmlElementRef
275            None
276        }
277    }
278
279    /// A tag name of a current top-level XML node, eg. node `<p></p>` has "p" as it's tag name.
280    pub fn tag(&self) -> &Arc<str> {
281        self.try_tag().expect("XmlElement tag was not defined")
282    }
283}
284
285impl GetString for XmlElementRef {
286    /// Converts current XML node into a textual representation. This representation if flat, it
287    /// doesn't include any indentation.
288    fn get_string<T: ReadTxn>(&self, txn: &T) -> String {
289        let tag: &str = self.tag();
290        let inner = self.0;
291        let mut s = String::new();
292        write!(&mut s, "<{}", tag).unwrap();
293        let attributes = Attributes(inner.entries(txn));
294        for (k, v) in attributes {
295            write!(&mut s, " {}=\"{}\"", k, v).unwrap();
296        }
297        write!(&mut s, ">").unwrap();
298        for i in inner.iter(txn) {
299            if !i.is_deleted() {
300                for content in i.content.get_content() {
301                    write!(&mut s, "{}", content.to_string(txn)).unwrap();
302                }
303            }
304        }
305        write!(&mut s, "</{}>", tag).unwrap();
306        s
307    }
308}
309
310impl DeepObservable for XmlElementRef {}
311impl Observable for XmlElementRef {
312    type Event = XmlEvent;
313}
314
315impl AsRef<Branch> for XmlElementRef {
316    fn as_ref(&self) -> &Branch {
317        &self.0
318    }
319}
320
321impl Eq for XmlElementRef {}
322impl PartialEq for XmlElementRef {
323    fn eq(&self, other: &Self) -> bool {
324        self.0.id() == other.0.id()
325    }
326}
327
328impl From<BranchPtr> for XmlElementRef {
329    fn from(inner: BranchPtr) -> Self {
330        XmlElementRef(inner)
331    }
332}
333
334impl TryFrom<ItemPtr> for XmlElementRef {
335    type Error = ItemPtr;
336
337    fn try_from(value: ItemPtr) -> Result<Self, Self::Error> {
338        if let Some(branch) = value.clone().as_branch() {
339            Ok(Self::from(branch))
340        } else {
341            Err(value)
342        }
343    }
344}
345
346impl TryFrom<Out> for XmlElementRef {
347    type Error = Out;
348
349    fn try_from(value: Out) -> Result<Self, Self::Error> {
350        match value {
351            Out::YXmlElement(value) => Ok(value),
352            other => Err(other),
353        }
354    }
355}
356
357impl AsPrelim for XmlElementRef {
358    type Prelim = XmlElementPrelim;
359
360    fn as_prelim<T: ReadTxn>(&self, txn: &T) -> Self::Prelim {
361        let attributes: HashMap<Arc<str>, String> = self
362            .0
363            .map
364            .iter()
365            .flat_map(|(k, ptr)| {
366                if ptr.is_deleted() {
367                    None
368                } else if let Some(value) = ptr.content.get_last() {
369                    Some((k.clone(), value.to_string(txn)))
370                } else {
371                    None
372                }
373            })
374            .collect();
375        let children: Vec<_> = self
376            .children(txn)
377            .map(|v| match v {
378                XmlOut::Element(v) => XmlIn::Element(v.as_prelim(txn)),
379                XmlOut::Fragment(v) => XmlIn::Fragment(v.as_prelim(txn)),
380                XmlOut::Text(v) => XmlIn::Text(v.as_prelim(txn)),
381            })
382            .collect();
383        XmlElementPrelim {
384            tag: self.tag().clone(),
385            attributes,
386            children,
387        }
388    }
389}
390
391/// A preliminary type that will be materialized into an [XmlElementRef] once it will be integrated
392/// into Yrs document.
393#[derive(Debug, Clone, PartialEq)]
394pub struct XmlElementPrelim {
395    pub tag: Arc<str>,
396    pub attributes: HashMap<Arc<str>, String>,
397    pub children: Vec<XmlIn>,
398}
399
400impl XmlElementPrelim {
401    pub fn new<S, I>(tag: S, iter: I) -> Self
402    where
403        S: Into<Arc<str>>,
404        I: IntoIterator<Item = XmlIn>,
405    {
406        XmlElementPrelim {
407            tag: tag.into(),
408            attributes: HashMap::default(),
409            children: iter.into_iter().collect(),
410        }
411    }
412
413    pub fn empty<S>(tag: S) -> Self
414    where
415        S: Into<Arc<str>>,
416    {
417        XmlElementPrelim {
418            tag: tag.into(),
419            attributes: HashMap::default(),
420            children: Vec::default(),
421        }
422    }
423}
424
425impl XmlPrelim for XmlElementPrelim {}
426
427impl Prelim for XmlElementPrelim {
428    type Return = XmlElementRef;
429
430    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
431        let inner = Branch::new(TypeRef::XmlElement(self.tag.clone()));
432        (ItemContent::Type(inner), Some(self))
433    }
434
435    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
436        let xml = XmlElementRef::from(inner_ref);
437        for (key, value) in self.attributes {
438            xml.insert_attribute(txn, key, value);
439        }
440        for value in self.children {
441            xml.push_back(txn, value);
442        }
443    }
444}
445
446impl Into<EmbedPrelim<XmlElementPrelim>> for XmlElementPrelim {
447    #[inline]
448    fn into(self) -> EmbedPrelim<XmlElementPrelim> {
449        EmbedPrelim::Shared(self)
450    }
451}
452
453impl From<XmlElementPrelim> for In {
454    #[inline]
455    fn from(value: XmlElementPrelim) -> Self {
456        In::XmlElement(value)
457    }
458}
459
460/// A shared data type used for collaborative text editing, that can be used in a context of
461/// [XmlElementRef] node. It enables multiple users to add and remove chunks of text in efficient
462/// manner. This type is internally represented as a mutable double-linked list of text chunks
463/// - an optimization occurs during [Transaction::commit], which allows to squash multiple
464/// consecutively inserted characters together as a single chunk of text even between transaction
465/// boundaries in order to preserve more efficient memory model.
466///
467/// Just like [XmlElementRef], [XmlTextRef] can be marked with extra metadata in form of attributes.
468///
469/// [XmlTextRef] structure internally uses UTF-8 encoding and its length is described in a number of
470/// bytes rather than individual characters (a single UTF-8 code point can consist of many bytes).
471///
472/// Like all Yrs shared data types, [XmlTextRef] is resistant to the problem of interleaving (situation
473/// when characters inserted one after another may interleave with other peers concurrent inserts
474/// after merging all updates together). In case of Yrs conflict resolution is solved by using
475/// unique document id to determine correct and consistent ordering.
476///
477/// [XmlTextRef] offers a rich text editing capabilities (it's not limited to simple text operations).
478/// Actions like embedding objects, binaries (eg. images) and formatting attributes are all possible
479/// using [XmlTextRef].
480///
481/// Keep in mind that [XmlTextRef::get_string] method returns a raw string, while rendering
482/// formatting attrbitues as XML tags in-text. However it doesn't include embedded elements.
483/// If there's a need to include them, use [XmlTextRef::diff] method instead.
484///
485/// Another note worth reminding is that human-readable numeric indexes are not good for maintaining
486/// cursor positions in rich text documents with real-time collaborative capabilities. In such cases
487/// any concurrent update incoming and applied from the remote peer may change the order of elements
488/// in current [XmlTextRef], invalidating numeric index. For such cases you can take advantage of fact
489/// that [XmlTextRef] implements [IndexedSequence::sticky_index] method that returns a
490/// [permanent index](crate::StickyIndex) position that sticks to the same place even when concurrent
491/// updates are being made.
492///
493/// # Example
494///
495/// ```rust
496/// use yrs::{Any, Array, ArrayPrelim, Doc, GetString, Text, Transact, WriteTxn, XmlFragment, XmlTextPrelim};
497/// use yrs::types::Attrs;
498///
499/// let doc = Doc::new();
500/// let mut txn = doc.transact_mut();
501/// let f = txn.get_or_insert_xml_fragment("article");
502/// let text = f.insert(&mut txn, 0, XmlTextPrelim::new(""));
503///
504/// let bold = Attrs::from([("b".into(), true.into())]);
505/// let italic = Attrs::from([("i".into(), true.into())]);
506///
507/// text.insert(&mut txn, 0, "hello ");
508/// text.insert_with_attributes(&mut txn, 6, "world", italic);
509/// text.format(&mut txn, 0, 5, bold);
510///
511/// assert_eq!(text.get_string(&txn), "<b>hello</b> <i>world</i>");
512///
513/// // remove formatting
514/// let remove_italic = Attrs::from([("i".into(), Any::Null)]);
515/// text.format(&mut txn, 6, 5, remove_italic);
516///
517/// assert_eq!(text.get_string(&txn), "<b>hello</b> world");
518///
519/// // insert binary payload eg. images
520/// let image = b"deadbeaf".to_vec();
521/// text.insert_embed(&mut txn, 1, image);
522///
523/// // insert nested shared type eg. table as ArrayRef of ArrayRefs
524/// let table = text.insert_embed(&mut txn, 5, ArrayPrelim::default());
525/// let header = table.insert(&mut txn, 0, ArrayPrelim::from(["Book title", "Author"]));
526/// let row = table.insert(&mut txn, 1, ArrayPrelim::from(["\"Moby-Dick\"", "Herman Melville"]));
527/// ```
528#[repr(transparent)]
529#[derive(Debug, Clone)]
530pub struct XmlTextRef(BranchPtr);
531
532impl XmlTextRef {
533    pub(crate) fn get_string_fragment(
534        head: Option<ItemPtr>,
535        start: Option<&StickyIndex>,
536        end: Option<&StickyIndex>,
537    ) -> String {
538        let mut buf = String::new();
539        for d in diff_between(head, start, end, YChange::identity) {
540            let mut attrs = Vec::new();
541            if let Some(attributes) = d.attributes.as_ref() {
542                for (key, value) in attributes.iter() {
543                    attrs.push((key, value));
544                }
545                attrs.sort_by(|x, y| x.0.cmp(y.0))
546            }
547
548            // write attributes as xml opening tags
549            for (node, at) in attrs.iter() {
550                write!(buf, "<{}", node).unwrap();
551                if let Any::Map(at) = at {
552                    for (k, v) in at.iter() {
553                        write!(buf, " {}=\"{}\"", k, v).unwrap();
554                    }
555                }
556                buf.push('>');
557            }
558
559            // write string content of delta
560            if let Out::Any(any) = d.insert {
561                write!(buf, "{}", any).unwrap();
562            }
563
564            // write attributes as xml closing tags
565            attrs.reverse();
566            for (key, _) in attrs {
567                write!(buf, "</{}>", key).unwrap();
568            }
569        }
570        buf
571    }
572}
573
574impl SharedRef for XmlTextRef {}
575impl Xml for XmlTextRef {}
576impl Text for XmlTextRef {}
577impl IndexedSequence for XmlTextRef {}
578#[cfg(feature = "weak")]
579impl crate::Quotable for XmlTextRef {}
580
581impl AsRef<TextRef> for XmlTextRef {
582    #[inline]
583    fn as_ref(&self) -> &TextRef {
584        unsafe { std::mem::transmute(self) }
585    }
586}
587
588impl DeepObservable for XmlTextRef {}
589impl Observable for XmlTextRef {
590    type Event = XmlTextEvent;
591}
592
593impl GetString for XmlTextRef {
594    fn get_string<T: ReadTxn>(&self, _txn: &T) -> String {
595        XmlTextRef::get_string_fragment(self.0.start, None, None)
596    }
597}
598
599impl AsRef<Branch> for XmlTextRef {
600    fn as_ref(&self) -> &Branch {
601        &self.0
602    }
603}
604
605impl Eq for XmlTextRef {}
606impl PartialEq for XmlTextRef {
607    fn eq(&self, other: &Self) -> bool {
608        self.0.id() == other.0.id()
609    }
610}
611
612impl From<BranchPtr> for XmlTextRef {
613    fn from(inner: BranchPtr) -> Self {
614        XmlTextRef(inner)
615    }
616}
617
618impl TryFrom<ItemPtr> for XmlTextRef {
619    type Error = ItemPtr;
620
621    fn try_from(value: ItemPtr) -> Result<Self, Self::Error> {
622        if let Some(branch) = value.clone().as_branch() {
623            Ok(Self::from(branch))
624        } else {
625            Err(value)
626        }
627    }
628}
629
630impl TryFrom<Out> for XmlTextRef {
631    type Error = Out;
632
633    fn try_from(value: Out) -> Result<Self, Self::Error> {
634        match value {
635            Out::YXmlText(value) => Ok(value),
636            other => Err(other),
637        }
638    }
639}
640
641impl AsPrelim for XmlTextRef {
642    type Prelim = XmlDeltaPrelim;
643
644    fn as_prelim<T: ReadTxn>(&self, txn: &T) -> Self::Prelim {
645        let attributes: HashMap<Arc<str>, String> = self
646            .0
647            .map
648            .iter()
649            .flat_map(|(k, ptr)| {
650                if ptr.is_deleted() {
651                    None
652                } else if let Some(value) = ptr.content.get_last() {
653                    Some((k.clone(), value.to_string(txn)))
654                } else {
655                    None
656                }
657            })
658            .collect();
659        let delta: Vec<Delta<In>> = self
660            .diff(txn, YChange::identity)
661            .into_iter()
662            .map(|diff| Delta::Inserted(diff.insert.as_prelim(txn), diff.attributes))
663            .collect();
664        XmlDeltaPrelim { attributes, delta }
665    }
666}
667
668impl DefaultPrelim for XmlTextRef {
669    type Prelim = XmlTextPrelim;
670
671    #[inline]
672    fn default_prelim() -> Self::Prelim {
673        XmlTextPrelim::default()
674    }
675}
676
677/// A preliminary type that will be materialized into an [XmlTextRef] once it will be integrated
678/// into Yrs document.
679#[repr(transparent)]
680#[derive(Debug, Clone, PartialEq, Hash, Default)]
681pub struct XmlTextPrelim(String);
682
683impl Deref for XmlTextPrelim {
684    type Target = String;
685
686    #[inline]
687    fn deref(&self) -> &Self::Target {
688        &self.0
689    }
690}
691
692impl DerefMut for XmlTextPrelim {
693    #[inline]
694    fn deref_mut(&mut self) -> &mut Self::Target {
695        &mut self.0
696    }
697}
698
699impl XmlTextPrelim {
700    #[inline]
701    pub fn new<S: Into<String>>(str: S) -> Self {
702        XmlTextPrelim(str.into())
703    }
704}
705
706impl XmlPrelim for XmlTextPrelim {}
707
708impl Prelim for XmlTextPrelim {
709    type Return = XmlTextRef;
710
711    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
712        let inner = Branch::new(TypeRef::XmlText);
713        (ItemContent::Type(inner), Some(self))
714    }
715
716    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
717        if !self.is_empty() {
718            let text = XmlTextRef::from(inner_ref);
719            text.push(txn, &self.0);
720        }
721    }
722}
723
724impl Into<EmbedPrelim<XmlTextPrelim>> for XmlTextPrelim {
725    #[inline]
726    fn into(self) -> EmbedPrelim<XmlTextPrelim> {
727        EmbedPrelim::Shared(self)
728    }
729}
730
731impl From<XmlTextPrelim> for In {
732    #[inline]
733    fn from(value: XmlTextPrelim) -> Self {
734        In::XmlText(XmlDeltaPrelim::from(value))
735    }
736}
737
738#[derive(Debug, Clone, PartialEq, Default)]
739pub struct XmlDeltaPrelim {
740    pub attributes: HashMap<Arc<str>, String>,
741    pub delta: Vec<Delta<In>>,
742}
743
744impl Deref for XmlDeltaPrelim {
745    type Target = [Delta<In>];
746
747    #[inline]
748    fn deref(&self) -> &Self::Target {
749        &self.delta
750    }
751}
752
753impl Prelim for XmlDeltaPrelim {
754    type Return = XmlTextRef;
755
756    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
757        (ItemContent::Type(Branch::new(TypeRef::XmlText)), Some(self))
758    }
759
760    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
761        let text_ref = XmlTextRef::from(inner_ref);
762        for (key, value) in self.attributes {
763            text_ref.insert_attribute(txn, key, value);
764        }
765        text_ref.apply_delta(txn, self.delta);
766    }
767}
768
769impl From<XmlTextPrelim> for XmlDeltaPrelim {
770    fn from(value: XmlTextPrelim) -> Self {
771        XmlDeltaPrelim {
772            attributes: HashMap::default(),
773            delta: vec![Delta::Inserted(In::Any(Any::from(value.0)), None)],
774        }
775    }
776}
777
778impl From<XmlDeltaPrelim> for In {
779    #[inline]
780    fn from(value: XmlDeltaPrelim) -> Self {
781        In::XmlText(value)
782    }
783}
784
785/// A XML fragment, which works as an untagged collection of XML nodes.
786#[repr(transparent)]
787#[derive(Debug, Clone)]
788pub struct XmlFragmentRef(BranchPtr);
789
790impl RootRef for XmlFragmentRef {
791    fn type_ref() -> TypeRef {
792        TypeRef::XmlFragment
793    }
794}
795impl SharedRef for XmlFragmentRef {}
796impl XmlFragment for XmlFragmentRef {}
797impl IndexedSequence for XmlFragmentRef {}
798
799impl XmlFragmentRef {
800    pub fn parent(&self) -> Option<XmlOut> {
801        let item = self.0.item?;
802        let parent = item.parent.as_branch()?;
803        XmlOut::try_from(*parent).ok()
804    }
805}
806
807impl AsRef<ArrayRef> for XmlFragmentRef {
808    #[inline]
809    fn as_ref(&self) -> &ArrayRef {
810        unsafe { std::mem::transmute(self) }
811    }
812}
813
814impl GetString for XmlFragmentRef {
815    /// Converts current XML node into a textual representation. This representation if flat, it
816    /// doesn't include any indentation.
817    fn get_string<T: ReadTxn>(&self, txn: &T) -> String {
818        let inner = self.0;
819        let mut s = String::new();
820        for i in inner.iter(txn) {
821            if !i.is_deleted() {
822                for content in i.content.get_content() {
823                    write!(&mut s, "{}", content.to_string(txn)).unwrap();
824                }
825            }
826        }
827        s
828    }
829}
830
831impl DeepObservable for XmlFragmentRef {}
832impl Observable for XmlFragmentRef {
833    type Event = XmlEvent;
834}
835
836impl AsRef<Branch> for XmlFragmentRef {
837    fn as_ref(&self) -> &Branch {
838        self.0.deref()
839    }
840}
841
842impl Eq for XmlFragmentRef {}
843impl PartialEq for XmlFragmentRef {
844    fn eq(&self, other: &Self) -> bool {
845        self.0.id() == other.0.id()
846    }
847}
848
849impl From<BranchPtr> for XmlFragmentRef {
850    fn from(inner: BranchPtr) -> Self {
851        XmlFragmentRef(inner)
852    }
853}
854
855impl TryFrom<ItemPtr> for XmlFragmentRef {
856    type Error = ItemPtr;
857
858    fn try_from(value: ItemPtr) -> Result<Self, Self::Error> {
859        if let Some(branch) = value.clone().as_branch() {
860            Ok(Self::from(branch))
861        } else {
862            Err(value)
863        }
864    }
865}
866
867impl TryFrom<Out> for XmlFragmentRef {
868    type Error = Out;
869
870    fn try_from(value: Out) -> Result<Self, Self::Error> {
871        match value {
872            Out::YXmlFragment(value) => Ok(value),
873            other => Err(other),
874        }
875    }
876}
877
878impl AsPrelim for XmlFragmentRef {
879    type Prelim = XmlFragmentPrelim;
880
881    fn as_prelim<T: ReadTxn>(&self, txn: &T) -> Self::Prelim {
882        let children: Vec<_> = self
883            .children(txn)
884            .map(|v| match v {
885                XmlOut::Element(v) => XmlIn::from(v.as_prelim(txn)),
886                XmlOut::Fragment(v) => XmlIn::from(v.as_prelim(txn)),
887                XmlOut::Text(v) => XmlIn::from(v.as_prelim(txn)),
888            })
889            .collect();
890        XmlFragmentPrelim(children)
891    }
892}
893
894impl DefaultPrelim for XmlFragmentRef {
895    type Prelim = XmlFragmentPrelim;
896
897    #[inline]
898    fn default_prelim() -> Self::Prelim {
899        XmlFragmentPrelim::default()
900    }
901}
902
903/// A preliminary type that will be materialized into an [XmlFragmentRef] once it will be integrated
904/// into Yrs document.
905#[derive(Debug, Clone, PartialEq, Default)]
906pub struct XmlFragmentPrelim(Vec<XmlIn>);
907
908impl XmlFragmentPrelim {
909    pub fn new<I, T>(iter: I) -> Self
910    where
911        I: IntoIterator<Item = XmlIn>,
912    {
913        XmlFragmentPrelim(iter.into_iter().collect())
914    }
915}
916
917impl Prelim for XmlFragmentPrelim {
918    type Return = XmlFragmentRef;
919
920    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
921        let inner = Branch::new(TypeRef::XmlFragment);
922        (ItemContent::Type(inner), Some(self))
923    }
924
925    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
926        let xml = XmlFragmentRef::from(inner_ref);
927        for value in self.0 {
928            xml.push_back(txn, value);
929        }
930    }
931}
932
933impl Into<EmbedPrelim<XmlFragmentPrelim>> for XmlFragmentPrelim {
934    #[inline]
935    fn into(self) -> EmbedPrelim<XmlFragmentPrelim> {
936        EmbedPrelim::Shared(self)
937    }
938}
939
940impl From<XmlFragmentPrelim> for In {
941    #[inline]
942    fn from(value: XmlFragmentPrelim) -> Self {
943        In::XmlFragment(value)
944    }
945}
946
947/// (Obsolete) an Yjs-compatible XML node used for nesting Map elements.
948#[derive(Debug, Clone)]
949pub struct XmlHookRef(BranchPtr);
950
951impl Map for XmlHookRef {}
952
953impl ToJson for XmlHookRef {
954    fn to_json<T: ReadTxn>(&self, txn: &T) -> Any {
955        let map: &MapRef = self.as_ref();
956        map.to_json(txn)
957    }
958}
959
960impl AsRef<Branch> for XmlHookRef {
961    fn as_ref(&self) -> &Branch {
962        self.0.deref()
963    }
964}
965
966impl Eq for XmlHookRef {}
967impl PartialEq for XmlHookRef {
968    fn eq(&self, other: &Self) -> bool {
969        self.0.id() == other.0.id()
970    }
971}
972
973impl From<BranchPtr> for XmlHookRef {
974    fn from(inner: BranchPtr) -> Self {
975        XmlHookRef(inner)
976    }
977}
978
979impl AsRef<MapRef> for XmlHookRef {
980    #[inline]
981    fn as_ref(&self) -> &MapRef {
982        unsafe { std::mem::transmute(self) }
983    }
984}
985
986pub trait Xml: AsRef<Branch> {
987    fn parent(&self) -> Option<XmlOut> {
988        let item = self.as_ref().item?;
989        let parent = item.parent.as_branch()?;
990        XmlOut::try_from(*parent).ok()
991    }
992
993    /// Removes an attribute recognized by an `attr_name` from a current XML element.
994    fn remove_attribute<K>(&self, txn: &mut TransactionMut, attr_name: &K)
995    where
996        K: AsRef<str>,
997    {
998        self.as_ref().remove(txn, attr_name.as_ref());
999    }
1000
1001    /// Inserts an attribute entry into current XML element.
1002    fn insert_attribute<K, V>(&self, txn: &mut TransactionMut, key: K, value: V) -> V::Return
1003    where
1004        K: Into<Arc<str>>,
1005        V: Prelim,
1006    {
1007        let key = key.into();
1008        let pos = {
1009            let inner = self.as_ref();
1010            let left = inner.map.get(&key);
1011            ItemPosition {
1012                parent: BranchPtr::from(inner).into(),
1013                left: left.cloned(),
1014                right: None,
1015                index: 0,
1016                current_attrs: None,
1017            }
1018        };
1019
1020        let ptr = txn
1021            .create_item(&pos, value, Some(key))
1022            .expect("Cannot insert empty value");
1023        if let Ok(integrated) = ptr.try_into() {
1024            integrated
1025        } else {
1026            panic!("Defect: unexpected integrated type")
1027        }
1028    }
1029
1030    /// Returns a value of an attribute given its `attr_name`. Returns `None` if no such attribute
1031    /// can be found inside of a current XML element.
1032    fn get_attribute<T: ReadTxn>(&self, txn: &T, attr_name: &str) -> Option<Out> {
1033        let branch = self.as_ref();
1034        branch.get(txn, attr_name)
1035    }
1036
1037    /// Returns an unordered iterator over all attributes (key-value pairs), that can be found
1038    /// inside of a current XML element.
1039    fn attributes<'a, T: ReadTxn>(&'a self, txn: &'a T) -> Attributes<'a, &'a T, T> {
1040        Attributes(Entries::new(&self.as_ref().map, txn))
1041    }
1042
1043    fn siblings<'a, T: ReadTxn>(&self, txn: &'a T) -> Siblings<'a, T> {
1044        let ptr = BranchPtr::from(self.as_ref());
1045        Siblings::new(ptr.item, txn)
1046    }
1047}
1048
1049pub trait XmlFragment: AsRef<Branch> {
1050    fn first_child(&self) -> Option<XmlOut> {
1051        let first = self.as_ref().first()?;
1052        match &first.content {
1053            ItemContent::Type(c) => {
1054                let ptr = BranchPtr::from(c);
1055                XmlOut::try_from(ptr).ok()
1056            }
1057            _ => None,
1058        }
1059    }
1060
1061    /// Returns an iterator over all children of a current XML fragment.
1062    /// It does NOT include nested children of its children - for such cases use [Self::successors]
1063    /// iterator.
1064    fn children<'a, T: ReadTxn>(&self, txn: &'a T) -> XmlNodes<'a, T> {
1065        let iter = BlockIter::new(BranchPtr::from(self.as_ref()));
1066        XmlNodes::new(iter, txn)
1067    }
1068
1069    /// Returns a number of elements stored in current array.
1070    fn len<T: ReadTxn>(&self, _txn: &T) -> u32 {
1071        self.as_ref().len()
1072    }
1073
1074    /// Inserts a `value` at the given `index`. Inserting at index `0` is equivalent to prepending
1075    /// current array with given `value`, while inserting at array length is equivalent to appending
1076    /// that value at the end of it.
1077    ///
1078    /// Using `index` value that's higher than current array length results in panic.
1079    fn insert<V>(&self, txn: &mut TransactionMut, index: u32, xml_node: V) -> V::Return
1080    where
1081        V: XmlPrelim,
1082    {
1083        let ptr = self.as_ref().insert_at(txn, index, xml_node).unwrap(); // XML node is never empty
1084        if let Ok(integrated) = V::Return::try_from(ptr) {
1085            integrated
1086        } else {
1087            panic!("Defect: inserted XML element returned primitive value block")
1088        }
1089    }
1090
1091    /// Inserts given `value` at the end of the current array.
1092    fn push_back<V>(&self, txn: &mut TransactionMut, xml_node: V) -> V::Return
1093    where
1094        V: XmlPrelim,
1095    {
1096        let len = self.len(txn);
1097        self.insert(txn, len, xml_node)
1098    }
1099
1100    /// Inserts given `value` at the beginning of the current array.
1101    fn push_front<V>(&self, txn: &mut TransactionMut, xml_node: V) -> V::Return
1102    where
1103        V: XmlPrelim,
1104    {
1105        self.insert(txn, 0, xml_node)
1106    }
1107
1108    /// Removes a single element at provided `index`.
1109    fn remove(&self, txn: &mut TransactionMut, index: u32) {
1110        self.remove_range(txn, index, 1)
1111    }
1112
1113    /// Removes a range of elements from current array, starting at given `index` up until
1114    /// a particular number described by `len` has been deleted. This method panics in case when
1115    /// not all expected elements were removed (due to insufficient number of elements in an array)
1116    /// or `index` is outside the bounds of an array.
1117    fn remove_range(&self, txn: &mut TransactionMut, index: u32, len: u32) {
1118        let mut walker = BlockIter::new(BranchPtr::from(self.as_ref()));
1119        if walker.try_forward(txn, index) {
1120            walker.delete(txn, len)
1121        } else {
1122            panic!("Index {} is outside of the range of an array", index);
1123        }
1124    }
1125
1126    /// Retrieves a value stored at a given `index`. Returns `None` when provided index was out
1127    /// of the range of a current array.
1128    fn get<T: ReadTxn>(&self, _txn: &T, index: u32) -> Option<XmlOut> {
1129        let branch = self.as_ref();
1130        let (content, _) = branch.get_at(index)?;
1131        if let ItemContent::Type(inner) = content {
1132            let ptr: BranchPtr = inner.into();
1133            XmlOut::try_from(ptr).ok()
1134        } else {
1135            None
1136        }
1137    }
1138
1139    /// Returns an iterator that can be used to traverse over the successors of a current
1140    /// XML element. This includes recursive step over children of its children. The recursive
1141    /// iteration is depth-first.
1142    ///
1143    /// Example:
1144    /// ```
1145    /// /* construct node with a shape:
1146    ///    <div>
1147    ///       <p>Hello <b>world</b></p>
1148    ///       again
1149    ///    </div>
1150    /// */
1151    /// use yrs::{Doc, Text, Xml, XmlOut, Transact, XmlFragment, XmlElementPrelim, XmlTextPrelim, GetString};
1152    ///
1153    /// let doc = Doc::new();
1154    /// let mut html = doc.get_or_insert_xml_fragment("div");
1155    /// let mut txn = doc.transact_mut();
1156    /// let p = html.push_back(&mut txn, XmlElementPrelim::empty("p"));
1157    /// let txt = p.push_back(&mut txn, XmlTextPrelim::new("Hello "));
1158    /// let b = p.push_back(&mut txn, XmlElementPrelim::empty("b"));
1159    /// let txt = b.push_back(&mut txn, XmlTextPrelim::new("world"));
1160    /// let txt = html.push_back(&mut txn, XmlTextPrelim::new("again"));
1161    ///
1162    /// let mut result = Vec::new();
1163    /// for node in html.successors(&txn) {
1164    ///   let value = match node {
1165    ///       XmlOut::Element(elem) => elem.tag().to_string(),
1166    ///       XmlOut::Text(txt) => txt.get_string(&txn),
1167    ///       _ => panic!("shouldn't be the case here")
1168    ///   };
1169    ///   result.push(value);
1170    /// }
1171    /// assert_eq!(result, vec![
1172    ///   "p".to_string(),
1173    ///   "Hello ".to_string(),
1174    ///   "b".to_string(),
1175    ///   "world".to_string(),
1176    ///   "again".to_string()
1177    /// ]);
1178    /// ```
1179    fn successors<'a, T: ReadTxn>(&'a self, txn: &'a T) -> TreeWalker<'a, &'a T, T> {
1180        TreeWalker::new(self.as_ref(), txn)
1181    }
1182}
1183
1184/// Iterator over the attributes (key-value pairs represented as a strings) of an [XmlElement].
1185pub struct Attributes<'a, B, T>(Entries<'a, B, T>);
1186
1187impl<'a, B, T> Attributes<'a, B, T>
1188where
1189    B: Borrow<T>,
1190    T: ReadTxn,
1191{
1192    pub fn new(branch: &'a Branch, txn: B) -> Self {
1193        let entries = Entries::new(&branch.map, txn);
1194        Attributes(entries)
1195    }
1196}
1197
1198impl<'a, B, T> Iterator for Attributes<'a, B, T>
1199where
1200    B: Borrow<T>,
1201    T: ReadTxn,
1202{
1203    type Item = (&'a str, Out);
1204
1205    fn next(&mut self) -> Option<Self::Item> {
1206        let (key, block) = self.0.next()?;
1207        match block.content.get_last() {
1208            Some(value) => Some((key.as_ref(), value)),
1209            None => self.next(),
1210        }
1211    }
1212}
1213
1214pub struct XmlNodes<'a, T> {
1215    iter: BlockIter,
1216    txn: &'a T,
1217}
1218
1219impl<'a, T: ReadTxn> XmlNodes<'a, T> {
1220    fn new(iter: BlockIter, txn: &'a T) -> Self {
1221        XmlNodes { iter, txn }
1222    }
1223}
1224
1225impl<'a, T: ReadTxn> Iterator for XmlNodes<'a, T> {
1226    type Item = XmlOut;
1227
1228    fn next(&mut self) -> Option<Self::Item> {
1229        let value = self.iter.read_value(self.txn)?;
1230        XmlOut::try_from(value).ok()
1231    }
1232}
1233
1234/// An iterator over [XmlElement] successors, working in a recursive depth-first manner.
1235pub struct TreeWalker<'a, B, T> {
1236    current: Option<&'a Item>,
1237    root: TypePtr,
1238    first_call: bool,
1239    _txn: B,
1240    _marker: PhantomData<T>,
1241}
1242
1243impl<'a, B, T: ReadTxn> TreeWalker<'a, B, T>
1244where
1245    B: Borrow<T>,
1246    T: ReadTxn,
1247{
1248    pub fn new(root: &'a Branch, txn: B) -> Self {
1249        TreeWalker {
1250            current: root.start.as_deref(),
1251            root: TypePtr::Branch(BranchPtr::from(root)),
1252            first_call: true,
1253            _txn: txn,
1254            _marker: PhantomData::default(),
1255        }
1256    }
1257}
1258
1259impl<'a, B, T: ReadTxn> Iterator for TreeWalker<'a, B, T>
1260where
1261    B: Borrow<T>,
1262    T: ReadTxn,
1263{
1264    type Item = XmlOut;
1265
1266    /// Tree walker used depth-first search to move over the xml tree.
1267    fn next(&mut self) -> Option<Self::Item> {
1268        fn try_descend(item: &Item) -> Option<&Item> {
1269            if let ItemContent::Type(t) = &item.content {
1270                let inner = t.as_ref();
1271                match inner.type_ref() {
1272                    TypeRef::XmlElement(_) | TypeRef::XmlFragment if !item.is_deleted() => {
1273                        return inner.start.as_deref();
1274                    }
1275                    _ => { /* do nothing */ }
1276                }
1277            }
1278
1279            None
1280        }
1281
1282        let mut result = None;
1283        let mut n = self.current.take();
1284        if let Some(current) = n {
1285            if !self.first_call || current.is_deleted() {
1286                while {
1287                    if let Some(current) = n {
1288                        if let Some(ptr) = try_descend(current) {
1289                            // depth-first search - try walk down the tree first
1290                            n = Some(ptr);
1291                        } else {
1292                            // walk right or up in the tree
1293                            while let Some(current) = n {
1294                                if let Some(right) = current.right.as_ref() {
1295                                    n = Some(right);
1296                                    break;
1297                                } else if current.parent == self.root {
1298                                    n = None;
1299                                } else {
1300                                    let ptr = current.parent.as_branch().unwrap();
1301                                    n = ptr.item.as_deref();
1302                                }
1303                            }
1304                        }
1305                    }
1306                    if let Some(current) = n {
1307                        current.is_deleted()
1308                    } else {
1309                        false
1310                    }
1311                } {}
1312            }
1313            self.first_call = false;
1314            self.current = n;
1315        }
1316        if let Some(current) = self.current {
1317            if let ItemContent::Type(t) = &current.content {
1318                result = XmlOut::try_from(BranchPtr::from(t)).ok();
1319            }
1320        }
1321        result
1322    }
1323}
1324
1325/// Event generated by [XmlText::observe] method. Emitted during transaction commit phase.
1326pub struct XmlTextEvent {
1327    pub(crate) current_target: BranchPtr,
1328    target: XmlTextRef,
1329    delta: UnsafeCell<Option<Vec<Delta>>>,
1330    keys: UnsafeCell<Result<HashMap<Arc<str>, EntryChange>, HashSet<Option<Arc<str>>>>>,
1331}
1332
1333impl XmlTextEvent {
1334    pub(crate) fn new(branch_ref: BranchPtr, key_changes: HashSet<Option<Arc<str>>>) -> Self {
1335        let current_target = branch_ref.clone();
1336        let target = XmlTextRef::from(branch_ref);
1337        XmlTextEvent {
1338            target,
1339            current_target,
1340            delta: UnsafeCell::new(None),
1341            keys: UnsafeCell::new(Err(key_changes)),
1342        }
1343    }
1344
1345    /// Returns a [XmlText] instance which emitted this event.
1346    pub fn target(&self) -> &XmlTextRef {
1347        &self.target
1348    }
1349
1350    /// Returns a path from root type down to [XmlText] instance which emitted this event.
1351    pub fn path(&self) -> Path {
1352        Branch::path(self.current_target, self.target.0)
1353    }
1354
1355    /// Returns a summary of text changes made over corresponding [XmlText] collection within
1356    /// bounds of current transaction.
1357    pub fn delta(&self, txn: &TransactionMut) -> &[Delta] {
1358        let delta = unsafe { self.delta.get().as_mut().unwrap() };
1359        delta
1360            .get_or_insert_with(|| TextEvent::get_delta(self.target.0, txn))
1361            .as_slice()
1362    }
1363
1364    /// Returns a summary of attribute changes made over corresponding [XmlText] collection within
1365    /// bounds of current transaction.
1366    pub fn keys(&self, txn: &TransactionMut) -> &HashMap<Arc<str>, EntryChange> {
1367        let keys = unsafe { self.keys.get().as_mut().unwrap() };
1368
1369        match keys {
1370            Ok(keys) => {
1371                return keys;
1372            }
1373            Err(subs) => {
1374                let subs = event_keys(txn, self.target.0, subs);
1375                *keys = Ok(subs);
1376                if let Ok(keys) = keys {
1377                    keys
1378                } else {
1379                    panic!("Defect: should not happen");
1380                }
1381            }
1382        }
1383    }
1384}
1385
1386pub struct Siblings<'a, T> {
1387    current: Option<ItemPtr>,
1388    _txn: &'a T,
1389}
1390
1391impl<'a, T> Siblings<'a, T> {
1392    fn new(current: Option<ItemPtr>, txn: &'a T) -> Self {
1393        Siblings { current, _txn: txn }
1394    }
1395}
1396
1397impl<'a, T> Iterator for Siblings<'a, T> {
1398    type Item = XmlOut;
1399
1400    fn next(&mut self) -> Option<Self::Item> {
1401        while let Some(item) = self.current.as_deref() {
1402            self.current = item.right;
1403            if let Some(right) = self.current.as_deref() {
1404                if !right.is_deleted() {
1405                    if let ItemContent::Type(inner) = &right.content {
1406                        let ptr = BranchPtr::from(inner);
1407                        return XmlOut::try_from(ptr).ok();
1408                    }
1409                }
1410            }
1411        }
1412
1413        None
1414    }
1415}
1416
1417impl<'a, T> DoubleEndedIterator for Siblings<'a, T> {
1418    fn next_back(&mut self) -> Option<Self::Item> {
1419        while let Some(item) = self.current.as_deref() {
1420            self.current = item.left;
1421            if let Some(left) = self.current.as_deref() {
1422                if !left.is_deleted() {
1423                    if let ItemContent::Type(inner) = &left.content {
1424                        let ptr = BranchPtr::from(inner);
1425                        return XmlOut::try_from(ptr).ok();
1426                    }
1427                }
1428            }
1429        }
1430
1431        None
1432    }
1433}
1434
1435/// Event generated by [XmlElement::observe] method. Emitted during transaction commit phase.
1436pub struct XmlEvent {
1437    pub(crate) current_target: BranchPtr,
1438    target: XmlOut,
1439    change_set: UnsafeCell<Option<Box<ChangeSet<Change>>>>,
1440    keys: UnsafeCell<Result<HashMap<Arc<str>, EntryChange>, HashSet<Option<Arc<str>>>>>,
1441    children_changed: bool,
1442}
1443
1444impl XmlEvent {
1445    pub(crate) fn new(branch_ref: BranchPtr, key_changes: HashSet<Option<Arc<str>>>) -> Self {
1446        let current_target = branch_ref.clone();
1447        let children_changed = key_changes.iter().any(Option::is_none);
1448        XmlEvent {
1449            target: XmlOut::try_from(branch_ref).unwrap(),
1450            current_target,
1451            change_set: UnsafeCell::new(None),
1452            keys: UnsafeCell::new(Err(key_changes)),
1453            children_changed,
1454        }
1455    }
1456
1457    /// True if any child XML nodes have been changed within bounds of current transaction.
1458    pub fn children_changed(&self) -> bool {
1459        self.children_changed
1460    }
1461
1462    /// Returns a [XmlElement] instance which emitted this event.
1463    pub fn target(&self) -> &XmlOut {
1464        &self.target
1465    }
1466
1467    /// Returns a path from root type down to [XmlElement] instance which emitted this event.
1468    pub fn path(&self) -> Path {
1469        Branch::path(self.current_target, self.target.as_ptr())
1470    }
1471
1472    /// Returns a summary of XML child nodes changed within corresponding [XmlElement] collection
1473    /// within bounds of current transaction.
1474    pub fn delta(&self, txn: &TransactionMut) -> &[Change] {
1475        self.changes(txn).delta.as_slice()
1476    }
1477
1478    /// Returns a collection of block identifiers that have been added within a bounds of
1479    /// current transaction.
1480    pub fn added(&self, txn: &TransactionMut) -> &HashSet<ID> {
1481        &self.changes(txn).added
1482    }
1483
1484    /// Returns a collection of block identifiers that have been removed within a bounds of
1485    /// current transaction.
1486    pub fn deleted(&self, txn: &TransactionMut) -> &HashSet<ID> {
1487        &self.changes(txn).deleted
1488    }
1489
1490    /// Returns a summary of attribute changes made over corresponding [XmlElement] collection
1491    /// within bounds of current transaction.
1492    pub fn keys(&self, txn: &TransactionMut) -> &HashMap<Arc<str>, EntryChange> {
1493        let keys = unsafe { self.keys.get().as_mut().unwrap() };
1494
1495        match keys {
1496            Ok(keys) => keys,
1497            Err(subs) => {
1498                let subs = event_keys(txn, self.target.as_ptr(), subs);
1499                *keys = Ok(subs);
1500                if let Ok(keys) = keys {
1501                    keys
1502                } else {
1503                    panic!("Defect: should not happen");
1504                }
1505            }
1506        }
1507    }
1508
1509    fn changes(&self, txn: &TransactionMut) -> &ChangeSet<Change> {
1510        let change_set = unsafe { self.change_set.get().as_mut().unwrap() };
1511        change_set
1512            .get_or_insert_with(|| Box::new(event_change_set(txn, self.target.as_ptr().start)))
1513    }
1514}
1515
1516#[cfg(test)]
1517mod test {
1518    use std::collections::{HashMap, HashSet};
1519    use std::sync::Arc;
1520
1521    use arc_swap::ArcSwapOption;
1522
1523    use crate::test_utils::exchange_updates;
1524    use crate::transaction::ReadTxn;
1525    use crate::types::xml::{Xml, XmlFragment, XmlOut};
1526    use crate::types::{Attrs, Change, EntryChange, Out};
1527    use crate::updates::decoder::Decode;
1528    use crate::updates::encoder::{Encoder, EncoderV1};
1529    use crate::{
1530        Any, Doc, GetString, Observable, SharedRef, StateVector, Text, Transact, Update,
1531        XmlElementPrelim, XmlTextPrelim, XmlTextRef,
1532    };
1533
1534    #[test]
1535    fn insert_attribute() {
1536        let d1 = Doc::with_client_id(1);
1537        let f = d1.get_or_insert_xml_fragment("xml");
1538        let mut t1 = d1.transact_mut();
1539        let xml1 = f.push_back(&mut t1, XmlElementPrelim::empty("div"));
1540        xml1.insert_attribute(&mut t1, "height", 10.to_string());
1541        assert_eq!(xml1.get_attribute(&t1, "height"), Some(Out::from("10")));
1542
1543        let d2 = Doc::with_client_id(1);
1544        let f = d2.get_or_insert_xml_fragment("xml");
1545        let mut t2 = d2.transact_mut();
1546        let xml2 = f.push_back(&mut t2, XmlElementPrelim::empty("div"));
1547        let u = t1.encode_state_as_update_v1(&StateVector::default());
1548        let u = Update::decode_v1(u.as_slice()).unwrap();
1549        t2.apply_update(u).unwrap();
1550        assert_eq!(xml2.get_attribute(&t2, "height"), Some(Out::from("10")));
1551    }
1552
1553    #[test]
1554    fn tree_walker() {
1555        let doc = Doc::with_client_id(1);
1556        let root = doc.get_or_insert_xml_fragment("xml");
1557        let mut txn = doc.transact_mut();
1558        /*
1559            <UNDEFINED>
1560                <p>{txt1}{txt2}</p>
1561                <p></p>
1562                <img/>
1563            </UNDEFINED>
1564        */
1565        let p1 = root.push_back(&mut txn, XmlElementPrelim::empty("p"));
1566        p1.push_back(&mut txn, XmlTextPrelim::new(""));
1567        p1.push_back(&mut txn, XmlTextPrelim::new(""));
1568        let p2 = root.push_back(&mut txn, XmlElementPrelim::empty("p"));
1569        root.push_back(&mut txn, XmlElementPrelim::empty("img"));
1570
1571        let all_paragraphs = root.successors(&txn).filter_map(|n| match n {
1572            XmlOut::Element(e) if e.tag() == &"p".into() => Some(e),
1573            _ => None,
1574        });
1575        let actual: Vec<_> = all_paragraphs.collect();
1576
1577        assert_eq!(
1578            actual.len(),
1579            2,
1580            "query selector should found two paragraphs"
1581        );
1582        assert_eq!(
1583            actual[0].hook(),
1584            p1.hook(),
1585            "query selector found 1st paragraph"
1586        );
1587        assert_eq!(
1588            actual[1].hook(),
1589            p2.hook(),
1590            "query selector found 2nd paragraph"
1591        );
1592    }
1593
1594    #[test]
1595    fn text_attributes() {
1596        let doc = Doc::with_client_id(1);
1597        let f = doc.get_or_insert_xml_fragment("test");
1598        let mut txn = doc.transact_mut();
1599        let txt = f.push_back(&mut txn, XmlTextPrelim::new(""));
1600        txt.insert_attribute(&mut txn, "test", 42.to_string());
1601
1602        assert_eq!(txt.get_attribute(&txn, "test"), Some(Out::from("42")));
1603        let actual: Vec<_> = txt.attributes(&txn).collect();
1604        let expected: Vec<_> = vec![("test", Out::from("42"))].into_iter().collect();
1605        assert_eq!(actual, expected);
1606    }
1607
1608    #[test]
1609    fn text_attributes_any() {
1610        let doc = Doc::with_client_id(1);
1611        let f = doc.get_or_insert_xml_fragment("test");
1612        let mut txn = doc.transact_mut();
1613        let txt = f.push_back(&mut txn, XmlTextPrelim::new(""));
1614        txt.insert_attribute(&mut txn, "test", Any::BigInt(42));
1615        txt.insert_attribute(&mut txn, "test_true", true);
1616        txt.insert_attribute(&mut txn, "test_null", Any::Null);
1617
1618        assert_eq!(
1619            txt.get_attribute(&txn, "test"),
1620            Some(Out::Any(Any::BigInt(42)))
1621        );
1622        assert_eq!(
1623            txt.get_attribute(&txn, "test_true"),
1624            Some(Out::Any(Any::Bool(true)))
1625        );
1626        assert_eq!(
1627            txt.get_attribute(&txn, "test_null"),
1628            Some(Out::Any(Any::Null))
1629        );
1630
1631        // Collect attributes into a HashSet of keys to verify all expected keys are present
1632        let actual_keys: HashSet<&str> = txt.attributes(&txn).map(|(k, _)| k).collect();
1633        let expected_keys: HashSet<&str> =
1634            vec!["test", "test_true", "test_null"].into_iter().collect();
1635        assert_eq!(actual_keys, expected_keys);
1636    }
1637
1638    #[test]
1639    fn siblings() {
1640        let doc = Doc::with_client_id(1);
1641        let root = doc.get_or_insert_xml_fragment("root");
1642        let mut txn = doc.transact_mut();
1643        let first = root.push_back(&mut txn, XmlTextPrelim::new("hello"));
1644        let second = root.push_back(&mut txn, XmlElementPrelim::empty("p"));
1645
1646        assert_eq!(
1647            &first.siblings(&txn).next().unwrap().id(),
1648            second.hook().id(),
1649            "first.next_sibling should point to second"
1650        );
1651        assert_eq!(
1652            &second.siblings(&txn).next_back().unwrap().id(),
1653            first.hook().id(),
1654            "second.prev_sibling should point to first"
1655        );
1656        assert_eq!(
1657            &first.parent().unwrap().id(),
1658            root.hook().id(),
1659            "first.parent should point to root"
1660        );
1661        assert!(root.parent().is_none(), "root parent should not exist");
1662        assert_eq!(
1663            &root.first_child().unwrap().id(),
1664            first.hook().id(),
1665            "root.first_child should point to first"
1666        );
1667    }
1668
1669    #[test]
1670    fn serialization() {
1671        let d1 = Doc::with_client_id(1);
1672        let r1 = d1.get_or_insert_xml_fragment("root");
1673        let mut t1 = d1.transact_mut();
1674        let _first = r1.push_back(&mut t1, XmlTextPrelim::new("hello"));
1675        r1.push_back(&mut t1, XmlElementPrelim::empty("p"));
1676
1677        let expected = "hello<p></p>";
1678        assert_eq!(r1.get_string(&t1), expected);
1679
1680        let u1 = t1.encode_state_as_update_v1(&StateVector::default());
1681
1682        let d2 = Doc::with_client_id(2);
1683        let r2 = d2.get_or_insert_xml_fragment("root");
1684        let mut t2 = d2.transact_mut();
1685
1686        let u1 = Update::decode_v1(u1.as_slice()).unwrap();
1687        t2.apply_update(u1).unwrap();
1688        assert_eq!(r2.get_string(&t2), expected);
1689    }
1690
1691    #[test]
1692    fn serialization_compatibility() {
1693        let d1 = Doc::with_client_id(1);
1694        let r1 = d1.get_or_insert_xml_fragment("root");
1695        let mut t1 = d1.transact_mut();
1696        let _first = r1.push_back(&mut t1, XmlTextPrelim::new("hello"));
1697        r1.push_back(&mut t1, XmlElementPrelim::empty("p"));
1698
1699        /* This binary is result of following Yjs code (matching Rust code above):
1700        ```js
1701            let d1 = new Y.Doc()
1702            d1.clientID = 1
1703            let root = d1.get('root', Y.XmlElement)
1704            let first = new Y.XmlText()
1705            first.insert(0, 'hello')
1706            let second = new Y.XmlElement('p')
1707            root.insert(0, [first,second])
1708
1709            let expected = Y.encodeStateAsUpdate(d1)
1710        ``` */
1711        let expected = &[
1712            1, 3, 1, 0, 7, 1, 4, 114, 111, 111, 116, 6, 4, 0, 1, 0, 5, 104, 101, 108, 108, 111,
1713            135, 1, 0, 3, 1, 112, 0,
1714        ];
1715        let u1 = t1.encode_state_as_update_v1(&StateVector::default());
1716        assert_eq!(u1.as_slice(), expected);
1717    }
1718
1719    #[test]
1720    fn event_observers() {
1721        let d1 = Doc::with_client_id(1);
1722        let f = d1.get_or_insert_xml_fragment("xml");
1723        let xml = f.insert(&mut d1.transact_mut(), 0, XmlElementPrelim::empty("test"));
1724
1725        let d2 = Doc::with_client_id(2);
1726        let f = d2.get_or_insert_xml_fragment("xml");
1727        exchange_updates(&[&d1, &d2]);
1728        let xml2 = f
1729            .get(&d2.transact(), 0)
1730            .unwrap()
1731            .into_xml_element()
1732            .unwrap();
1733
1734        let attributes = Arc::new(ArcSwapOption::default());
1735        let nodes = Arc::new(ArcSwapOption::default());
1736        let attributes_c = attributes.clone();
1737        let nodes_c = nodes.clone();
1738        let _sub = xml.observe(move |txn, e| {
1739            attributes_c.store(Some(Arc::new(e.keys(txn).clone())));
1740            nodes_c.store(Some(Arc::new(e.delta(txn).to_vec())));
1741        });
1742
1743        // insert attribute
1744        {
1745            let mut txn = d1.transact_mut();
1746            xml.insert_attribute(&mut txn, "key1", "value1");
1747            xml.insert_attribute(&mut txn, "key2", "value2");
1748        }
1749        assert!(nodes.swap(None).unwrap().is_empty());
1750        assert_eq!(
1751            attributes.swap(None),
1752            Some(Arc::new(HashMap::from([
1753                (
1754                    "key1".into(),
1755                    EntryChange::Inserted(Any::String("value1".into()).into())
1756                ),
1757                (
1758                    "key2".into(),
1759                    EntryChange::Inserted(Any::String("value2".into()).into())
1760                )
1761            ])))
1762        );
1763
1764        // change and remove attribute
1765        {
1766            let mut txn = d1.transact_mut();
1767            xml.insert_attribute(&mut txn, "key1", "value11");
1768            xml.remove_attribute(&mut txn, &"key2");
1769        }
1770        assert!(nodes.swap(None).unwrap().is_empty());
1771        assert_eq!(
1772            attributes.swap(None),
1773            Some(Arc::new(HashMap::from([
1774                (
1775                    "key1".into(),
1776                    EntryChange::Updated(
1777                        Any::String("value1".into()).into(),
1778                        Any::String("value11".into()).into()
1779                    )
1780                ),
1781                (
1782                    "key2".into(),
1783                    EntryChange::Removed(Any::String("value2".into()).into())
1784                )
1785            ])))
1786        );
1787
1788        // add xml elements
1789        let (nested_txt, nested_xml) = {
1790            let mut txn = d1.transact_mut();
1791            let txt = xml.insert(&mut txn, 0, XmlTextPrelim::new(""));
1792            let xml2 = xml.insert(&mut txn, 1, XmlElementPrelim::empty("div"));
1793            (txt, xml2)
1794        };
1795        assert_eq!(
1796            nodes.swap(None),
1797            Some(Arc::new(vec![Change::Added(vec![
1798                Out::YXmlText(nested_txt.clone()),
1799                Out::YXmlElement(nested_xml.clone())
1800            ])]))
1801        );
1802        assert_eq!(attributes.swap(None), Some(HashMap::new().into()));
1803
1804        // remove and add
1805        let nested_xml2 = {
1806            let mut txn = d1.transact_mut();
1807            xml.remove_range(&mut txn, 1, 1);
1808            xml.insert(&mut txn, 1, XmlElementPrelim::empty("p"))
1809        };
1810        assert_eq!(
1811            nodes.swap(None),
1812            Some(Arc::new(vec![
1813                Change::Retain(1),
1814                Change::Added(vec![Out::YXmlElement(nested_xml2.clone())]),
1815                Change::Removed(1),
1816            ]))
1817        );
1818        assert_eq!(attributes.swap(None), Some(HashMap::new().into()));
1819
1820        // copy updates over
1821        let attributes = Arc::new(ArcSwapOption::default());
1822        let nodes = Arc::new(ArcSwapOption::default());
1823        let attributes_c = attributes.clone();
1824        let nodes_c = nodes.clone();
1825        let _sub = xml2.observe(move |txn, e| {
1826            attributes_c.store(Some(Arc::new(e.keys(txn).clone())));
1827            nodes_c.store(Some(Arc::new(e.delta(txn).to_vec())));
1828        });
1829
1830        {
1831            let t1 = d1.transact_mut();
1832            let mut t2 = d2.transact_mut();
1833            let sv = t2.state_vector();
1834            let mut encoder = EncoderV1::new();
1835            t1.encode_diff(&sv, &mut encoder);
1836            let update = Update::decode_v1(encoder.to_vec().as_slice()).unwrap();
1837            t2.apply_update(update).unwrap();
1838        }
1839        assert_eq!(
1840            nodes.swap(None),
1841            Some(Arc::new(vec![Change::Added(vec![
1842                Out::YXmlText(nested_txt),
1843                Out::YXmlElement(nested_xml2)
1844            ])]))
1845        );
1846        assert_eq!(
1847            attributes.swap(None),
1848            Some(Arc::new(HashMap::from([(
1849                "key1".into(),
1850                EntryChange::Inserted(Any::String("value11".into()).into())
1851            )])))
1852        );
1853    }
1854
1855    #[test]
1856    fn xml_to_string() {
1857        let doc = Doc::new();
1858        let f = doc.get_or_insert_xml_fragment("test");
1859        let mut txn = doc.transact_mut();
1860        let div = f.push_back(&mut txn, XmlElementPrelim::empty("div"));
1861        div.insert_attribute(&mut txn, "class", "t-button");
1862        let text = div.push_back(&mut txn, XmlTextPrelim::new("hello world"));
1863        text.format(
1864            &mut txn,
1865            6,
1866            5,
1867            Attrs::from([(
1868                "a".into(),
1869                HashMap::from([("href".into(), "http://domain.org")]).into(),
1870            )]),
1871        );
1872        drop(txn);
1873
1874        let str = f.get_string(&doc.transact());
1875        assert_eq!(
1876            str.as_str(),
1877            "<div class=\"t-button\">hello <a href=\"http://domain.org\">world</a></div>"
1878        )
1879    }
1880
1881    #[test]
1882    fn xml_to_string_2() {
1883        let doc = Doc::new();
1884        let f = doc.get_or_insert_xml_fragment("article");
1885        let xml = f.insert(&mut doc.transact_mut(), 0, XmlTextPrelim::new(""));
1886        let mut txn = doc.transact_mut();
1887
1888        let bold = Attrs::from([("b".into(), true.into())]);
1889        let italic = Attrs::from([("i".into(), true.into())]);
1890
1891        xml.insert(&mut txn, 0, "hello ");
1892        xml.insert_with_attributes(&mut txn, 6, "world", italic);
1893        xml.format(&mut txn, 0, 5, bold);
1894
1895        assert_eq!(xml.get_string(&txn), "<b>hello</b> <i>world</i>");
1896
1897        let remove_italic = Attrs::from([("i".into(), Any::Null)]);
1898        xml.format(&mut txn, 6, 5, remove_italic);
1899
1900        assert_eq!(xml.get_string(&txn), "<b>hello</b> world");
1901    }
1902
1903    #[test]
1904    fn format_attributes_decode_compatibility_v1() {
1905        let data = &[
1906            1, 6, 1, 0, 6, 1, 4, 116, 101, 115, 116, 1, 105, 4, 116, 114, 117, 101, 132, 1, 0, 6,
1907            104, 101, 108, 108, 111, 32, 132, 1, 6, 5, 119, 111, 114, 108, 100, 134, 1, 11, 1, 105,
1908            4, 110, 117, 108, 108, 198, 1, 6, 1, 7, 1, 98, 4, 116, 114, 117, 101, 134, 1, 12, 1,
1909            98, 4, 110, 117, 108, 108, 0,
1910        ];
1911        let update = Update::decode_v1(data).unwrap();
1912        let doc = Doc::new();
1913        let txt = doc.get_or_insert_text("test");
1914        let txt: &XmlTextRef = txt.as_ref();
1915        let mut txn = doc.transact_mut();
1916
1917        txn.apply_update(update).unwrap();
1918        assert_eq!(txt.get_string(&txn), "<i>hello </i><b><i>world</i></b>");
1919
1920        let actual = txn.encode_state_as_update_v1(&StateVector::default());
1921        assert_eq!(actual, data);
1922    }
1923
1924    #[test]
1925    fn format_attributes_decode_compatibility_v2() {
1926        let data = &[
1927            0, 3, 0, 3, 1, 2, 65, 5, 5, 0, 12, 10, 74, 12, 1, 14, 9, 6, 0, 132, 1, 134, 0, 198, 0,
1928            134, 26, 19, 116, 101, 115, 116, 105, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108,
1929            100, 105, 98, 98, 4, 1, 6, 5, 65, 1, 1, 1, 0, 0, 1, 6, 0, 120, 126, 120, 126, 0,
1930        ];
1931        let update = Update::decode_v2(data).unwrap();
1932        let doc = Doc::new();
1933        let txt = doc.get_or_insert_text("test");
1934        let txt: &XmlTextRef = txt.as_ref();
1935        let mut txn = doc.transact_mut();
1936
1937        txn.apply_update(update).unwrap();
1938        assert_eq!(txt.get_string(&txn), "<i>hello </i><b><i>world</i></b>");
1939
1940        let actual = txn.encode_state_as_update_v2(&StateVector::default());
1941        assert_eq!(actual, data);
1942    }
1943}