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, attr_name: K, attr_value: V)
1003    where
1004        K: Into<Arc<str>>,
1005        V: Into<String>,
1006    {
1007        let key = attr_name.into();
1008        let value = attr_value.into();
1009        let pos = {
1010            let branch = self.as_ref();
1011            let left = branch.map.get(&key);
1012            ItemPosition {
1013                parent: BranchPtr::from(branch).into(),
1014                left: left.cloned(),
1015                right: None,
1016                index: 0,
1017                current_attrs: None,
1018            }
1019        };
1020
1021        txn.create_item(&pos, value, Some(key));
1022    }
1023
1024    /// Returns a value of an attribute given its `attr_name`. Returns `None` if no such attribute
1025    /// can be found inside of a current XML element.
1026    fn get_attribute<T: ReadTxn>(&self, txn: &T, attr_name: &str) -> Option<String> {
1027        let branch = self.as_ref();
1028        let value = branch.get(txn, attr_name)?;
1029        Some(value.to_string(txn))
1030    }
1031
1032    /// Returns an unordered iterator over all attributes (key-value pairs), that can be found
1033    /// inside of a current XML element.
1034    fn attributes<'a, T: ReadTxn>(&'a self, txn: &'a T) -> Attributes<'a, &'a T, T> {
1035        Attributes(Entries::new(&self.as_ref().map, txn))
1036    }
1037
1038    fn siblings<'a, T: ReadTxn>(&self, txn: &'a T) -> Siblings<'a, T> {
1039        let ptr = BranchPtr::from(self.as_ref());
1040        Siblings::new(ptr.item, txn)
1041    }
1042}
1043
1044pub trait XmlFragment: AsRef<Branch> {
1045    fn first_child(&self) -> Option<XmlOut> {
1046        let first = self.as_ref().first()?;
1047        match &first.content {
1048            ItemContent::Type(c) => {
1049                let ptr = BranchPtr::from(c);
1050                XmlOut::try_from(ptr).ok()
1051            }
1052            _ => None,
1053        }
1054    }
1055
1056    /// Returns an iterator over all children of a current XML fragment.
1057    /// It does NOT include nested children of its children - for such cases use [Self::successors]
1058    /// iterator.
1059    fn children<'a, T: ReadTxn>(&self, txn: &'a T) -> XmlNodes<'a, T> {
1060        let iter = BlockIter::new(BranchPtr::from(self.as_ref()));
1061        XmlNodes::new(iter, txn)
1062    }
1063
1064    /// Returns a number of elements stored in current array.
1065    fn len<T: ReadTxn>(&self, _txn: &T) -> u32 {
1066        self.as_ref().len()
1067    }
1068
1069    /// Inserts a `value` at the given `index`. Inserting at index `0` is equivalent to prepending
1070    /// current array with given `value`, while inserting at array length is equivalent to appending
1071    /// that value at the end of it.
1072    ///
1073    /// Using `index` value that's higher than current array length results in panic.
1074    fn insert<V>(&self, txn: &mut TransactionMut, index: u32, xml_node: V) -> V::Return
1075    where
1076        V: XmlPrelim,
1077    {
1078        let ptr = self.as_ref().insert_at(txn, index, xml_node).unwrap(); // XML node is never empty
1079        if let Ok(integrated) = V::Return::try_from(ptr) {
1080            integrated
1081        } else {
1082            panic!("Defect: inserted XML element returned primitive value block")
1083        }
1084    }
1085
1086    /// Inserts given `value` at the end of the current array.
1087    fn push_back<V>(&self, txn: &mut TransactionMut, xml_node: V) -> V::Return
1088    where
1089        V: XmlPrelim,
1090    {
1091        let len = self.len(txn);
1092        self.insert(txn, len, xml_node)
1093    }
1094
1095    /// Inserts given `value` at the beginning of the current array.
1096    fn push_front<V>(&self, txn: &mut TransactionMut, xml_node: V) -> V::Return
1097    where
1098        V: XmlPrelim,
1099    {
1100        self.insert(txn, 0, xml_node)
1101    }
1102
1103    /// Removes a single element at provided `index`.
1104    fn remove(&self, txn: &mut TransactionMut, index: u32) {
1105        self.remove_range(txn, index, 1)
1106    }
1107
1108    /// Removes a range of elements from current array, starting at given `index` up until
1109    /// a particular number described by `len` has been deleted. This method panics in case when
1110    /// not all expected elements were removed (due to insufficient number of elements in an array)
1111    /// or `index` is outside the bounds of an array.
1112    fn remove_range(&self, txn: &mut TransactionMut, index: u32, len: u32) {
1113        let mut walker = BlockIter::new(BranchPtr::from(self.as_ref()));
1114        if walker.try_forward(txn, index) {
1115            walker.delete(txn, len)
1116        } else {
1117            panic!("Index {} is outside of the range of an array", index);
1118        }
1119    }
1120
1121    /// Retrieves a value stored at a given `index`. Returns `None` when provided index was out
1122    /// of the range of a current array.
1123    fn get<T: ReadTxn>(&self, _txn: &T, index: u32) -> Option<XmlOut> {
1124        let branch = self.as_ref();
1125        let (content, _) = branch.get_at(index)?;
1126        if let ItemContent::Type(inner) = content {
1127            let ptr: BranchPtr = inner.into();
1128            XmlOut::try_from(ptr).ok()
1129        } else {
1130            None
1131        }
1132    }
1133
1134    /// Returns an iterator that can be used to traverse over the successors of a current
1135    /// XML element. This includes recursive step over children of its children. The recursive
1136    /// iteration is depth-first.
1137    ///
1138    /// Example:
1139    /// ```
1140    /// /* construct node with a shape:
1141    ///    <div>
1142    ///       <p>Hello <b>world</b></p>
1143    ///       again
1144    ///    </div>
1145    /// */
1146    /// use yrs::{Doc, Text, Xml, XmlOut, Transact, XmlFragment, XmlElementPrelim, XmlTextPrelim, GetString};
1147    ///
1148    /// let doc = Doc::new();
1149    /// let mut html = doc.get_or_insert_xml_fragment("div");
1150    /// let mut txn = doc.transact_mut();
1151    /// let p = html.push_back(&mut txn, XmlElementPrelim::empty("p"));
1152    /// let txt = p.push_back(&mut txn, XmlTextPrelim::new("Hello "));
1153    /// let b = p.push_back(&mut txn, XmlElementPrelim::empty("b"));
1154    /// let txt = b.push_back(&mut txn, XmlTextPrelim::new("world"));
1155    /// let txt = html.push_back(&mut txn, XmlTextPrelim::new("again"));
1156    ///
1157    /// let mut result = Vec::new();
1158    /// for node in html.successors(&txn) {
1159    ///   let value = match node {
1160    ///       XmlOut::Element(elem) => elem.tag().to_string(),
1161    ///       XmlOut::Text(txt) => txt.get_string(&txn),
1162    ///       _ => panic!("shouldn't be the case here")
1163    ///   };
1164    ///   result.push(value);
1165    /// }
1166    /// assert_eq!(result, vec![
1167    ///   "p".to_string(),
1168    ///   "Hello ".to_string(),
1169    ///   "b".to_string(),
1170    ///   "world".to_string(),
1171    ///   "again".to_string()
1172    /// ]);
1173    /// ```
1174    fn successors<'a, T: ReadTxn>(&'a self, txn: &'a T) -> TreeWalker<'a, &'a T, T> {
1175        TreeWalker::new(self.as_ref(), txn)
1176    }
1177}
1178
1179/// Iterator over the attributes (key-value pairs represented as a strings) of an [XmlElement].
1180pub struct Attributes<'a, B, T>(Entries<'a, B, T>);
1181
1182impl<'a, B, T> Attributes<'a, B, T>
1183where
1184    B: Borrow<T>,
1185    T: ReadTxn,
1186{
1187    pub fn new(branch: &'a Branch, txn: B) -> Self {
1188        let entries = Entries::new(&branch.map, txn);
1189        Attributes(entries)
1190    }
1191}
1192
1193impl<'a, B, T> Iterator for Attributes<'a, B, T>
1194where
1195    B: Borrow<T>,
1196    T: ReadTxn,
1197{
1198    type Item = (&'a str, String);
1199
1200    fn next(&mut self) -> Option<Self::Item> {
1201        let (key, block) = self.0.next()?;
1202        let txn = self.0.txn.borrow();
1203        let value = block
1204            .content
1205            .get_last()
1206            .map(|v| v.to_string(txn))
1207            .unwrap_or(String::default());
1208        Some((key.as_ref(), value))
1209    }
1210}
1211
1212pub struct XmlNodes<'a, T> {
1213    iter: BlockIter,
1214    txn: &'a T,
1215}
1216
1217impl<'a, T: ReadTxn> XmlNodes<'a, T> {
1218    fn new(iter: BlockIter, txn: &'a T) -> Self {
1219        XmlNodes { iter, txn }
1220    }
1221}
1222
1223impl<'a, T: ReadTxn> Iterator for XmlNodes<'a, T> {
1224    type Item = XmlOut;
1225
1226    fn next(&mut self) -> Option<Self::Item> {
1227        let value = self.iter.read_value(self.txn)?;
1228        XmlOut::try_from(value).ok()
1229    }
1230}
1231
1232/// An iterator over [XmlElement] successors, working in a recursive depth-first manner.
1233pub struct TreeWalker<'a, B, T> {
1234    current: Option<&'a Item>,
1235    root: TypePtr,
1236    first_call: bool,
1237    _txn: B,
1238    _marker: PhantomData<T>,
1239}
1240
1241impl<'a, B, T: ReadTxn> TreeWalker<'a, B, T>
1242where
1243    B: Borrow<T>,
1244    T: ReadTxn,
1245{
1246    pub fn new(root: &'a Branch, txn: B) -> Self {
1247        TreeWalker {
1248            current: root.start.as_deref(),
1249            root: TypePtr::Branch(BranchPtr::from(root)),
1250            first_call: true,
1251            _txn: txn,
1252            _marker: PhantomData::default(),
1253        }
1254    }
1255}
1256
1257impl<'a, B, T: ReadTxn> Iterator for TreeWalker<'a, B, T>
1258where
1259    B: Borrow<T>,
1260    T: ReadTxn,
1261{
1262    type Item = XmlOut;
1263
1264    /// Tree walker used depth-first search to move over the xml tree.
1265    fn next(&mut self) -> Option<Self::Item> {
1266        fn try_descend(item: &Item) -> Option<&Item> {
1267            if let ItemContent::Type(t) = &item.content {
1268                let inner = t.as_ref();
1269                match inner.type_ref() {
1270                    TypeRef::XmlElement(_) | TypeRef::XmlFragment if !item.is_deleted() => {
1271                        return inner.start.as_deref();
1272                    }
1273                    _ => { /* do nothing */ }
1274                }
1275            }
1276
1277            None
1278        }
1279
1280        let mut result = None;
1281        let mut n = self.current.take();
1282        if let Some(current) = n {
1283            if !self.first_call || current.is_deleted() {
1284                while {
1285                    if let Some(current) = n {
1286                        if let Some(ptr) = try_descend(current) {
1287                            // depth-first search - try walk down the tree first
1288                            n = Some(ptr);
1289                        } else {
1290                            // walk right or up in the tree
1291                            while let Some(current) = n {
1292                                if let Some(right) = current.right.as_ref() {
1293                                    n = Some(right);
1294                                    break;
1295                                } else if current.parent == self.root {
1296                                    n = None;
1297                                } else {
1298                                    let ptr = current.parent.as_branch().unwrap();
1299                                    n = ptr.item.as_deref();
1300                                }
1301                            }
1302                        }
1303                    }
1304                    if let Some(current) = n {
1305                        current.is_deleted()
1306                    } else {
1307                        false
1308                    }
1309                } {}
1310            }
1311            self.first_call = false;
1312            self.current = n;
1313        }
1314        if let Some(current) = self.current {
1315            if let ItemContent::Type(t) = &current.content {
1316                result = XmlOut::try_from(BranchPtr::from(t)).ok();
1317            }
1318        }
1319        result
1320    }
1321}
1322
1323/// Event generated by [XmlText::observe] method. Emitted during transaction commit phase.
1324pub struct XmlTextEvent {
1325    pub(crate) current_target: BranchPtr,
1326    target: XmlTextRef,
1327    delta: UnsafeCell<Option<Vec<Delta>>>,
1328    keys: UnsafeCell<Result<HashMap<Arc<str>, EntryChange>, HashSet<Option<Arc<str>>>>>,
1329}
1330
1331impl XmlTextEvent {
1332    pub(crate) fn new(branch_ref: BranchPtr, key_changes: HashSet<Option<Arc<str>>>) -> Self {
1333        let current_target = branch_ref.clone();
1334        let target = XmlTextRef::from(branch_ref);
1335        XmlTextEvent {
1336            target,
1337            current_target,
1338            delta: UnsafeCell::new(None),
1339            keys: UnsafeCell::new(Err(key_changes)),
1340        }
1341    }
1342
1343    /// Returns a [XmlText] instance which emitted this event.
1344    pub fn target(&self) -> &XmlTextRef {
1345        &self.target
1346    }
1347
1348    /// Returns a path from root type down to [XmlText] instance which emitted this event.
1349    pub fn path(&self) -> Path {
1350        Branch::path(self.current_target, self.target.0)
1351    }
1352
1353    /// Returns a summary of text changes made over corresponding [XmlText] collection within
1354    /// bounds of current transaction.
1355    pub fn delta(&self, txn: &TransactionMut) -> &[Delta] {
1356        let delta = unsafe { self.delta.get().as_mut().unwrap() };
1357        delta
1358            .get_or_insert_with(|| TextEvent::get_delta(self.target.0, txn))
1359            .as_slice()
1360    }
1361
1362    /// Returns a summary of attribute changes made over corresponding [XmlText] collection within
1363    /// bounds of current transaction.
1364    pub fn keys(&self, txn: &TransactionMut) -> &HashMap<Arc<str>, EntryChange> {
1365        let keys = unsafe { self.keys.get().as_mut().unwrap() };
1366
1367        match keys {
1368            Ok(keys) => {
1369                return keys;
1370            }
1371            Err(subs) => {
1372                let subs = event_keys(txn, self.target.0, subs);
1373                *keys = Ok(subs);
1374                if let Ok(keys) = keys {
1375                    keys
1376                } else {
1377                    panic!("Defect: should not happen");
1378                }
1379            }
1380        }
1381    }
1382}
1383
1384pub struct Siblings<'a, T> {
1385    current: Option<ItemPtr>,
1386    _txn: &'a T,
1387}
1388
1389impl<'a, T> Siblings<'a, T> {
1390    fn new(current: Option<ItemPtr>, txn: &'a T) -> Self {
1391        Siblings { current, _txn: txn }
1392    }
1393}
1394
1395impl<'a, T> Iterator for Siblings<'a, T> {
1396    type Item = XmlOut;
1397
1398    fn next(&mut self) -> Option<Self::Item> {
1399        while let Some(item) = self.current.as_deref() {
1400            self.current = item.right;
1401            if let Some(right) = self.current.as_deref() {
1402                if !right.is_deleted() {
1403                    if let ItemContent::Type(inner) = &right.content {
1404                        let ptr = BranchPtr::from(inner);
1405                        return XmlOut::try_from(ptr).ok();
1406                    }
1407                }
1408            }
1409        }
1410
1411        None
1412    }
1413}
1414
1415impl<'a, T> DoubleEndedIterator for Siblings<'a, T> {
1416    fn next_back(&mut self) -> Option<Self::Item> {
1417        while let Some(item) = self.current.as_deref() {
1418            self.current = item.left;
1419            if let Some(left) = self.current.as_deref() {
1420                if !left.is_deleted() {
1421                    if let ItemContent::Type(inner) = &left.content {
1422                        let ptr = BranchPtr::from(inner);
1423                        return XmlOut::try_from(ptr).ok();
1424                    }
1425                }
1426            }
1427        }
1428
1429        None
1430    }
1431}
1432
1433/// Event generated by [XmlElement::observe] method. Emitted during transaction commit phase.
1434pub struct XmlEvent {
1435    pub(crate) current_target: BranchPtr,
1436    target: XmlOut,
1437    change_set: UnsafeCell<Option<Box<ChangeSet<Change>>>>,
1438    keys: UnsafeCell<Result<HashMap<Arc<str>, EntryChange>, HashSet<Option<Arc<str>>>>>,
1439    children_changed: bool,
1440}
1441
1442impl XmlEvent {
1443    pub(crate) fn new(branch_ref: BranchPtr, key_changes: HashSet<Option<Arc<str>>>) -> Self {
1444        let current_target = branch_ref.clone();
1445        let children_changed = key_changes.iter().any(Option::is_none);
1446        XmlEvent {
1447            target: XmlOut::try_from(branch_ref).unwrap(),
1448            current_target,
1449            change_set: UnsafeCell::new(None),
1450            keys: UnsafeCell::new(Err(key_changes)),
1451            children_changed,
1452        }
1453    }
1454
1455    /// True if any child XML nodes have been changed within bounds of current transaction.
1456    pub fn children_changed(&self) -> bool {
1457        self.children_changed
1458    }
1459
1460    /// Returns a [XmlElement] instance which emitted this event.
1461    pub fn target(&self) -> &XmlOut {
1462        &self.target
1463    }
1464
1465    /// Returns a path from root type down to [XmlElement] instance which emitted this event.
1466    pub fn path(&self) -> Path {
1467        Branch::path(self.current_target, self.target.as_ptr())
1468    }
1469
1470    /// Returns a summary of XML child nodes changed within corresponding [XmlElement] collection
1471    /// within bounds of current transaction.
1472    pub fn delta(&self, txn: &TransactionMut) -> &[Change] {
1473        self.changes(txn).delta.as_slice()
1474    }
1475
1476    /// Returns a collection of block identifiers that have been added within a bounds of
1477    /// current transaction.
1478    pub fn added(&self, txn: &TransactionMut) -> &HashSet<ID> {
1479        &self.changes(txn).added
1480    }
1481
1482    /// Returns a collection of block identifiers that have been removed within a bounds of
1483    /// current transaction.
1484    pub fn deleted(&self, txn: &TransactionMut) -> &HashSet<ID> {
1485        &self.changes(txn).deleted
1486    }
1487
1488    /// Returns a summary of attribute changes made over corresponding [XmlElement] collection
1489    /// within bounds of current transaction.
1490    pub fn keys(&self, txn: &TransactionMut) -> &HashMap<Arc<str>, EntryChange> {
1491        let keys = unsafe { self.keys.get().as_mut().unwrap() };
1492
1493        match keys {
1494            Ok(keys) => keys,
1495            Err(subs) => {
1496                let subs = event_keys(txn, self.target.as_ptr(), subs);
1497                *keys = Ok(subs);
1498                if let Ok(keys) = keys {
1499                    keys
1500                } else {
1501                    panic!("Defect: should not happen");
1502                }
1503            }
1504        }
1505    }
1506
1507    fn changes(&self, txn: &TransactionMut) -> &ChangeSet<Change> {
1508        let change_set = unsafe { self.change_set.get().as_mut().unwrap() };
1509        change_set
1510            .get_or_insert_with(|| Box::new(event_change_set(txn, self.target.as_ptr().start)))
1511    }
1512}
1513
1514#[cfg(test)]
1515mod test {
1516    use std::collections::HashMap;
1517    use std::sync::Arc;
1518
1519    use arc_swap::ArcSwapOption;
1520
1521    use crate::test_utils::exchange_updates;
1522    use crate::transaction::ReadTxn;
1523    use crate::types::xml::{Xml, XmlFragment, XmlOut};
1524    use crate::types::{Attrs, Change, EntryChange, Out};
1525    use crate::updates::decoder::Decode;
1526    use crate::updates::encoder::{Encoder, EncoderV1};
1527    use crate::{
1528        Any, Doc, GetString, Observable, SharedRef, StateVector, Text, Transact, Update,
1529        XmlElementPrelim, XmlTextPrelim, XmlTextRef,
1530    };
1531
1532    #[test]
1533    fn insert_attribute() {
1534        let d1 = Doc::with_client_id(1);
1535        let f = d1.get_or_insert_xml_fragment("xml");
1536        let mut t1 = d1.transact_mut();
1537        let xml1 = f.push_back(&mut t1, XmlElementPrelim::empty("div"));
1538        xml1.insert_attribute(&mut t1, "height", 10.to_string());
1539        assert_eq!(xml1.get_attribute(&t1, "height"), Some("10".to_string()));
1540
1541        let d2 = Doc::with_client_id(1);
1542        let f = d2.get_or_insert_xml_fragment("xml");
1543        let mut t2 = d2.transact_mut();
1544        let xml2 = f.push_back(&mut t2, XmlElementPrelim::empty("div"));
1545        let u = t1.encode_state_as_update_v1(&StateVector::default());
1546        let u = Update::decode_v1(u.as_slice()).unwrap();
1547        t2.apply_update(u).unwrap();
1548        assert_eq!(xml2.get_attribute(&t2, "height"), Some("10".to_string()));
1549    }
1550
1551    #[test]
1552    fn tree_walker() {
1553        let doc = Doc::with_client_id(1);
1554        let root = doc.get_or_insert_xml_fragment("xml");
1555        let mut txn = doc.transact_mut();
1556        /*
1557            <UNDEFINED>
1558                <p>{txt1}{txt2}</p>
1559                <p></p>
1560                <img/>
1561            </UNDEFINED>
1562        */
1563        let p1 = root.push_back(&mut txn, XmlElementPrelim::empty("p"));
1564        p1.push_back(&mut txn, XmlTextPrelim::new(""));
1565        p1.push_back(&mut txn, XmlTextPrelim::new(""));
1566        let p2 = root.push_back(&mut txn, XmlElementPrelim::empty("p"));
1567        root.push_back(&mut txn, XmlElementPrelim::empty("img"));
1568
1569        let all_paragraphs = root.successors(&txn).filter_map(|n| match n {
1570            XmlOut::Element(e) if e.tag() == &"p".into() => Some(e),
1571            _ => None,
1572        });
1573        let actual: Vec<_> = all_paragraphs.collect();
1574
1575        assert_eq!(
1576            actual.len(),
1577            2,
1578            "query selector should found two paragraphs"
1579        );
1580        assert_eq!(
1581            actual[0].hook(),
1582            p1.hook(),
1583            "query selector found 1st paragraph"
1584        );
1585        assert_eq!(
1586            actual[1].hook(),
1587            p2.hook(),
1588            "query selector found 2nd paragraph"
1589        );
1590    }
1591
1592    #[test]
1593    fn text_attributes() {
1594        let doc = Doc::with_client_id(1);
1595        let f = doc.get_or_insert_xml_fragment("test");
1596        let mut txn = doc.transact_mut();
1597        let txt = f.push_back(&mut txn, XmlTextPrelim::new(""));
1598        txt.insert_attribute(&mut txn, "test", 42.to_string());
1599
1600        assert_eq!(txt.get_attribute(&txn, "test"), Some("42".to_string()));
1601        let actual: Vec<_> = txt.attributes(&txn).collect();
1602        assert_eq!(actual, vec![("test", "42".to_string())]);
1603    }
1604
1605    #[test]
1606    fn siblings() {
1607        let doc = Doc::with_client_id(1);
1608        let root = doc.get_or_insert_xml_fragment("root");
1609        let mut txn = doc.transact_mut();
1610        let first = root.push_back(&mut txn, XmlTextPrelim::new("hello"));
1611        let second = root.push_back(&mut txn, XmlElementPrelim::empty("p"));
1612
1613        assert_eq!(
1614            &first.siblings(&txn).next().unwrap().id(),
1615            second.hook().id(),
1616            "first.next_sibling should point to second"
1617        );
1618        assert_eq!(
1619            &second.siblings(&txn).next_back().unwrap().id(),
1620            first.hook().id(),
1621            "second.prev_sibling should point to first"
1622        );
1623        assert_eq!(
1624            &first.parent().unwrap().id(),
1625            root.hook().id(),
1626            "first.parent should point to root"
1627        );
1628        assert!(root.parent().is_none(), "root parent should not exist");
1629        assert_eq!(
1630            &root.first_child().unwrap().id(),
1631            first.hook().id(),
1632            "root.first_child should point to first"
1633        );
1634    }
1635
1636    #[test]
1637    fn serialization() {
1638        let d1 = Doc::with_client_id(1);
1639        let r1 = d1.get_or_insert_xml_fragment("root");
1640        let mut t1 = d1.transact_mut();
1641        let _first = r1.push_back(&mut t1, XmlTextPrelim::new("hello"));
1642        r1.push_back(&mut t1, XmlElementPrelim::empty("p"));
1643
1644        let expected = "hello<p></p>";
1645        assert_eq!(r1.get_string(&t1), expected);
1646
1647        let u1 = t1.encode_state_as_update_v1(&StateVector::default());
1648
1649        let d2 = Doc::with_client_id(2);
1650        let r2 = d2.get_or_insert_xml_fragment("root");
1651        let mut t2 = d2.transact_mut();
1652
1653        let u1 = Update::decode_v1(u1.as_slice()).unwrap();
1654        t2.apply_update(u1).unwrap();
1655        assert_eq!(r2.get_string(&t2), expected);
1656    }
1657
1658    #[test]
1659    fn serialization_compatibility() {
1660        let d1 = Doc::with_client_id(1);
1661        let r1 = d1.get_or_insert_xml_fragment("root");
1662        let mut t1 = d1.transact_mut();
1663        let _first = r1.push_back(&mut t1, XmlTextPrelim::new("hello"));
1664        r1.push_back(&mut t1, XmlElementPrelim::empty("p"));
1665
1666        /* This binary is result of following Yjs code (matching Rust code above):
1667        ```js
1668            let d1 = new Y.Doc()
1669            d1.clientID = 1
1670            let root = d1.get('root', Y.XmlElement)
1671            let first = new Y.XmlText()
1672            first.insert(0, 'hello')
1673            let second = new Y.XmlElement('p')
1674            root.insert(0, [first,second])
1675
1676            let expected = Y.encodeStateAsUpdate(d1)
1677        ``` */
1678        let expected = &[
1679            1, 3, 1, 0, 7, 1, 4, 114, 111, 111, 116, 6, 4, 0, 1, 0, 5, 104, 101, 108, 108, 111,
1680            135, 1, 0, 3, 1, 112, 0,
1681        ];
1682        let u1 = t1.encode_state_as_update_v1(&StateVector::default());
1683        assert_eq!(u1.as_slice(), expected);
1684    }
1685
1686    #[test]
1687    fn event_observers() {
1688        let d1 = Doc::with_client_id(1);
1689        let f = d1.get_or_insert_xml_fragment("xml");
1690        let xml = f.insert(&mut d1.transact_mut(), 0, XmlElementPrelim::empty("test"));
1691
1692        let d2 = Doc::with_client_id(2);
1693        let f = d2.get_or_insert_xml_fragment("xml");
1694        exchange_updates(&[&d1, &d2]);
1695        let xml2 = f
1696            .get(&d2.transact(), 0)
1697            .unwrap()
1698            .into_xml_element()
1699            .unwrap();
1700
1701        let attributes = Arc::new(ArcSwapOption::default());
1702        let nodes = Arc::new(ArcSwapOption::default());
1703        let attributes_c = attributes.clone();
1704        let nodes_c = nodes.clone();
1705        let _sub = xml.observe(move |txn, e| {
1706            attributes_c.store(Some(Arc::new(e.keys(txn).clone())));
1707            nodes_c.store(Some(Arc::new(e.delta(txn).to_vec())));
1708        });
1709
1710        // insert attribute
1711        {
1712            let mut txn = d1.transact_mut();
1713            xml.insert_attribute(&mut txn, "key1", "value1");
1714            xml.insert_attribute(&mut txn, "key2", "value2");
1715        }
1716        assert!(nodes.swap(None).unwrap().is_empty());
1717        assert_eq!(
1718            attributes.swap(None),
1719            Some(Arc::new(HashMap::from([
1720                (
1721                    "key1".into(),
1722                    EntryChange::Inserted(Any::String("value1".into()).into())
1723                ),
1724                (
1725                    "key2".into(),
1726                    EntryChange::Inserted(Any::String("value2".into()).into())
1727                )
1728            ])))
1729        );
1730
1731        // change and remove attribute
1732        {
1733            let mut txn = d1.transact_mut();
1734            xml.insert_attribute(&mut txn, "key1", "value11");
1735            xml.remove_attribute(&mut txn, &"key2");
1736        }
1737        assert!(nodes.swap(None).unwrap().is_empty());
1738        assert_eq!(
1739            attributes.swap(None),
1740            Some(Arc::new(HashMap::from([
1741                (
1742                    "key1".into(),
1743                    EntryChange::Updated(
1744                        Any::String("value1".into()).into(),
1745                        Any::String("value11".into()).into()
1746                    )
1747                ),
1748                (
1749                    "key2".into(),
1750                    EntryChange::Removed(Any::String("value2".into()).into())
1751                )
1752            ])))
1753        );
1754
1755        // add xml elements
1756        let (nested_txt, nested_xml) = {
1757            let mut txn = d1.transact_mut();
1758            let txt = xml.insert(&mut txn, 0, XmlTextPrelim::new(""));
1759            let xml2 = xml.insert(&mut txn, 1, XmlElementPrelim::empty("div"));
1760            (txt, xml2)
1761        };
1762        assert_eq!(
1763            nodes.swap(None),
1764            Some(Arc::new(vec![Change::Added(vec![
1765                Out::YXmlText(nested_txt.clone()),
1766                Out::YXmlElement(nested_xml.clone())
1767            ])]))
1768        );
1769        assert_eq!(attributes.swap(None), Some(HashMap::new().into()));
1770
1771        // remove and add
1772        let nested_xml2 = {
1773            let mut txn = d1.transact_mut();
1774            xml.remove_range(&mut txn, 1, 1);
1775            xml.insert(&mut txn, 1, XmlElementPrelim::empty("p"))
1776        };
1777        assert_eq!(
1778            nodes.swap(None),
1779            Some(Arc::new(vec![
1780                Change::Retain(1),
1781                Change::Added(vec![Out::YXmlElement(nested_xml2.clone())]),
1782                Change::Removed(1),
1783            ]))
1784        );
1785        assert_eq!(attributes.swap(None), Some(HashMap::new().into()));
1786
1787        // copy updates over
1788        let attributes = Arc::new(ArcSwapOption::default());
1789        let nodes = Arc::new(ArcSwapOption::default());
1790        let attributes_c = attributes.clone();
1791        let nodes_c = nodes.clone();
1792        let _sub = xml2.observe(move |txn, e| {
1793            attributes_c.store(Some(Arc::new(e.keys(txn).clone())));
1794            nodes_c.store(Some(Arc::new(e.delta(txn).to_vec())));
1795        });
1796
1797        {
1798            let t1 = d1.transact_mut();
1799            let mut t2 = d2.transact_mut();
1800            let sv = t2.state_vector();
1801            let mut encoder = EncoderV1::new();
1802            t1.encode_diff(&sv, &mut encoder);
1803            let update = Update::decode_v1(encoder.to_vec().as_slice()).unwrap();
1804            t2.apply_update(update).unwrap();
1805        }
1806        assert_eq!(
1807            nodes.swap(None),
1808            Some(Arc::new(vec![Change::Added(vec![
1809                Out::YXmlText(nested_txt),
1810                Out::YXmlElement(nested_xml2)
1811            ])]))
1812        );
1813        assert_eq!(
1814            attributes.swap(None),
1815            Some(Arc::new(HashMap::from([(
1816                "key1".into(),
1817                EntryChange::Inserted(Any::String("value11".into()).into())
1818            )])))
1819        );
1820    }
1821
1822    #[test]
1823    fn xml_to_string() {
1824        let doc = Doc::new();
1825        let f = doc.get_or_insert_xml_fragment("test");
1826        let mut txn = doc.transact_mut();
1827        let div = f.push_back(&mut txn, XmlElementPrelim::empty("div"));
1828        div.insert_attribute(&mut txn, "class", "t-button");
1829        let text = div.push_back(&mut txn, XmlTextPrelim::new("hello world"));
1830        text.format(
1831            &mut txn,
1832            6,
1833            5,
1834            Attrs::from([(
1835                "a".into(),
1836                HashMap::from([("href".into(), "http://domain.org")]).into(),
1837            )]),
1838        );
1839        drop(txn);
1840
1841        let str = f.get_string(&doc.transact());
1842        assert_eq!(
1843            str.as_str(),
1844            "<div class=\"t-button\">hello <a href=\"http://domain.org\">world</a></div>"
1845        )
1846    }
1847
1848    #[test]
1849    fn xml_to_string_2() {
1850        let doc = Doc::new();
1851        let f = doc.get_or_insert_xml_fragment("article");
1852        let xml = f.insert(&mut doc.transact_mut(), 0, XmlTextPrelim::new(""));
1853        let mut txn = doc.transact_mut();
1854
1855        let bold = Attrs::from([("b".into(), true.into())]);
1856        let italic = Attrs::from([("i".into(), true.into())]);
1857
1858        xml.insert(&mut txn, 0, "hello ");
1859        xml.insert_with_attributes(&mut txn, 6, "world", italic);
1860        xml.format(&mut txn, 0, 5, bold);
1861
1862        assert_eq!(xml.get_string(&txn), "<b>hello</b> <i>world</i>");
1863
1864        let remove_italic = Attrs::from([("i".into(), Any::Null)]);
1865        xml.format(&mut txn, 6, 5, remove_italic);
1866
1867        assert_eq!(xml.get_string(&txn), "<b>hello</b> world");
1868    }
1869
1870    #[test]
1871    fn format_attributes_decode_compatibility_v1() {
1872        let data = &[
1873            1, 6, 1, 0, 6, 1, 4, 116, 101, 115, 116, 1, 105, 4, 116, 114, 117, 101, 132, 1, 0, 6,
1874            104, 101, 108, 108, 111, 32, 132, 1, 6, 5, 119, 111, 114, 108, 100, 134, 1, 11, 1, 105,
1875            4, 110, 117, 108, 108, 198, 1, 6, 1, 7, 1, 98, 4, 116, 114, 117, 101, 134, 1, 12, 1,
1876            98, 4, 110, 117, 108, 108, 0,
1877        ];
1878        let update = Update::decode_v1(data).unwrap();
1879        let doc = Doc::new();
1880        let txt = doc.get_or_insert_text("test");
1881        let txt: &XmlTextRef = txt.as_ref();
1882        let mut txn = doc.transact_mut();
1883
1884        txn.apply_update(update).unwrap();
1885        assert_eq!(txt.get_string(&txn), "<i>hello </i><b><i>world</i></b>");
1886
1887        let actual = txn.encode_state_as_update_v1(&StateVector::default());
1888        assert_eq!(actual, data);
1889    }
1890
1891    #[test]
1892    fn format_attributes_decode_compatibility_v2() {
1893        let data = &[
1894            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,
1895            134, 26, 19, 116, 101, 115, 116, 105, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108,
1896            100, 105, 98, 98, 4, 1, 6, 5, 65, 1, 1, 1, 0, 0, 1, 6, 0, 120, 126, 120, 126, 0,
1897        ];
1898        let update = Update::decode_v2(data).unwrap();
1899        let doc = Doc::new();
1900        let txt = doc.get_or_insert_text("test");
1901        let txt: &XmlTextRef = txt.as_ref();
1902        let mut txn = doc.transact_mut();
1903
1904        txn.apply_update(update).unwrap();
1905        assert_eq!(txt.get_string(&txn), "<i>hello </i><b><i>world</i></b>");
1906
1907        let actual = txn.encode_state_as_update_v2(&StateVector::default());
1908        assert_eq!(actual, data);
1909    }
1910}