Skip to main content

yrs/types/
text.rs

1use crate::block::{Block, EmbedPrelim, Item, ItemContent, ItemPosition, ItemPtr, Prelim, Unused};
2use crate::transaction::TransactionMut;
3use crate::types::{
4    AsPrelim, Attrs, Branch, BranchPtr, DefaultPrelim, Delta, Out, Path, RootRef, SharedRef,
5    TypePtr, TypeRef,
6};
7use crate::utils::OptionExt;
8use crate::*;
9use std::cell::UnsafeCell;
10use std::collections::HashMap;
11use std::convert::{TryFrom, TryInto};
12use std::fmt::Formatter;
13use std::ops::{Deref, DerefMut};
14
15/// A shared data type used for collaborative text editing. It enables multiple users to add and
16/// remove chunks of text in efficient manner. This type is internally represented as a mutable
17/// double-linked list of text chunks - an optimization occurs during [Transaction::commit], which
18/// allows to squash multiple consecutively inserted characters together as a single chunk of text
19/// even between transaction boundaries in order to preserve more efficient memory model.
20///
21/// [TextRef] structure internally uses UTF-8 encoding and its length is described in a number of
22/// bytes rather than individual characters (a single UTF-8 code point can consist of many bytes).
23///
24/// Like all Yrs shared data types, [TextRef] is resistant to the problem of interleaving (situation
25/// when characters inserted one after another may interleave with other peers concurrent inserts
26/// after merging all updates together). In case of Yrs conflict resolution is solved by using
27/// unique document id to determine correct and consistent ordering.
28///
29/// [TextRef] offers a rich text editing capabilities (it's not limited to simple text operations).
30/// Actions like embedding objects, binaries (eg. images) and formatting attributes are all possible
31/// using [TextRef].
32///
33/// Keep in mind that [TextRef::get_string] method returns a raw string, stripped of formatting
34/// attributes or embedded objects. If there's a need to include them, use [TextRef::diff] method
35/// instead.
36///
37/// Another note worth reminding is that human-readable numeric indexes are not good for maintaining
38/// cursor positions in rich text documents with real-time collaborative capabilities. In such cases
39/// any concurrent update incoming and applied from the remote peer may change the order of elements
40/// in current [TextRef], invalidating numeric index. For such cases you can take advantage of fact
41/// that [TextRef] implements [IndexedSequence::sticky_index] method that returns a
42/// [permanent index](StickyIndex) position that sticks to the same place even when concurrent
43/// updates are being made.
44///
45/// # Example
46///
47/// ```rust
48/// use yrs::{Any, Array, ArrayPrelim, Doc, GetString, Text, Transact};
49/// use yrs::types::Attrs;
50/// use yrs::types::text::{Diff, YChange};
51///
52/// let doc = Doc::new();
53/// let text = doc.get_or_insert_text("article");
54/// let mut txn = doc.transact_mut();
55///
56/// let bold = Attrs::from([("b".into(), true.into())]);
57/// let italic = Attrs::from([("i".into(), true.into())]);
58///
59/// text.insert(&mut txn, 0, "hello ");
60/// text.insert_with_attributes(&mut txn, 6, "world", italic.clone());
61/// text.format(&mut txn, 0, 5, bold.clone());
62///
63/// let chunks = text.diff(&txn, YChange::identity);
64/// assert_eq!(chunks, vec![
65///     Diff::new("hello".into(), Some(Box::new(bold.clone()))),
66///     Diff::new(" ".into(), None),
67///     Diff::new("world".into(), Some(Box::new(italic))),
68/// ]);
69///
70/// // remove formatting
71/// let remove_italic = Attrs::from([("i".into(), Any::Null)]);
72/// text.format(&mut txn, 6, 5, remove_italic);
73///
74/// let chunks = text.diff(&txn, YChange::identity);
75/// assert_eq!(chunks, vec![
76///     Diff::new("hello".into(), Some(Box::new(bold.clone()))),
77///     Diff::new(" world".into(), None),
78/// ]);
79///
80/// // insert binary payload eg. images
81/// let image = b"deadbeaf".to_vec();
82/// text.insert_embed(&mut txn, 1, image);
83///
84/// // insert nested shared type eg. table as ArrayRef of ArrayRefs
85/// let table = text.insert_embed(&mut txn, 5, ArrayPrelim::default());
86/// let header = table.insert(&mut txn, 0, ArrayPrelim::from(["Book title", "Author"]));
87/// let row = table.insert(&mut txn, 1, ArrayPrelim::from(["\"Moby-Dick\"", "Herman Melville"]));
88/// ```
89#[repr(transparent)]
90#[derive(Debug, Clone)]
91pub struct TextRef(BranchPtr);
92
93impl RootRef for TextRef {
94    fn type_ref() -> TypeRef {
95        TypeRef::Text
96    }
97}
98impl SharedRef for TextRef {}
99impl Text for TextRef {}
100impl IndexedSequence for TextRef {}
101#[cfg(feature = "weak")]
102impl crate::Quotable for TextRef {}
103
104impl AsRef<XmlTextRef> for TextRef {
105    #[inline]
106    fn as_ref(&self) -> &XmlTextRef {
107        unsafe { std::mem::transmute(self) }
108    }
109}
110
111impl DeepObservable for TextRef {}
112impl Observable for TextRef {
113    type Event = TextEvent;
114}
115
116impl GetString for TextRef {
117    /// Converts context of this text data structure into a single string value. This method doesn't
118    /// render formatting attributes or embedded content. In order to retrieve it, use
119    /// [TextRef::diff] method.
120    fn get_string<T: ReadTxn>(&self, _txn: &T) -> String {
121        let mut start = self.0.start;
122        let mut s = String::new();
123        while let Some(item) = start.as_deref() {
124            if !item.is_deleted() {
125                if let ItemContent::String(item_string) = &item.content {
126                    s.push_str(item_string);
127                }
128            }
129            start = item.right.clone();
130        }
131        s
132    }
133}
134
135impl TryFrom<ItemPtr> for TextRef {
136    type Error = ItemPtr;
137
138    fn try_from(value: ItemPtr) -> Result<Self, Self::Error> {
139        if let Some(branch) = value.clone().as_branch() {
140            Ok(TextRef::from(branch))
141        } else {
142            Err(value)
143        }
144    }
145}
146
147impl TryFrom<Out> for TextRef {
148    type Error = Out;
149
150    fn try_from(value: Out) -> Result<Self, Self::Error> {
151        match value {
152            Out::YText(value) => Ok(value),
153            other => Err(other),
154        }
155    }
156}
157
158pub trait Text: AsRef<Branch> + Sized {
159    /// Returns a number of characters visible in a current text data structure.
160    fn len<T: ReadTxn>(&self, _txn: &T) -> u32 {
161        self.as_ref().content_len
162    }
163
164    /// Inserts a `chunk` of text at a given `index`.
165    /// If `index` is `0`, this `chunk` will be inserted at the beginning of a current text.
166    /// If `index` is equal to current data structure length, this `chunk` will be appended at
167    /// the end of it.
168    ///
169    /// This method will panic if provided `index` is greater than the length of a current text.
170    ///
171    /// # Examples
172    ///
173    /// By default Document uses byte offset:
174    ///
175    /// ```
176    /// use yrs::{Doc, Text, GetString, Transact};
177    ///
178    /// let doc = Doc::new();
179    /// let ytext = doc.get_or_insert_text("text");
180    /// let txn = &mut doc.transact_mut();
181    /// ytext.push(txn, "Hi ★ to you");
182    ///
183    /// // The same as `String::len()`
184    /// assert_eq!(ytext.len(txn), 13);
185    ///
186    /// // To insert you have to count bytes and not chars.
187    /// ytext.insert(txn, 6, "!");
188    /// assert_eq!(ytext.get_string(txn), "Hi ★! to you");
189    /// ```
190    ///
191    /// You can override how Yrs calculates the index with [OffsetKind]:
192    ///
193    /// ```
194    /// use yrs::{Doc, Options, Text, GetString, Transact, OffsetKind};
195    ///
196    /// let doc = Doc::with_options(Options {
197    ///     offset_kind: OffsetKind::Utf16,
198    ///     ..Default::default()
199    /// });
200    /// let ytext = doc.get_or_insert_text("text");
201    /// let txn = &mut doc.transact_mut();
202    /// ytext.push(txn, "Hi ★ to you");
203    ///
204    /// // The same as `String::chars()::count()`
205    /// assert_eq!(ytext.len(txn), 11);
206    ///
207    /// // To insert you have to count chars.
208    /// ytext.insert(txn, 4, "!");
209    /// assert_eq!(ytext.get_string(txn), "Hi ★! to you");
210    /// ```
211    ///
212    fn insert(&self, txn: &mut TransactionMut, index: u32, chunk: &str) {
213        if chunk.is_empty() {
214            return;
215        }
216        let this = BranchPtr::from(self.as_ref());
217        if let Some(mut pos) = find_position(this, txn, index) {
218            let value = crate::block::PrelimString(chunk.into());
219            while let Some(right) = pos.right.as_ref() {
220                if right.is_deleted() {
221                    // skip over deleted blocks, just like Yjs does
222                    pos.forward();
223                } else {
224                    break;
225                }
226            }
227            txn.create_item(&pos, value, None);
228        } else {
229            panic!("The type or the position doesn't exist!");
230        }
231    }
232
233    fn apply_delta<D, P>(&self, txn: &mut TransactionMut, delta: D)
234    where
235        D: IntoIterator<Item = Delta<P>>,
236        P: Prelim,
237    {
238        let branch = BranchPtr::from(self.as_ref());
239        let mut pos = ItemPosition {
240            parent: TypePtr::Branch(branch),
241            left: None,
242            right: branch.start,
243            index: 0,
244            current_attrs: Some(Box::new(Attrs::new())),
245        };
246        for delta in delta {
247            match delta {
248                Delta::Inserted(value, attrs) => {
249                    let attrs: Attrs = match attrs {
250                        None => Attrs::new(),
251                        Some(attrs) => *attrs,
252                    };
253                    insert(branch, txn, &mut pos, DeltaChunk(value), attrs);
254                }
255                Delta::Deleted(len) => remove(txn, &mut pos, len),
256                Delta::Retain(len, attrs) => {
257                    let attrs: Attrs = match attrs {
258                        None => Attrs::new(),
259                        Some(attrs) => *attrs,
260                    };
261                    insert_format(branch, txn, &mut pos, len, attrs);
262                }
263            }
264        }
265    }
266
267    /// Inserts a `chunk` of text at a given `index`.
268    /// If `index` is `0`, this `chunk` will be inserted at the beginning of a current text.
269    /// If `index` is equal to current data structure length, this `chunk` will be appended at
270    /// the end of it.
271    /// Collection of supplied `attributes` will be used to wrap provided text `chunk` range with a
272    /// formatting blocks.
273    ///
274    /// This method will panic if provided `index` is greater than the length of a current text.
275    fn insert_with_attributes(
276        &self,
277        txn: &mut TransactionMut,
278        index: u32,
279        chunk: &str,
280        attributes: Attrs,
281    ) {
282        if chunk.is_empty() {
283            return;
284        }
285        let this = BranchPtr::from(self.as_ref());
286        if let Some(mut pos) = find_position(this, txn, index) {
287            let value = block::PrelimString(chunk.into());
288            insert(this, txn, &mut pos, value, attributes);
289        } else {
290            panic!("The type or the position doesn't exist!");
291        }
292    }
293
294    /// Inserts an embed `content` at a given `index`.
295    ///
296    /// If `index` is `0`, this `content` will be inserted at the beginning of a current text.
297    /// If `index` is equal to current data structure length, this `embed` will be appended at
298    /// the end of it.
299    ///
300    /// This method will panic if provided `index` is greater than the length of a current text.
301    fn insert_embed<V>(&self, txn: &mut TransactionMut, index: u32, content: V) -> V::Return
302    where
303        V: Into<EmbedPrelim<V>> + Prelim,
304    {
305        let this = BranchPtr::from(self.as_ref());
306        if let Some(pos) = find_position(this, txn, index) {
307            let ptr = txn
308                .create_item(&pos, content.into(), None)
309                .expect("cannot insert empty value");
310            if let Ok(integrated) = ptr.try_into() {
311                integrated
312            } else {
313                panic!("Defect: embedded return type doesn't match.")
314            }
315        } else {
316            panic!("The type or the position doesn't exist!");
317        }
318    }
319
320    /// Inserts an embed `content` of text at a given `index`.
321    /// If `index` is `0`, this `content` will be inserted at the beginning of a current text.
322    /// If `index` is equal to current data structure length, this `chunk` will be appended at
323    /// the end of it.
324    /// Collection of supplied `attributes` will be used to wrap provided text `content` range with
325    /// a formatting blocks.
326    ///
327    /// This method will panic if provided `index` is greater than the length of a current text.
328    fn insert_embed_with_attributes<V>(
329        &self,
330        txn: &mut TransactionMut,
331        index: u32,
332        embed: V,
333        attributes: Attrs,
334    ) -> V::Return
335    where
336        V: Into<EmbedPrelim<V>> + Prelim,
337    {
338        let this = BranchPtr::from(self.as_ref());
339        if let Some(mut pos) = find_position(this, txn, index) {
340            let item = insert(this, txn, &mut pos, embed.into(), attributes)
341                .expect("cannot insert empty value");
342            if let Ok(integrated) = item.try_into() {
343                integrated
344            } else {
345                panic!("Defect: unexpected returned integrated type")
346            }
347        } else {
348            panic!("The type or the position doesn't exist!");
349        }
350    }
351
352    /// Appends a given `chunk` of text at the end of a current text structure.
353    fn push(&self, txn: &mut TransactionMut, chunk: &str) {
354        let idx = self.len(txn);
355        self.insert(txn, idx, chunk)
356    }
357
358    /// Removes up to a `len` characters from a current text structure, starting at given `index`.
359    /// This method panics in case when not all expected characters were removed (due to
360    /// insufficient number of characters to remove) or `index` is outside of the bounds of text.
361    fn remove_range(&self, txn: &mut TransactionMut, index: u32, len: u32) {
362        let this = BranchPtr::from(self.as_ref());
363        if let Some(mut pos) = find_position(this, txn, index) {
364            remove(txn, &mut pos, len)
365        } else {
366            panic!("The type or the position doesn't exist!");
367        }
368    }
369
370    /// Wraps an existing piece of text within a range described by `index`-`len` parameters with
371    /// formatting blocks containing provided `attributes` metadata.
372    fn format(&self, txn: &mut TransactionMut, index: u32, len: u32, attributes: Attrs) {
373        let this = BranchPtr::from(self.as_ref());
374        if let Some(mut pos) = find_position(this, txn, index) {
375            insert_format(this, txn, &mut pos, len, attributes)
376        } else {
377            panic!("Index {} is outside of the range.", index);
378        }
379    }
380
381    /// Returns an ordered sequence of formatted chunks, current [Text] corresponds of. These chunks
382    /// may contain inserted pieces of text or more complex elements like embedded binaries of
383    /// shared objects. Chunks are organized by type of inserted value and formatting attributes
384    /// wrapping it around. If formatting attributes are nested into each other, they will be split
385    /// into separate [Diff] chunks.
386    ///
387    /// `compute_ychange` callback is used to attach custom data to produced chunks.
388    ///
389    /// # Example
390    ///
391    /// ```rust
392    /// use yrs::{Doc, Text, Transact};
393    /// use yrs::types::Attrs;
394    /// use yrs::types::text::{Diff, YChange};
395    ///
396    /// let doc = Doc::new();
397    /// let text = doc.get_or_insert_text("article");
398    /// let mut txn = doc.transact_mut();
399    ///
400    /// let bold = Attrs::from([("b".into(), true.into())]);
401    /// let italic = Attrs::from([("i".into(), true.into())]);
402    ///
403    /// text.insert_with_attributes(&mut txn, 0, "hello world", italic.clone()); // "<i>hello world</i>"
404    /// text.format(&mut txn, 6, 5, bold.clone()); // "<i>hello <b>world</b></i>"
405    /// let image = vec![0, 0, 0, 0];
406    /// text.insert_embed(&mut txn, 5, image.clone()); // insert binary after "hello"
407    ///
408    /// let italic_and_bold = Attrs::from([
409    ///   ("b".into(), true.into()),
410    ///   ("i".into(), true.into())
411    /// ]);
412    /// let chunks = text.diff(&txn, YChange::identity);
413    /// assert_eq!(chunks, vec![
414    ///     Diff::new("hello".into(), Some(Box::new(italic.clone()))),
415    ///     Diff::new(image.into(), Some(Box::new(italic.clone()))),
416    ///     Diff::new(" ".into(), Some(Box::new(italic))),
417    ///     Diff::new("world".into(), Some(Box::new(italic_and_bold))),
418    /// ]);
419    /// ```
420    fn diff<T, D, F>(&self, _txn: &T, compute_ychange: F) -> Vec<Diff<D>>
421    where
422        T: ReadTxn,
423        F: Fn(YChange) -> D,
424    {
425        let mut asm = DiffAssembler::new(compute_ychange);
426        asm.process(self.as_ref().start, None, None, None, None);
427        asm.finish()
428    }
429
430    /// Returns the Delta representation of this YText type.
431    fn diff_range<D, F>(
432        &self,
433        txn: &mut TransactionMut,
434        hi: Option<&Snapshot>,
435        lo: Option<&Snapshot>,
436        compute_ychange: F,
437    ) -> Vec<Diff<D>>
438    where
439        F: Fn(YChange) -> D,
440    {
441        if let Some(snapshot) = hi {
442            txn.split_by_snapshot(snapshot);
443        }
444        if let Some(snapshot) = lo {
445            txn.split_by_snapshot(snapshot);
446        }
447
448        let mut asm = DiffAssembler::new(compute_ychange);
449        asm.process(self.as_ref().start, hi, lo, None, None);
450        asm.finish()
451    }
452}
453
454impl From<BranchPtr> for TextRef {
455    fn from(inner: BranchPtr) -> Self {
456        TextRef(inner)
457    }
458}
459
460impl AsRef<Branch> for TextRef {
461    fn as_ref(&self) -> &Branch {
462        self.0.deref()
463    }
464}
465
466impl AsPrelim for TextRef {
467    type Prelim = DeltaPrelim;
468
469    fn as_prelim<T: ReadTxn>(&self, txn: &T) -> Self::Prelim {
470        let delta: Vec<Delta<In>> = self
471            .diff(txn, YChange::identity)
472            .into_iter()
473            .map(|diff| Delta::Inserted(diff.insert.as_prelim(txn), diff.attributes))
474            .collect();
475        DeltaPrelim(delta)
476    }
477}
478
479impl DefaultPrelim for TextRef {
480    type Prelim = TextPrelim;
481
482    #[inline]
483    fn default_prelim() -> Self::Prelim {
484        TextPrelim::default()
485    }
486}
487
488impl Eq for TextRef {}
489impl PartialEq for TextRef {
490    fn eq(&self, other: &Self) -> bool {
491        self.0.id() == other.0.id()
492    }
493}
494
495struct DeltaChunk<P>(P);
496
497impl<P> Prelim for DeltaChunk<P>
498where
499    P: Prelim,
500{
501    type Return = Unused;
502
503    fn into_content(self, txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
504        let (content, rest) = self.0.into_content(txn);
505        match content {
506            ItemContent::Any(mut any) if any.len() == 1 => match any.pop().unwrap() {
507                Any::String(str) => (ItemContent::String(str.as_ref().into()), None),
508                other => (ItemContent::Embed(other), None),
509            },
510            other => (other, rest.map(DeltaChunk)),
511        }
512    }
513
514    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
515        self.0.integrate(txn, inner_ref)
516    }
517}
518
519struct DiffAssembler<D, F>
520where
521    F: Fn(YChange) -> D,
522{
523    ops: Vec<Diff<D>>,
524    buf: String,
525    curr_attrs: Attrs,
526    curr_ychange: Option<YChange>,
527    compute_ychange: F,
528}
529
530impl<T, F> DiffAssembler<T, F>
531where
532    F: Fn(YChange) -> T,
533{
534    fn new(compute_ychange: F) -> Self {
535        DiffAssembler {
536            ops: Vec::new(),
537            buf: String::new(),
538            curr_attrs: HashMap::new(),
539            curr_ychange: None,
540            compute_ychange,
541        }
542    }
543    fn pack_str(&mut self) {
544        if !self.buf.is_empty() {
545            let attrs = self.attrs_boxed();
546            let mut buf = std::mem::replace(&mut self.buf, String::new());
547            buf.shrink_to_fit();
548            let change = if let Some(ychange) = self.curr_ychange.take() {
549                Some((self.compute_ychange)(ychange))
550            } else {
551                None
552            };
553            let op = Diff::with_change(Out::Any(buf.into()), attrs, change);
554            self.ops.push(op);
555        }
556    }
557
558    fn finish(self) -> Vec<Diff<T>> {
559        self.ops
560    }
561
562    fn attrs_boxed(&mut self) -> Option<Box<Attrs>> {
563        if self.curr_attrs.is_empty() {
564            None
565        } else {
566            Some(Box::new(self.curr_attrs.clone()))
567        }
568    }
569    fn process(
570        &mut self,
571        mut n: Option<ItemPtr>,
572        hi: Option<&Snapshot>,
573        lo: Option<&Snapshot>,
574        start: Option<&StickyIndex>,
575        end: Option<&StickyIndex>,
576    ) {
577        fn seen(snapshot: Option<&Snapshot>, item: &Item) -> bool {
578            if let Some(s) = snapshot {
579                s.is_visible(&item.id)
580            } else {
581                !item.is_deleted()
582            }
583        }
584        let (start, start_assoc) = if let Some(index) = start {
585            (index.id(), index.assoc)
586        } else {
587            (None, Assoc::Before)
588        };
589        let (end, end_assoc) = if let Some(index) = end {
590            (index.id(), index.assoc)
591        } else {
592            (None, Assoc::After)
593        };
594
595        let mut start_offset: i32 = if start.is_none() { 0 } else { -1 };
596        'LOOP: while let Some(item) = n.as_deref() {
597            if let Some(start) = start {
598                if start_offset < 0 && item.contains(start) {
599                    if start_assoc == Assoc::After {
600                        if start.clock == item.id.clock + item.len() - 1 {
601                            start_offset = 0;
602                            n = item.right;
603                            continue;
604                        } else {
605                            start_offset = start.clock as i32 - item.id.clock as i32 + 1;
606                        }
607                    } else {
608                        start_offset = start.clock as i32 - item.id.clock as i32;
609                    }
610                }
611            }
612            if let Some(end) = end {
613                if end_assoc == Assoc::Before && &item.id == end {
614                    break;
615                }
616            }
617            if seen(hi, item) || (lo.is_some() && seen(lo, item)) {
618                match &item.content {
619                    ItemContent::String(s) => {
620                        if let Some(snapshot) = hi {
621                            if !snapshot.is_visible(&item.id) {
622                                self.pack_str();
623                                self.curr_ychange =
624                                    Some(YChange::new(ChangeKind::Removed, item.id));
625                            } else if let Some(snapshot) = lo {
626                                if !snapshot.is_visible(&item.id) {
627                                    self.pack_str();
628                                    self.curr_ychange =
629                                        Some(YChange::new(ChangeKind::Added, item.id));
630                                } else if self.curr_ychange.is_some() {
631                                    self.pack_str();
632                                }
633                            }
634                        }
635                        if start_offset > 0 {
636                            let slice = &s.as_str()[start_offset as usize..];
637                            self.buf.push_str(slice);
638                            start_offset = 0;
639                        } else {
640                            match end {
641                                Some(end) if item.contains(end) => {
642                                    // we reached the end or range
643                                    let mut end_offset =
644                                        (item.id.clock + item.len - end.clock - 1) as usize;
645                                    if end_assoc == Assoc::Before {
646                                        end_offset -= 1;
647                                    }
648                                    let s = s.as_str();
649                                    let slice = &s[..(s.len() + end_offset)];
650                                    self.buf.push_str(slice);
651                                    self.pack_str();
652                                    break 'LOOP;
653                                }
654                                _ => {
655                                    if start_offset == 0 {
656                                        self.buf.push_str(s.as_str());
657                                    }
658                                }
659                            }
660                        }
661                    }
662                    ItemContent::Type(_) | ItemContent::Embed(_) => {
663                        self.pack_str();
664                        if let Some(value) = item.content.get_first() {
665                            let attrs = self.attrs_boxed();
666                            self.ops.push(Diff::new(value, attrs));
667                        }
668                    }
669                    ItemContent::Format(key, value) => {
670                        if seen(hi, item) {
671                            self.pack_str();
672                            update_current_attributes(&mut self.curr_attrs, key, value.as_ref());
673                        }
674                    }
675                    _ => {}
676                }
677            } else if let Some(end) = end {
678                if item.contains(end) {
679                    break;
680                }
681            }
682            n = item.right;
683        }
684
685        self.pack_str();
686    }
687}
688
689pub(crate) fn diff_between<D, F>(
690    ptr: Option<ItemPtr>,
691    start: Option<&StickyIndex>,
692    end: Option<&StickyIndex>,
693    compute_ychange: F,
694) -> Vec<Diff<D>>
695where
696    F: Fn(YChange) -> D,
697{
698    let mut asm = DiffAssembler::new(compute_ychange);
699    asm.process(ptr, None, None, start, end);
700    asm.finish()
701}
702
703fn insert<P: Prelim>(
704    branch: BranchPtr,
705    txn: &mut TransactionMut,
706    pos: &mut ItemPosition,
707    value: P,
708    mut attributes: Attrs,
709) -> Option<ItemPtr> {
710    pos.unset_missing(&mut attributes);
711    minimize_attr_changes(pos, &attributes);
712    let negated_attrs = insert_attributes(branch, txn, pos, attributes);
713
714    let item = if let Some(item) = txn.create_item(&pos, value, None) {
715        pos.right = Some(item);
716        pos.forward();
717        Some(item)
718    } else {
719        None
720    };
721
722    insert_negated_attributes(branch, txn, pos, negated_attrs);
723    item
724}
725
726pub(crate) fn update_current_attributes(attrs: &mut Attrs, key: &str, value: &Any) {
727    if let Any::Null = value {
728        attrs.remove(key);
729    } else {
730        attrs.insert(key.into(), value.clone());
731    }
732}
733
734fn find_position(this: BranchPtr, txn: &mut TransactionMut, index: u32) -> Option<ItemPosition> {
735    let mut pos = {
736        ItemPosition {
737            parent: this.into(),
738            left: None,
739            right: this.start,
740            index: 0,
741            current_attrs: None,
742        }
743    };
744
745    let mut format_ptrs = HashMap::new();
746    let store = txn.store_mut();
747    let encoding = store.offset_kind;
748    let mut remaining = index;
749    while let Some(right) = pos.right {
750        if remaining == 0 {
751            break;
752        }
753
754        if !right.is_deleted() {
755            match &right.content {
756                ItemContent::Format(key, value) => {
757                    if let Any::Null = value.as_ref() {
758                        format_ptrs.remove(key);
759                    } else {
760                        format_ptrs.insert(key.clone(), pos.right.clone());
761                    }
762                }
763                _ => {
764                    let mut block_len = right.len();
765                    let content_len = right.content_len(encoding);
766                    if remaining < content_len {
767                        // split right item
768                        let offset = if let ItemContent::String(str) = &right.content {
769                            str.block_offset(remaining, encoding)
770                        } else {
771                            remaining
772                        };
773                        store
774                            .blocks
775                            .split_block(right, offset, OffsetKind::Utf16)
776                            .unwrap();
777                        block_len -= offset;
778                        remaining = 0;
779                    } else {
780                        remaining -= content_len;
781                    }
782                    pos.index += block_len;
783                }
784            }
785        }
786        pos.left = pos.right.take();
787        pos.right = if let Some(item) = pos.left.as_deref() {
788            item.right
789        } else {
790            None
791        };
792    }
793
794    for (_, block_ptr) in format_ptrs {
795        if let Some(item) = block_ptr {
796            if let ItemContent::Format(key, value) = &item.content {
797                let attrs = pos.current_attrs.get_or_init();
798                update_current_attributes(attrs, key, value.as_ref());
799            }
800        }
801    }
802
803    Some(pos)
804}
805
806fn remove(txn: &mut TransactionMut, pos: &mut ItemPosition, len: u32) {
807    let encoding = txn.store().offset_kind;
808    let mut remaining = len;
809    let start = pos.right.clone();
810    let start_attrs = pos.current_attrs.clone();
811    while let Some(item) = pos.right.as_deref() {
812        if remaining == 0 {
813            break;
814        }
815
816        if !item.is_deleted() {
817            match &item.content {
818                ItemContent::Embed(_) | ItemContent::String(_) | ItemContent::Type(_) => {
819                    let content_len = item.content_len(encoding);
820                    let ptr = pos.right.unwrap();
821                    if remaining < content_len {
822                        // split block
823                        let offset = if let ItemContent::String(s) = &item.content {
824                            s.block_offset(remaining, encoding)
825                        } else {
826                            len
827                        };
828                        remaining = 0;
829                        txn.store_mut()
830                            .blocks
831                            .split_block(ptr, offset, OffsetKind::Utf16);
832                    } else {
833                        remaining -= content_len;
834                    };
835                    txn.delete(ptr);
836                }
837                _ => {}
838            }
839        }
840
841        pos.forward();
842    }
843
844    if remaining > 0 {
845        panic!(
846            "Couldn't remove {} elements from an array. Only {} of them were successfully removed.",
847            len,
848            len - remaining
849        );
850    }
851
852    if let (Some(start), Some(start_attrs), Some(end_attrs)) =
853        (start, start_attrs, pos.current_attrs.as_mut())
854    {
855        clean_format_gap(
856            txn,
857            Some(start),
858            pos.right,
859            start_attrs.as_ref(),
860            end_attrs.as_mut(),
861        );
862    }
863}
864
865fn is_valid_target(item: ItemPtr) -> bool {
866    if item.is_deleted() {
867        true
868    } else if let ItemContent::Format(_, _) = &item.content {
869        true
870    } else {
871        false
872    }
873}
874
875fn insert_format(
876    this: BranchPtr,
877    txn: &mut TransactionMut,
878    pos: &mut ItemPosition,
879    mut len: u32,
880    attrs: Attrs,
881) {
882    minimize_attr_changes(pos, &attrs);
883    let mut negated_attrs = insert_attributes(this, txn, pos, attrs.clone()); //TODO: remove `attrs.clone()`
884    let encoding = txn.store().offset_kind;
885    // iterate until first non-format or null is found
886    // delete all formats with attributes[format.key] != null
887    // also check the attributes after the first non-format as we do not want to insert redundant
888    // negated attributes there
889    while let Some(right) = pos.right {
890        if !(len > 0 || (!negated_attrs.is_empty() && is_valid_target(right))) {
891            break;
892        }
893
894        if !right.is_deleted() {
895            match &right.content {
896                ItemContent::Format(key, value) => {
897                    if let Some(v) = attrs.get(key) {
898                        if v == value.as_ref() {
899                            negated_attrs.remove(key);
900                        } else {
901                            negated_attrs.insert(key.clone(), *value.clone());
902                        }
903                        txn.delete(right);
904                    }
905                }
906                ItemContent::String(s) => {
907                    let content_len = right.content_len(encoding);
908                    if len < content_len {
909                        // split block
910                        let offset = s.block_offset(len, encoding);
911                        let new_right =
912                            txn.store_mut()
913                                .blocks
914                                .split_block(right, offset, OffsetKind::Utf16);
915                        pos.left = Some(right);
916                        pos.right = new_right;
917                        break;
918                    }
919                    len -= content_len;
920                }
921                _ => {
922                    let content_len = right.len();
923                    if len < content_len {
924                        let new_right =
925                            txn.store_mut()
926                                .blocks
927                                .split_block(right, len, OffsetKind::Utf16);
928                        pos.left = Some(right);
929                        pos.right = new_right;
930                        break;
931                    }
932                    len -= content_len;
933                }
934            }
935        }
936
937        if !pos.forward() {
938            break;
939        }
940    }
941
942    insert_negated_attributes(this, txn, pos, negated_attrs);
943}
944
945fn minimize_attr_changes(pos: &mut ItemPosition, attrs: &Attrs) {
946    // go right while attrs[right.key] === right.value (or right is deleted)
947    while let Some(i) = pos.right.as_deref() {
948        if !i.is_deleted() {
949            if let ItemContent::Format(k, v) = &i.content {
950                if let Some(v2) = attrs.get(k) {
951                    if (v.as_ref()).eq(v2) {
952                        pos.forward();
953                        continue;
954                    }
955                }
956            }
957
958            break;
959        } else {
960            pos.forward();
961        }
962    }
963}
964
965fn insert_attributes(
966    this: BranchPtr,
967    txn: &mut TransactionMut,
968    pos: &mut ItemPosition,
969    attrs: Attrs,
970) -> Attrs {
971    let mut negated_attrs = HashMap::with_capacity(attrs.len());
972    let mut store = txn.store_mut();
973    for (k, v) in attrs {
974        let current_value = pos
975            .current_attrs
976            .as_ref()
977            .and_then(|a| a.get(&k))
978            .unwrap_or(&Any::Null);
979        if &v != current_value {
980            // save negated attribute (set null if currentVal undefined)
981            negated_attrs.insert(k.clone(), current_value.clone());
982
983            let client_id = store.client_id;
984            let parent = this.into();
985            let item = Item::new(
986                ID::new(client_id, store.blocks.get_clock(&client_id)),
987                pos.left.clone(),
988                pos.left.map(|ptr| ptr.last_id()),
989                pos.right.clone(),
990                pos.right.map(|ptr| ptr.id().clone()),
991                parent,
992                None,
993                ItemContent::Format(k, v.into()),
994            )
995            .unwrap();
996            let item_ptr = txn.integrate_item(item, 0);
997            pos.right = item_ptr;
998            pos.forward();
999            store = txn.store_mut();
1000        }
1001    }
1002    negated_attrs
1003}
1004
1005fn insert_negated_attributes(
1006    this: BranchPtr,
1007    txn: &mut TransactionMut,
1008    pos: &mut ItemPosition,
1009    mut attrs: Attrs,
1010) {
1011    while let Some(item) = pos.right.as_deref() {
1012        if !item.is_deleted() {
1013            if let ItemContent::Format(key, value) = &item.content {
1014                if let Some(curr_val) = attrs.get(key) {
1015                    if curr_val == value.as_ref() {
1016                        attrs.remove(key);
1017                        pos.forward();
1018                        continue;
1019                    }
1020                }
1021            }
1022
1023            break;
1024        } else {
1025            pos.forward();
1026        }
1027    }
1028
1029    let mut store = txn.store_mut();
1030    for (k, v) in attrs {
1031        let client_id = store.client_id;
1032        let parent = this.into();
1033        let item = Item::new(
1034            ID::new(client_id, store.blocks.get_clock(&client_id)),
1035            pos.left.clone(),
1036            pos.left.map(|ptr| ptr.last_id()),
1037            pos.right.clone(),
1038            pos.right.map(|ptr| ptr.id().clone()),
1039            parent,
1040            None,
1041            ItemContent::Format(k, v.into()),
1042        )
1043        .unwrap();
1044        let item_ptr = txn.integrate_item(item, 0);
1045        pos.right = item_ptr;
1046        pos.forward();
1047        store = txn.store_mut();
1048    }
1049}
1050
1051fn clean_format_gap(
1052    txn: &mut TransactionMut,
1053    mut start: Option<ItemPtr>,
1054    mut end: Option<ItemPtr>,
1055    start_attrs: &Attrs,
1056    end_attrs: &mut Attrs,
1057) -> u32 {
1058    while let Some(item) = end.as_deref() {
1059        match &item.content {
1060            ItemContent::String(_) | ItemContent::Embed(_) => break,
1061            ItemContent::Format(key, value) if !item.is_deleted() => {
1062                update_current_attributes(end_attrs, key.as_ref(), value);
1063            }
1064            _ => {}
1065        }
1066        end = item.right.clone();
1067    }
1068
1069    let mut cleanups = 0;
1070    while start != end {
1071        if let Some(item) = start.as_deref() {
1072            let right = item.right.clone();
1073            if !item.is_deleted() {
1074                if let ItemContent::Format(key, value) = &item.content {
1075                    let e = end_attrs.get(key).unwrap_or(&Any::Null);
1076                    let s = start_attrs.get(key).unwrap_or(&Any::Null);
1077                    if e != value.as_ref() || s == value.as_ref() {
1078                        txn.delete(start.unwrap());
1079                        cleanups += 1;
1080                    }
1081                }
1082            }
1083            start = right;
1084        } else {
1085            break;
1086        }
1087    }
1088    cleanups
1089}
1090
1091/// A representation of an uniformly-formatted chunk of rich context stored by [TextRef] or
1092/// [XmlTextRef]. It contains a value (which could be a string, embedded object or another shared
1093/// type) with optional formatting attributes wrapping around this chunk. It can also contain some
1094/// custom data generated by caller as part of [TextRef::diff] callback.
1095#[derive(Debug, PartialEq)]
1096pub struct Diff<T> {
1097    /// Inserted chunk of data. It can be (usually) piece of text, but possibly also embedded value
1098    /// or another shared type.
1099    pub insert: Out,
1100
1101    /// Optional formatting attributes wrapping inserted chunk of data.
1102    pub attributes: Option<Box<Attrs>>,
1103
1104    /// Custom user data attached to this chunk of data.
1105    pub ychange: Option<T>,
1106}
1107
1108impl<T> Diff<T> {
1109    pub fn new(insert: Out, attributes: Option<Box<Attrs>>) -> Self {
1110        Self::with_change(insert, attributes, None)
1111    }
1112
1113    pub fn with_change(insert: Out, attributes: Option<Box<Attrs>>, ychange: Option<T>) -> Self {
1114        Diff {
1115            insert,
1116            attributes,
1117            ychange,
1118        }
1119    }
1120}
1121
1122impl<T> From<Diff<T>> for Delta {
1123    #[inline]
1124    fn from(value: Diff<T>) -> Self {
1125        Delta::Inserted(value.insert, value.attributes)
1126    }
1127}
1128
1129#[repr(transparent)]
1130#[derive(Debug, Clone, PartialEq, Default)]
1131pub struct DeltaPrelim(Vec<Delta<In>>);
1132
1133impl Deref for DeltaPrelim {
1134    type Target = [Delta<In>];
1135
1136    #[inline]
1137    fn deref(&self) -> &Self::Target {
1138        &self.0
1139    }
1140}
1141
1142impl Prelim for DeltaPrelim {
1143    type Return = TextRef;
1144
1145    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
1146        (ItemContent::Type(Branch::new(TypeRef::Text)), Some(self))
1147    }
1148
1149    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
1150        let text_ref = TextRef::from(inner_ref);
1151        text_ref.apply_delta(txn, self.0);
1152    }
1153}
1154
1155impl From<TextPrelim> for DeltaPrelim {
1156    fn from(value: TextPrelim) -> Self {
1157        DeltaPrelim(vec![Delta::Inserted(
1158            In::Any(Any::String(value.0.into())),
1159            None,
1160        )])
1161    }
1162}
1163
1164impl<T> std::fmt::Display for Diff<T> {
1165    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1166        write!(f, "{{ insert: '{}'", self.insert)?;
1167        if let Some(attrs) = self.attributes.as_ref() {
1168            write!(f, ", attributes: {{")?;
1169            let mut i = attrs.iter();
1170            if let Some((k, v)) = i.next() {
1171                write!(f, " {}={}", k, v)?;
1172            }
1173            for (k, v) in i {
1174                write!(f, ", {}={}", k, v)?;
1175            }
1176            write!(f, " }}")?;
1177        }
1178        write!(f, " }}")
1179    }
1180}
1181
1182#[derive(Debug, Clone, PartialEq)]
1183pub struct YChange {
1184    pub kind: ChangeKind,
1185    pub id: ID,
1186}
1187
1188impl YChange {
1189    pub fn new(kind: ChangeKind, id: ID) -> Self {
1190        YChange { kind, id }
1191    }
1192
1193    #[inline]
1194    pub fn identity(change: YChange) -> YChange {
1195        change
1196    }
1197}
1198
1199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1200pub enum ChangeKind {
1201    Added,
1202    Removed,
1203}
1204
1205/// Event generated by [Text::observe] method. Emitted during transaction commit phase.
1206pub struct TextEvent {
1207    pub(crate) current_target: BranchPtr,
1208    target: TextRef,
1209    delta: UnsafeCell<Option<Vec<Delta>>>,
1210}
1211
1212impl TextEvent {
1213    pub(crate) fn new(branch_ref: BranchPtr) -> Self {
1214        let current_target = branch_ref.clone();
1215        let target = TextRef::from(branch_ref);
1216        TextEvent {
1217            target,
1218            current_target,
1219            delta: UnsafeCell::new(None),
1220        }
1221    }
1222
1223    /// Returns a [Text] instance which emitted this event.
1224    pub fn target(&self) -> &TextRef {
1225        &self.target
1226    }
1227
1228    /// Returns a path from root type down to [Text] instance which emitted this event.
1229    pub fn path(&self) -> Path {
1230        Branch::path(self.current_target, self.target.0)
1231    }
1232
1233    /// Returns a summary of text changes made over corresponding [Text] collection within
1234    /// bounds of current transaction.
1235    pub fn delta(&self, txn: &TransactionMut) -> &[Delta] {
1236        let delta = unsafe { self.delta.get().as_mut().unwrap() };
1237        delta
1238            .get_or_insert_with(|| Self::get_delta(self.target.0, txn))
1239            .as_slice()
1240    }
1241
1242    pub(crate) fn get_delta(target: BranchPtr, txn: &TransactionMut) -> Vec<Delta> {
1243        #[derive(Debug, Clone, Copy, Eq, PartialEq)]
1244        enum Action {
1245            Insert,
1246            Retain,
1247            Delete,
1248        }
1249
1250        #[derive(Debug, Default)]
1251        struct DeltaAssembler {
1252            action: Option<Action>,
1253            insert: Option<Out>,
1254            insert_string: Option<String>,
1255            retain: u32,
1256            delete: u32,
1257            attrs: Attrs,
1258            current_attrs: Attrs,
1259            delta: Vec<Delta>,
1260        }
1261
1262        impl DeltaAssembler {
1263            fn add_op(&mut self) {
1264                match self.action.take() {
1265                    None => {}
1266                    Some(Action::Delete) => {
1267                        let len = self.delete;
1268                        self.delete = 0;
1269                        self.delta.push(Delta::Deleted(len))
1270                    }
1271                    Some(Action::Insert) => {
1272                        let value = if let Some(str) = self.insert.take() {
1273                            str
1274                        } else {
1275                            let value = self.insert_string.take().unwrap();
1276                            Any::from(value).into()
1277                        };
1278                        let attrs = if self.current_attrs.is_empty() {
1279                            None
1280                        } else {
1281                            Some(Box::new(self.current_attrs.clone()))
1282                        };
1283                        self.delta.push(Delta::Inserted(value, attrs))
1284                    }
1285                    Some(Action::Retain) => {
1286                        let len = self.retain;
1287                        self.retain = 0;
1288                        let attrs = if self.attrs.is_empty() {
1289                            None
1290                        } else {
1291                            Some(Box::new(self.attrs.clone()))
1292                        };
1293                        self.delta.push(Delta::Retain(len, attrs));
1294                    }
1295                }
1296            }
1297
1298            fn finish(mut self) -> Vec<Delta> {
1299                while let Some(last) = self.delta.pop() {
1300                    match last {
1301                        Delta::Retain(_, None) => {
1302                            // retain delta's if they don't assign attributes
1303                        }
1304                        other => {
1305                            self.delta.push(other);
1306                            return self.delta;
1307                        }
1308                    }
1309                }
1310                self.delta
1311            }
1312        }
1313
1314        let encoding = txn.store().offset_kind;
1315        let mut old_attrs = HashMap::new();
1316        let mut asm = DeltaAssembler::default();
1317        let mut current = target.start;
1318
1319        while let Some(item) = current.as_deref() {
1320            match &item.content {
1321                ItemContent::Type(_) | ItemContent::Embed(_) => {
1322                    if txn.has_added(&item.id) {
1323                        if !txn.has_deleted(&item.id) {
1324                            asm.add_op();
1325                            asm.action = Some(Action::Insert);
1326                            asm.insert = item.content.get_last();
1327                            asm.add_op();
1328                        }
1329                    } else if txn.has_deleted(&item.id) {
1330                        if asm.action != Some(Action::Delete) {
1331                            asm.add_op();
1332                            asm.action = Some(Action::Delete);
1333                        }
1334                        asm.delete += 1;
1335                    } else if !item.is_deleted() {
1336                        if asm.action != Some(Action::Retain) {
1337                            asm.add_op();
1338                            asm.action = Some(Action::Retain);
1339                        }
1340                        asm.retain += 1;
1341                    }
1342                }
1343                ItemContent::String(s) => {
1344                    if txn.has_added(&item.id) {
1345                        if !txn.has_deleted(&item.id) {
1346                            if asm.action != Some(Action::Insert) {
1347                                asm.add_op();
1348                                asm.action = Some(Action::Insert);
1349                            }
1350                            let buf = asm.insert_string.get_or_insert_with(String::default);
1351                            buf.push_str(s.as_str());
1352                        }
1353                    } else if txn.has_deleted(&item.id) {
1354                        if asm.action != Some(Action::Delete) {
1355                            asm.add_op();
1356                            asm.action = Some(Action::Delete);
1357                        }
1358                        let content_len = item.content_len(encoding);
1359                        asm.delete += content_len;
1360                    } else if !item.is_deleted() {
1361                        if asm.action != Some(Action::Retain) {
1362                            asm.add_op();
1363                            asm.action = Some(Action::Retain);
1364                        }
1365                        asm.retain += item.content_len(encoding);
1366                    }
1367                }
1368                ItemContent::Format(key, value) => {
1369                    if txn.has_added(&item.id) {
1370                        if !txn.has_deleted(&item.id) {
1371                            let current_val = asm.current_attrs.get(key);
1372                            if current_val != Some(value) {
1373                                if asm.action == Some(Action::Retain) {
1374                                    asm.add_op();
1375                                }
1376                                match old_attrs.get(key) {
1377                                    None if value.as_ref() == &Any::Null => {
1378                                        asm.attrs.remove(key);
1379                                    }
1380                                    Some(v) if v == value => {
1381                                        asm.attrs.remove(key);
1382                                    }
1383                                    _ => {
1384                                        asm.attrs.insert(key.clone(), *value.clone());
1385                                    }
1386                                }
1387                            } else {
1388                                // item.delete(transaction)
1389                            }
1390                        }
1391                    } else if txn.has_deleted(&item.id) {
1392                        old_attrs.insert(key.clone(), value.clone());
1393                        let current_val = asm.current_attrs.get(key).unwrap_or(&Any::Null);
1394                        if current_val != value.as_ref() {
1395                            let curr_val_clone = current_val.clone();
1396                            if asm.action == Some(Action::Retain) {
1397                                asm.add_op();
1398                            }
1399                            asm.attrs.insert(key.clone(), curr_val_clone);
1400                        }
1401                    } else if !item.is_deleted() {
1402                        old_attrs.insert(key.clone(), value.clone());
1403                        let attr = asm.attrs.get(key);
1404                        if let Some(attr) = attr {
1405                            if attr != value.as_ref() {
1406                                if asm.action == Some(Action::Retain) {
1407                                    asm.add_op();
1408                                }
1409                                if value.as_ref() == &Any::Null {
1410                                    asm.attrs.remove(key);
1411                                } else {
1412                                    asm.attrs.insert(key.clone(), *value.clone());
1413                                }
1414                            } else {
1415                                // item.delete(transaction)
1416                            }
1417                        }
1418                    }
1419
1420                    if !item.is_deleted() {
1421                        if asm.action == Some(Action::Insert) {
1422                            asm.add_op();
1423                        }
1424                        update_current_attributes(&mut asm.current_attrs, key, value.as_ref());
1425                    }
1426                }
1427                _ => {}
1428            }
1429
1430            current = item.right;
1431        }
1432
1433        asm.add_op();
1434        asm.finish()
1435    }
1436}
1437
1438/// A preliminary text. It's can be used to initialize a [TextRef], when it's about to be nested
1439/// into another Yrs data collection, such as [Map] or [Array].
1440#[repr(transparent)]
1441#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
1442pub struct TextPrelim(String);
1443
1444impl TextPrelim {
1445    #[inline]
1446    pub fn new<S: Into<String>>(value: S) -> Self {
1447        TextPrelim(value.into())
1448    }
1449}
1450
1451impl Deref for TextPrelim {
1452    type Target = String;
1453
1454    #[inline]
1455    fn deref(&self) -> &Self::Target {
1456        &self.0
1457    }
1458}
1459
1460impl DerefMut for TextPrelim {
1461    #[inline]
1462    fn deref_mut(&mut self) -> &mut Self::Target {
1463        &mut self.0
1464    }
1465}
1466
1467impl From<TextPrelim> for In {
1468    #[inline]
1469    fn from(value: TextPrelim) -> Self {
1470        In::Text(DeltaPrelim::from(value))
1471    }
1472}
1473
1474impl Prelim for TextPrelim {
1475    type Return = TextRef;
1476
1477    fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
1478        let inner = Branch::new(TypeRef::Text);
1479        (ItemContent::Type(inner), Some(self))
1480    }
1481
1482    fn integrate(self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
1483        if !self.0.is_empty() {
1484            let text = TextRef::from(inner_ref);
1485            text.push(txn, &self.0);
1486        }
1487    }
1488}
1489
1490impl Into<EmbedPrelim<TextPrelim>> for TextPrelim {
1491    #[inline]
1492    fn into(self) -> EmbedPrelim<TextPrelim> {
1493        EmbedPrelim::Shared(self)
1494    }
1495}
1496
1497#[cfg(test)]
1498mod test {
1499    use crate::block::ClientID;
1500    use crate::doc::{OffsetKind, Options};
1501    use crate::test_utils::{exchange_updates, run_scenario, RngExt};
1502    use crate::transaction::ReadTxn;
1503    use crate::types::text::{Attrs, ChangeKind, Delta, Diff, YChange};
1504    use crate::types::Out;
1505    use crate::updates::decoder::Decode;
1506    use crate::updates::encoder::{Encode, Encoder, EncoderV1};
1507    use crate::{
1508        any, Any, ArrayPrelim, Doc, GetString, Map, MapPrelim, MapRef, Observable, StateVector,
1509        Text, Transact, Update, WriteTxn, ID,
1510    };
1511    use arc_swap::ArcSwapOption;
1512    use fastrand::Rng;
1513    use std::collections::HashMap;
1514    use std::sync::atomic::{AtomicBool, Ordering};
1515    use std::sync::Arc;
1516    use std::time::Duration;
1517
1518    #[test]
1519    fn insert_empty_string() {
1520        let doc = Doc::new();
1521        let txt = doc.get_or_insert_text("test");
1522        let mut txn = doc.transact_mut();
1523
1524        assert_eq!(txt.get_string(&txn).as_str(), "");
1525
1526        txt.push(&mut txn, "");
1527        assert_eq!(txt.get_string(&txn).as_str(), "");
1528
1529        txt.push(&mut txn, "abc");
1530        txt.push(&mut txn, "");
1531        assert_eq!(txt.get_string(&txn).as_str(), "abc");
1532    }
1533
1534    #[test]
1535    fn append_single_character_blocks() {
1536        let doc = Doc::new();
1537        let txt = doc.get_or_insert_text("test");
1538        let mut txn = doc.transact_mut();
1539
1540        txt.insert(&mut txn, 0, "a");
1541        txt.insert(&mut txn, 1, "b");
1542        txt.insert(&mut txn, 2, "c");
1543
1544        assert_eq!(txt.get_string(&txn).as_str(), "abc");
1545    }
1546
1547    #[test]
1548    fn append_mutli_character_blocks() {
1549        let doc = Doc::new();
1550        let txt = doc.get_or_insert_text("test");
1551        let mut txn = doc.transact_mut();
1552
1553        txt.insert(&mut txn, 0, "hello");
1554        txt.insert(&mut txn, 5, " ");
1555        txt.insert(&mut txn, 6, "world");
1556
1557        assert_eq!(txt.get_string(&txn).as_str(), "hello world");
1558    }
1559
1560    #[test]
1561    fn prepend_single_character_blocks() {
1562        let doc = Doc::new();
1563        let txt = doc.get_or_insert_text("test");
1564        let mut txn = doc.transact_mut();
1565
1566        txt.insert(&mut txn, 0, "a");
1567        txt.insert(&mut txn, 0, "b");
1568        txt.insert(&mut txn, 0, "c");
1569
1570        assert_eq!(txt.get_string(&txn).as_str(), "cba");
1571    }
1572
1573    #[test]
1574    fn prepend_mutli_character_blocks() {
1575        let doc = Doc::new();
1576        let txt = doc.get_or_insert_text("test");
1577        let mut txn = doc.transact_mut();
1578
1579        txt.insert(&mut txn, 0, "hello");
1580        txt.insert(&mut txn, 0, " ");
1581        txt.insert(&mut txn, 0, "world");
1582
1583        assert_eq!(txt.get_string(&txn).as_str(), "world hello");
1584    }
1585
1586    #[test]
1587    fn insert_after_block() {
1588        let doc = Doc::new();
1589        let txt = doc.get_or_insert_text("test");
1590        let mut txn = doc.transact_mut();
1591
1592        txt.insert(&mut txn, 0, "hello");
1593        txt.insert(&mut txn, 5, " ");
1594        txt.insert(&mut txn, 6, "world");
1595        txt.insert(&mut txn, 6, "beautiful ");
1596
1597        assert_eq!(txt.get_string(&txn).as_str(), "hello beautiful world");
1598    }
1599
1600    #[test]
1601    fn insert_inside_of_block() {
1602        let doc = Doc::new();
1603        let txt = doc.get_or_insert_text("test");
1604        let mut txn = doc.transact_mut();
1605
1606        txt.insert(&mut txn, 0, "it was expected");
1607        txt.insert(&mut txn, 6, " not");
1608
1609        assert_eq!(txt.get_string(&txn).as_str(), "it was not expected");
1610    }
1611
1612    #[test]
1613    fn insert_concurrent_root() {
1614        let d1 = Doc::with_client_id(1);
1615        let txt1 = d1.get_or_insert_text("test");
1616        let mut t1 = d1.transact_mut();
1617
1618        txt1.insert(&mut t1, 0, "hello ");
1619
1620        let d2 = Doc::with_client_id(2);
1621        let txt2 = d2.get_or_insert_text("test");
1622        let mut t2 = d2.transact_mut();
1623
1624        txt2.insert(&mut t2, 0, "world");
1625
1626        let d1_sv = t1.state_vector().encode_v1();
1627        let d2_sv = t2.state_vector().encode_v1();
1628
1629        let u1 = t1.encode_diff_v1(&StateVector::decode_v1(&d2_sv).unwrap());
1630        let u2 = t2.encode_diff_v1(&StateVector::decode_v1(&d1_sv).unwrap());
1631
1632        t1.apply_update(Update::decode_v1(u2.as_slice()).unwrap())
1633            .unwrap();
1634        t2.apply_update(Update::decode_v1(u1.as_slice()).unwrap())
1635            .unwrap();
1636
1637        let a = txt1.get_string(&t1);
1638        let b = txt2.get_string(&t2);
1639
1640        assert_eq!(a, b);
1641        assert_eq!(a.as_str(), "hello world");
1642    }
1643
1644    #[test]
1645    fn insert_concurrent_in_the_middle() {
1646        let d1 = Doc::with_client_id(1);
1647        let txt1 = d1.get_or_insert_text("test");
1648        let mut t1 = d1.transact_mut();
1649
1650        txt1.insert(&mut t1, 0, "I expect that");
1651        assert_eq!(txt1.get_string(&t1).as_str(), "I expect that");
1652
1653        let d2 = Doc::with_client_id(2);
1654        let txt2 = d2.get_or_insert_text("test");
1655        let mut t2 = d2.transact_mut();
1656
1657        let d2_sv = t2.state_vector().encode_v1();
1658        let u1 = t1.encode_diff_v1(&StateVector::decode_v1(&d2_sv).unwrap());
1659        t2.apply_update(Update::decode_v1(u1.as_slice()).unwrap())
1660            .unwrap();
1661
1662        assert_eq!(txt2.get_string(&t2).as_str(), "I expect that");
1663
1664        txt2.insert(&mut t2, 1, " have");
1665        txt2.insert(&mut t2, 13, "ed");
1666        assert_eq!(txt2.get_string(&t2).as_str(), "I have expected that");
1667
1668        txt1.insert(&mut t1, 1, " didn't");
1669        assert_eq!(txt1.get_string(&t1).as_str(), "I didn't expect that");
1670
1671        let d2_sv = t2.state_vector().encode_v1();
1672        let d1_sv = t1.state_vector().encode_v1();
1673        let u1 = t1.encode_diff_v1(&StateVector::decode_v1(&d2_sv.as_slice()).unwrap());
1674        let u2 = t2.encode_diff_v1(&StateVector::decode_v1(&d1_sv.as_slice()).unwrap());
1675        t1.apply_update(Update::decode_v1(u2.as_slice()).unwrap())
1676            .unwrap();
1677        t2.apply_update(Update::decode_v1(u1.as_slice()).unwrap())
1678            .unwrap();
1679
1680        let a = txt1.get_string(&t1);
1681        let b = txt2.get_string(&t2);
1682
1683        assert_eq!(a, b);
1684        assert_eq!(a.as_str(), "I didn't have expected that");
1685    }
1686
1687    #[test]
1688    fn append_concurrent() {
1689        let d1 = Doc::with_client_id(1);
1690        let txt1 = d1.get_or_insert_text("test");
1691        let mut t1 = d1.transact_mut();
1692
1693        txt1.insert(&mut t1, 0, "aaa");
1694        assert_eq!(txt1.get_string(&t1).as_str(), "aaa");
1695
1696        let d2 = Doc::with_client_id(2);
1697        let txt2 = d2.get_or_insert_text("test");
1698        let mut t2 = d2.transact_mut();
1699
1700        let d2_sv = t2.state_vector().encode_v1();
1701        let u1 = t1.encode_diff_v1(&StateVector::decode_v1(&d2_sv.as_slice()).unwrap());
1702        t2.apply_update(Update::decode_v1(u1.as_slice()).unwrap())
1703            .unwrap();
1704
1705        assert_eq!(txt2.get_string(&t2).as_str(), "aaa");
1706
1707        txt2.insert(&mut t2, 3, "bbb");
1708        txt2.insert(&mut t2, 6, "bbb");
1709        assert_eq!(txt2.get_string(&t2).as_str(), "aaabbbbbb");
1710
1711        txt1.insert(&mut t1, 3, "aaa");
1712        assert_eq!(txt1.get_string(&t1).as_str(), "aaaaaa");
1713
1714        let d2_sv = t2.state_vector().encode_v1();
1715        let d1_sv = t1.state_vector().encode_v1();
1716        let u1 = t1.encode_diff_v1(&StateVector::decode_v1(&d2_sv.as_slice()).unwrap());
1717        let u2 = t2.encode_diff_v1(&StateVector::decode_v1(&d1_sv.as_slice()).unwrap());
1718
1719        t1.apply_update(Update::decode_v1(u2.as_slice()).unwrap())
1720            .unwrap();
1721        t2.apply_update(Update::decode_v1(u1.as_slice()).unwrap())
1722            .unwrap();
1723
1724        let a = txt1.get_string(&t1);
1725        let b = txt2.get_string(&t2);
1726
1727        assert_eq!(a.as_str(), "aaaaaabbbbbb");
1728        assert_eq!(a, b);
1729    }
1730
1731    #[test]
1732    fn delete_single_block_start() {
1733        let doc = Doc::new();
1734        let txt = doc.get_or_insert_text("test");
1735        let mut txn = doc.transact_mut();
1736
1737        txt.insert(&mut txn, 0, "bbb");
1738        txt.insert(&mut txn, 0, "aaa");
1739        txt.remove_range(&mut txn, 0, 3);
1740
1741        assert_eq!(txt.len(&txn), 3);
1742        assert_eq!(txt.get_string(&txn).as_str(), "bbb");
1743    }
1744
1745    #[test]
1746    fn delete_single_block_end() {
1747        let doc = Doc::new();
1748        let txt = doc.get_or_insert_text("test");
1749        let mut txn = doc.transact_mut();
1750
1751        txt.insert(&mut txn, 0, "bbb");
1752        txt.insert(&mut txn, 0, "aaa");
1753        txt.remove_range(&mut txn, 3, 3);
1754
1755        assert_eq!(txt.get_string(&txn).as_str(), "aaa");
1756    }
1757
1758    #[test]
1759    fn delete_multiple_whole_blocks() {
1760        let doc = Doc::new();
1761        let txt = doc.get_or_insert_text("test");
1762        let mut txn = doc.transact_mut();
1763
1764        txt.insert(&mut txn, 0, "a");
1765        txt.insert(&mut txn, 1, "b");
1766        txt.insert(&mut txn, 2, "c");
1767
1768        txt.remove_range(&mut txn, 1, 1);
1769        assert_eq!(txt.get_string(&txn).as_str(), "ac");
1770
1771        txt.remove_range(&mut txn, 1, 1);
1772        assert_eq!(txt.get_string(&txn).as_str(), "a");
1773
1774        txt.remove_range(&mut txn, 0, 1);
1775        assert_eq!(txt.get_string(&txn).as_str(), "");
1776    }
1777
1778    #[test]
1779    fn delete_slice_of_block() {
1780        let doc = Doc::new();
1781        let txt = doc.get_or_insert_text("test");
1782        let mut txn = doc.transact_mut();
1783
1784        txt.insert(&mut txn, 0, "abc");
1785        txt.remove_range(&mut txn, 1, 1);
1786
1787        assert_eq!(txt.get_string(&txn).as_str(), "ac");
1788    }
1789
1790    #[test]
1791    fn delete_multiple_blocks_with_slicing() {
1792        let doc = Doc::new();
1793        let txt = doc.get_or_insert_text("test");
1794        let mut txn = doc.transact_mut();
1795
1796        txt.insert(&mut txn, 0, "hello ");
1797        txt.insert(&mut txn, 6, "beautiful");
1798        txt.insert(&mut txn, 15, " world");
1799
1800        txt.remove_range(&mut txn, 5, 11);
1801        assert_eq!(txt.get_string(&txn).as_str(), "helloworld");
1802    }
1803
1804    #[test]
1805    fn insert_after_delete() {
1806        let doc = Doc::new();
1807        let txt = doc.get_or_insert_text("test");
1808        let mut txn = doc.transact_mut();
1809
1810        txt.insert(&mut txn, 0, "hello ");
1811        txt.remove_range(&mut txn, 0, 5);
1812        txt.insert(&mut txn, 1, "world");
1813
1814        assert_eq!(txt.get_string(&txn).as_str(), " world");
1815    }
1816
1817    #[test]
1818    fn concurrent_insert_delete() {
1819        let d1 = Doc::with_client_id(1);
1820        let txt1 = d1.get_or_insert_text("test");
1821        let mut t1 = d1.transact_mut();
1822
1823        txt1.insert(&mut t1, 0, "hello world");
1824        assert_eq!(txt1.get_string(&t1).as_str(), "hello world");
1825
1826        let u1 = t1.encode_state_as_update_v1(&StateVector::default());
1827
1828        let d2 = Doc::with_client_id(2);
1829        let txt2 = d2.get_or_insert_text("test");
1830        let mut t2 = d2.transact_mut();
1831        t2.apply_update(Update::decode_v1(u1.as_slice()).unwrap())
1832            .unwrap();
1833        assert_eq!(txt2.get_string(&t2).as_str(), "hello world");
1834
1835        txt1.insert(&mut t1, 5, " beautiful");
1836        txt1.insert(&mut t1, 21, "!");
1837        txt1.remove_range(&mut t1, 0, 5);
1838        assert_eq!(txt1.get_string(&t1).as_str(), " beautiful world!");
1839
1840        txt2.remove_range(&mut t2, 5, 5);
1841        txt2.remove_range(&mut t2, 0, 1);
1842        txt2.insert(&mut t2, 0, "H");
1843        assert_eq!(txt2.get_string(&t2).as_str(), "Hellod");
1844
1845        let sv1 = t1.state_vector().encode_v1();
1846        let sv2 = t2.state_vector().encode_v1();
1847        let u1 = t1.encode_diff_v1(&StateVector::decode_v1(&sv2.as_slice()).unwrap());
1848        let u2 = t2.encode_diff_v1(&StateVector::decode_v1(&sv1.as_slice()).unwrap());
1849
1850        t1.apply_update(Update::decode_v1(u2.as_slice()).unwrap())
1851            .unwrap();
1852        t2.apply_update(Update::decode_v1(u1.as_slice()).unwrap())
1853            .unwrap();
1854
1855        let a = txt1.get_string(&t1);
1856        let b = txt2.get_string(&t2);
1857
1858        assert_eq!(a, b);
1859        assert_eq!(a, "H beautifuld!".to_owned());
1860    }
1861
1862    #[test]
1863    fn observer() {
1864        let doc = Doc::with_client_id(1);
1865        let txt = doc.get_or_insert_text("text");
1866        let delta = Arc::new(ArcSwapOption::default());
1867        let delta_c = delta.clone();
1868        let sub = txt.observe(move |txn, e| {
1869            delta_c.store(Some(Arc::new(e.delta(txn).to_vec())));
1870        });
1871
1872        // insert initial data to an empty YText
1873        txt.insert(&mut doc.transact_mut(), 0, "abcd"); // => 'abcd'
1874        assert_eq!(
1875            delta.load_full(),
1876            Some(Arc::new(vec![Delta::Inserted("abcd".into(), None)]))
1877        );
1878
1879        // remove 2 chars from the middle
1880        txt.remove_range(&mut doc.transact_mut(), 1, 2); // => 'ad'
1881        assert_eq!(
1882            delta.load_full(),
1883            Some(Arc::new(vec![Delta::Retain(1, None), Delta::Deleted(2)]))
1884        );
1885
1886        // insert new item in the middle
1887        let attrs = Attrs::from([("bold".into(), true.into())]);
1888        txt.insert_with_attributes(&mut doc.transact_mut(), 1, "e", attrs.clone()); // => 'a<bold>e</bold>d'
1889        assert_eq!(
1890            delta.load_full(),
1891            Some(Arc::new(vec![
1892                Delta::Retain(1, None),
1893                Delta::Inserted("e".into(), Some(Box::new(attrs)))
1894            ]))
1895        );
1896
1897        // remove formatting
1898        let attrs = Attrs::from([("bold".into(), Any::Null)]);
1899        txt.format(&mut doc.transact_mut(), 1, 1, attrs.clone()); // => 'aed'
1900        assert_eq!(
1901            delta.swap(None),
1902            Some(Arc::new(vec![
1903                Delta::Retain(1, None),
1904                Delta::Retain(2, Some(Box::new(attrs)))
1905            ]))
1906        );
1907
1908        // free the observer and make sure that callback is no longer called
1909        drop(sub);
1910        txt.insert(&mut doc.transact_mut(), 1, "fgh"); // => 'afghed'
1911        assert_eq!(delta.swap(None), None);
1912    }
1913
1914    #[test]
1915    fn insert_and_remove_event_changes() {
1916        let d1 = Doc::with_client_id(1);
1917        let txt = d1.get_or_insert_text("text");
1918        let delta = Arc::new(ArcSwapOption::default());
1919        let delta_c = delta.clone();
1920        let _sub = txt.observe(move |txn, e| delta_c.store(Some(Arc::new(e.delta(txn).to_vec()))));
1921
1922        // insert initial string
1923        {
1924            let mut txn = d1.transact_mut();
1925            txt.insert(&mut txn, 0, "abcd");
1926        }
1927        assert_eq!(
1928            delta.swap(None),
1929            Some(Arc::new(vec![Delta::Inserted("abcd".into(), None)]))
1930        );
1931
1932        // remove middle
1933        {
1934            let mut txn = d1.transact_mut();
1935            txt.remove_range(&mut txn, 1, 2);
1936        }
1937        assert_eq!(
1938            delta.swap(None),
1939            Some(Arc::new(vec![Delta::Retain(1, None), Delta::Deleted(2)]))
1940        );
1941
1942        // insert again
1943        {
1944            let mut txn = d1.transact_mut();
1945            txt.insert(&mut txn, 1, "ef");
1946        }
1947        assert_eq!(
1948            delta.swap(None),
1949            Some(Arc::new(vec![
1950                Delta::Retain(1, None),
1951                Delta::Inserted("ef".into(), None)
1952            ]))
1953        );
1954
1955        // replicate data to another peer
1956        let d2 = Doc::with_client_id(2);
1957        let txt = d2.get_or_insert_text("text");
1958        let delta_c = delta.clone();
1959        let _sub = txt.observe(move |txn, e| delta_c.store(Some(Arc::new(e.delta(txn).to_vec()))));
1960
1961        {
1962            let t1 = d1.transact_mut();
1963            let mut t2 = d2.transact_mut();
1964
1965            let sv = t2.state_vector();
1966            let mut encoder = EncoderV1::new();
1967            t1.encode_diff(&sv, &mut encoder);
1968            t2.apply_update(Update::decode_v1(encoder.to_vec().as_slice()).unwrap())
1969                .unwrap();
1970        }
1971
1972        assert_eq!(
1973            delta.swap(None),
1974            Some(Arc::new(vec![Delta::Inserted("aefd".into(), None)]))
1975        );
1976    }
1977
1978    fn text_transactions() -> [Box<dyn Fn(&mut Doc, &mut Rng)>; 2] {
1979        fn insert_text(doc: &mut Doc, rng: &mut Rng) {
1980            let ytext = doc.get_or_insert_text("text");
1981            let mut txn = doc.transact_mut();
1982            let pos = rng.between(0, ytext.len(&txn));
1983            let word = rng.random_string();
1984            ytext.insert(&mut txn, pos, word.as_str());
1985        }
1986
1987        fn delete_text(doc: &mut Doc, rng: &mut Rng) {
1988            let ytext = doc.get_or_insert_text("text");
1989            let mut txn = doc.transact_mut();
1990            let len = ytext.len(&txn);
1991            if len > 0 {
1992                let pos = rng.between(0, len - 1);
1993                let to_delete = rng.between(2, len - pos);
1994                ytext.remove_range(&mut txn, pos, to_delete);
1995            }
1996        }
1997
1998        [Box::new(insert_text), Box::new(delete_text)]
1999    }
2000
2001    fn fuzzy(iterations: usize) {
2002        run_scenario(0, &text_transactions(), 5, iterations)
2003    }
2004
2005    #[test]
2006    fn fuzzy_test_3() {
2007        fuzzy(3)
2008    }
2009
2010    #[test]
2011    fn basic_format() {
2012        let d1 = Doc::with_client_id(1);
2013        let txt1 = d1.get_or_insert_text("text");
2014
2015        let delta1 = Arc::new(ArcSwapOption::default());
2016        let delta_clone = delta1.clone();
2017        let _sub1 =
2018            txt1.observe(move |txn, e| delta_clone.store(Some(Arc::new(e.delta(txn).to_vec()))));
2019
2020        let d2 = Doc::with_client_id(2);
2021        let txt2 = d2.get_or_insert_text("text");
2022
2023        let delta2 = Arc::new(ArcSwapOption::default());
2024        let delta_clone = delta2.clone();
2025        let _sub2 =
2026            txt2.observe(move |txn, e| delta_clone.store(Some(Arc::new(e.delta(txn).to_vec()))));
2027
2028        let a: Attrs = HashMap::from([("bold".into(), Any::Bool(true))]);
2029
2030        // step 1
2031        {
2032            let mut txn = d1.transact_mut();
2033            txt1.insert_with_attributes(&mut txn, 0, "abc", a.clone());
2034            let update = txn.encode_update_v1();
2035            drop(txn);
2036
2037            let expected = Some(Arc::new(vec![Delta::Inserted(
2038                "abc".into(),
2039                Some(Box::new(a.clone())),
2040            )]));
2041
2042            assert_eq!(txt1.get_string(&d1.transact()), "abc".to_string());
2043            assert_eq!(
2044                txt1.diff(&d1.transact(), YChange::identity),
2045                vec![Diff::new("abc".into(), Some(Box::new(a.clone())))]
2046            );
2047            assert_eq!(delta1.swap(None), expected);
2048
2049            let mut txn = d2.transact_mut();
2050            txn.apply_update(Update::decode_v1(update.as_slice()).unwrap())
2051                .unwrap();
2052            drop(txn);
2053
2054            assert_eq!(txt2.get_string(&d2.transact()), "abc".to_string());
2055            assert_eq!(delta2.swap(None), expected);
2056        }
2057
2058        // step 2
2059        {
2060            let mut txn = d1.transact_mut();
2061            txt1.remove_range(&mut txn, 0, 1);
2062            let update = txn.encode_update_v1();
2063            drop(txn);
2064
2065            let expected = Some(Arc::new(vec![Delta::Deleted(1)]));
2066
2067            assert_eq!(txt1.get_string(&d1.transact()), "bc".to_string());
2068            assert_eq!(
2069                txt1.diff(&d1.transact(), YChange::identity),
2070                vec![Diff::new("bc".into(), Some(Box::new(a.clone())))]
2071            );
2072            assert_eq!(delta1.swap(None), expected);
2073
2074            let mut txn = d2.transact_mut();
2075            txn.apply_update(Update::decode_v1(update.as_slice()).unwrap())
2076                .unwrap();
2077            drop(txn);
2078
2079            assert_eq!(txt2.get_string(&d2.transact()), "bc".to_string());
2080            assert_eq!(delta2.swap(None), expected);
2081        }
2082
2083        // step 3
2084        {
2085            let mut txn = d1.transact_mut();
2086            txt1.remove_range(&mut txn, 1, 1);
2087            let update = txn.encode_update_v1();
2088            drop(txn);
2089
2090            let expected = Some(Arc::new(vec![Delta::Retain(1, None), Delta::Deleted(1)]));
2091
2092            assert_eq!(txt1.get_string(&d1.transact()), "b".to_string());
2093            assert_eq!(
2094                txt1.diff(&d1.transact(), YChange::identity),
2095                vec![Diff::new("b".into(), Some(Box::new(a.clone())))]
2096            );
2097            assert_eq!(delta1.swap(None), expected);
2098
2099            let mut txn = d2.transact_mut();
2100            txn.apply_update(Update::decode_v1(update.as_slice()).unwrap())
2101                .unwrap();
2102            drop(txn);
2103
2104            assert_eq!(txt2.get_string(&d2.transact()), "b".to_string());
2105            assert_eq!(delta2.swap(None), expected);
2106        }
2107
2108        // step 4
2109        {
2110            let mut txn = d1.transact_mut();
2111            txt1.insert_with_attributes(&mut txn, 0, "z", a.clone());
2112            let update = txn.encode_update_v1();
2113            drop(txn);
2114
2115            let expected = Some(Arc::new(vec![Delta::Inserted(
2116                "z".into(),
2117                Some(Box::new(a.clone())),
2118            )]));
2119
2120            assert_eq!(txt1.get_string(&d1.transact()), "zb".to_string());
2121            assert_eq!(
2122                txt1.diff(&mut d1.transact_mut(), YChange::identity),
2123                vec![Diff::new("zb".into(), Some(Box::new(a.clone())))]
2124            );
2125            assert_eq!(delta1.swap(None), expected);
2126
2127            let mut txn = d2.transact_mut();
2128            txn.apply_update(Update::decode_v1(update.as_slice()).unwrap())
2129                .unwrap();
2130            drop(txn);
2131
2132            assert_eq!(txt2.get_string(&d2.transact()), "zb".to_string());
2133            assert_eq!(delta2.swap(None), expected);
2134        }
2135
2136        // step 5
2137        {
2138            let mut txn = d1.transact_mut();
2139            txt1.insert(&mut txn, 0, "y");
2140            let update = txn.encode_update_v1();
2141            drop(txn);
2142
2143            let expected = Some(Arc::new(vec![Delta::Inserted("y".into(), None)]));
2144
2145            assert_eq!(txt1.get_string(&d1.transact()), "yzb".to_string());
2146            assert_eq!(
2147                txt1.diff(&mut d1.transact_mut(), YChange::identity),
2148                vec![
2149                    Diff::new("y".into(), None),
2150                    Diff::new("zb".into(), Some(Box::new(a.clone())))
2151                ]
2152            );
2153            assert_eq!(delta1.swap(None), expected);
2154
2155            let mut txn = d2.transact_mut();
2156            txn.apply_update(Update::decode_v1(update.as_slice()).unwrap())
2157                .unwrap();
2158            drop(txn);
2159
2160            assert_eq!(txt2.get_string(&d2.transact()), "yzb".to_string());
2161            assert_eq!(delta2.swap(None), expected);
2162        }
2163
2164        // step 6
2165        {
2166            let mut txn = d1.transact_mut();
2167            let b: Attrs = HashMap::from([("bold".into(), Any::Null)]);
2168            txt1.format(&mut txn, 0, 2, b.clone());
2169            let update = txn.encode_update_v1();
2170            drop(txn);
2171
2172            let expected = Some(Arc::new(vec![
2173                Delta::Retain(1, None),
2174                Delta::Retain(1, Some(Box::new(b))),
2175            ]));
2176
2177            assert_eq!(txt1.get_string(&d1.transact()), "yzb".to_string());
2178            assert_eq!(
2179                txt1.diff(&mut d1.transact_mut(), YChange::identity),
2180                vec![
2181                    Diff::new("yz".into(), None),
2182                    Diff::new("b".into(), Some(Box::new(a.clone())))
2183                ]
2184            );
2185            assert_eq!(delta1.swap(None), expected);
2186
2187            let mut txn = d2.transact_mut();
2188            txn.apply_update(Update::decode_v1(update.as_slice()).unwrap())
2189                .unwrap();
2190            drop(txn);
2191
2192            assert_eq!(txt2.get_string(&d2.transact()), "yzb".to_string());
2193            assert_eq!(delta2.swap(None), expected);
2194        }
2195    }
2196
2197    #[test]
2198    fn embed_with_attributes() {
2199        let d1 = Doc::with_client_id(1);
2200        let txt1 = d1.get_or_insert_text("text");
2201
2202        let delta1 = Arc::new(ArcSwapOption::default());
2203        let delta_clone = delta1.clone();
2204        let _sub1 = txt1.observe(move |txn, e| {
2205            let delta = e.delta(txn).to_vec();
2206            delta_clone.store(Some(Arc::new(delta)));
2207        });
2208
2209        let a1: Attrs = HashMap::from([("bold".into(), true.into())]);
2210        let embed = any!({
2211            "image": "imageSrc.png"
2212        });
2213
2214        let (update_v1, update_v2) = {
2215            let mut txn = d1.transact_mut();
2216            txt1.insert_with_attributes(&mut txn, 0, "ab", a1.clone());
2217
2218            let a2: Attrs = HashMap::from([("width".into(), Any::Number(100.0))]);
2219
2220            txt1.insert_embed_with_attributes(&mut txn, 1, embed.clone(), a2.clone());
2221            drop(txn);
2222
2223            let a1 = Some(Box::new(a1.clone()));
2224            let a2 = Some(Box::new(a2.clone()));
2225
2226            let expected = Some(Arc::new(vec![
2227                Delta::Inserted("a".into(), a1.clone()),
2228                Delta::Inserted(embed.clone().into(), a2.clone()),
2229                Delta::Inserted("b".into(), a1.clone()),
2230            ]));
2231            assert_eq!(delta1.swap(None), expected);
2232
2233            let expected = vec![
2234                Diff::new("a".into(), a1.clone()),
2235                Diff::new(embed.clone().into(), a2),
2236                Diff::new("b".into(), a1.clone()),
2237            ];
2238            let mut txn = d1.transact_mut();
2239            assert_eq!(txt1.diff(&mut txn, YChange::identity), expected);
2240
2241            let update_v1 = txn.encode_state_as_update_v1(&StateVector::default());
2242            let update_v2 = txn.encode_state_as_update_v2(&StateVector::default());
2243            (update_v1, update_v2)
2244        };
2245
2246        let a1 = Some(Box::new(a1));
2247        let a2 = Some(Box::new(HashMap::from([(
2248            "width".into(),
2249            Any::Number(100.0),
2250        )])));
2251
2252        let expected = vec![
2253            Diff::new("a".into(), a1.clone()),
2254            Diff::new(embed.into(), a2),
2255            Diff::new("b".into(), a1.clone()),
2256        ];
2257
2258        let d2 = Doc::new();
2259        let txt2 = d2.get_or_insert_text("text");
2260        {
2261            let txn = &mut d2.transact_mut();
2262            let update = Update::decode_v1(&update_v1).unwrap();
2263            txn.apply_update(update).unwrap();
2264            assert_eq!(txt2.diff(txn, YChange::identity), expected);
2265        }
2266
2267        let d3 = Doc::new();
2268        let txt3 = d3.get_or_insert_text("text");
2269        {
2270            let txn = &mut d3.transact_mut();
2271            let update = Update::decode_v2(&update_v2).unwrap();
2272            txn.apply_update(update).unwrap();
2273            let actual = txt3.diff(txn, YChange::identity);
2274            assert_eq!(actual, expected);
2275        }
2276    }
2277
2278    #[test]
2279    fn issue_101() {
2280        let d1 = Doc::with_client_id(1);
2281        let txt1 = d1.get_or_insert_text("text");
2282        let delta = Arc::new(ArcSwapOption::default());
2283        let delta_copy = delta.clone();
2284
2285        let attrs: Attrs = HashMap::from([("bold".into(), true.into())]);
2286
2287        txt1.insert(&mut d1.transact_mut(), 0, "abcd");
2288
2289        let _sub = txt1.observe(move |txn, e| {
2290            delta_copy.store(Some(e.delta(txn).to_vec().into()));
2291        });
2292        txt1.format(&mut d1.transact_mut(), 1, 2, attrs.clone());
2293
2294        let expected = Arc::new(vec![
2295            Delta::Retain(1, None),
2296            Delta::Retain(2, Some(Box::new(attrs))),
2297        ]);
2298        let actual = delta.load_full();
2299        assert_eq!(actual, Some(expected));
2300    }
2301
2302    #[test]
2303    fn yrs_delete() {
2304        let doc = Doc::with_options(Options {
2305            offset_kind: OffsetKind::Utf16,
2306            ..Default::default()
2307        });
2308
2309        let text1 = r#"
2310		Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eleifend mi in nulla posuere sollicitudin. Lorem mollis aliquam ut porttitor. Enim ut sem viverra aliquet eget sit amet. Sed turpis tincidunt id aliquet risus feugiat in ante metus. Accumsan lacus vel facilisis volutpat. Non consectetur a erat nam at lectus urna. Enim diam vulputate ut pharetra sit amet. In dictum non consectetur a erat. Bibendum at varius vel pharetra vel turpis nunc eget lorem. Blandit cursus risus at ultrices. Sed lectus vestibulum mattis ullamcorper velit sed ullamcorper. Sagittis nisl rhoncus mattis rhoncus.
2311
2312		Sed vulputate odio ut enim. Erat pellentesque adipiscing commodo elit at imperdiet dui. Ultricies tristique nulla aliquet enim tortor at auctor urna nunc. Tincidunt eget nullam non nisi est sit amet. Sed adipiscing diam donec adipiscing tristique risus nec. Risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est. Donec enim diam vulputate ut pharetra sit amet aliquam id. Netus et malesuada fames ac turpis egestas sed tempus urna. Augue mauris augue neque gravida. Tellus orci ac auctor augue mauris augue. Ante metus dictum at tempor. Feugiat in ante metus dictum at. Vitae elementum curabitur vitae nunc sed velit dignissim. Non arcu risus quis varius quam quisque id diam vel. Fermentum leo vel orci porta non. Donec adipiscing tristique risus nec feugiat in fermentum posuere. Duis convallis convallis tellus id interdum velit laoreet id. Vel eros donec ac odio tempor orci dapibus ultrices in. At varius vel pharetra vel turpis nunc eget lorem. Blandit aliquam etiam erat velit scelerisque in.
2313		"#;
2314
2315        let text2 = r#"test"#;
2316
2317        {
2318            let text = doc.get_or_insert_text("content");
2319            let mut txn = doc.transact_mut();
2320            text.insert(&mut txn, 0, text1);
2321            txn.commit();
2322        }
2323
2324        {
2325            let text = doc.get_or_insert_text("content");
2326            let mut txn = doc.transact_mut();
2327            text.insert(&mut txn, 100, text2);
2328            txn.commit();
2329        }
2330
2331        {
2332            let text = doc.get_or_insert_text("content");
2333            let mut txn = doc.transact_mut();
2334
2335            let c1 = text1.chars().count();
2336            let c2 = text2.chars().count();
2337            let count = c1 as u32 + c2 as u32;
2338
2339            let _observer = text
2340                .observe(move |txn, edit| assert_eq!(edit.delta(txn)[0], Delta::Deleted(count)));
2341
2342            text.remove_range(&mut txn, 0, count);
2343            txn.commit();
2344        }
2345
2346        {
2347            let text = doc.get_or_insert_text("content");
2348            assert_eq!(text.get_string(&doc.transact()), "");
2349        }
2350    }
2351
2352    #[test]
2353    fn text_diff_adjacent() {
2354        let doc = Doc::with_client_id(1);
2355        let txt = doc.get_or_insert_text("text");
2356        let mut txn = doc.transact_mut();
2357        let attrs1 = Attrs::from([("a".into(), "a".into())]);
2358        txt.insert_with_attributes(&mut txn, 0, "abc", attrs1.clone());
2359        let attrs2 = Attrs::from([("a".into(), "a".into()), ("b".into(), "b".into())]);
2360        txt.insert_with_attributes(&mut txn, 3, "def", attrs2.clone());
2361
2362        let diff = txt.diff(&mut txn, YChange::identity);
2363        let expected = vec![
2364            Diff::new("abc".into(), Some(Box::new(attrs1))),
2365            Diff::new("def".into(), Some(Box::new(attrs2))),
2366        ];
2367        assert_eq!(diff, expected);
2368    }
2369
2370    #[test]
2371    fn text_remove_4_byte_range() {
2372        let d1 = Doc::new();
2373        let txt = d1.get_or_insert_text("test");
2374
2375        txt.insert(&mut d1.transact_mut(), 0, "😭😊");
2376
2377        let d2 = Doc::new();
2378        exchange_updates(&[&d1, &d2]);
2379
2380        txt.remove_range(&mut d1.transact_mut(), 0, "😭".len() as u32);
2381        assert_eq!(txt.get_string(&d1.transact()).as_str(), "😊");
2382
2383        exchange_updates(&[&d1, &d2]);
2384        let txt = d2.get_or_insert_text("test");
2385        assert_eq!(txt.get_string(&d2.transact()).as_str(), "😊");
2386    }
2387
2388    #[test]
2389    fn text_remove_3_byte_range() {
2390        let d1 = Doc::new();
2391        let txt = d1.get_or_insert_text("test");
2392
2393        txt.insert(&mut d1.transact_mut(), 0, "⏰⏳");
2394
2395        let d2 = Doc::new();
2396        exchange_updates(&[&d1, &d2]);
2397
2398        txt.remove_range(&mut d1.transact_mut(), 0, "⏰".len() as u32);
2399        assert_eq!(txt.get_string(&d1.transact()).as_str(), "⏳");
2400
2401        exchange_updates(&[&d1, &d2]);
2402        let txt = d2.get_or_insert_text("test");
2403        assert_eq!(txt.get_string(&d2.transact()).as_str(), "⏳");
2404    }
2405    #[test]
2406    fn delete_4_byte_character_from_middle() {
2407        let doc = Doc::new();
2408        let txt = doc.get_or_insert_text("test");
2409        let mut txn = doc.transact_mut();
2410
2411        txt.insert(&mut txn, 0, "😊😭");
2412        // uncomment the following line will pass the test
2413        // txt.format(&mut txn, 0, "😊".len() as u32, HashMap::new());
2414        txt.remove_range(&mut txn, "😊".len() as u32, "😭".len() as u32);
2415
2416        assert_eq!(txt.get_string(&txn).as_str(), "😊");
2417    }
2418
2419    #[test]
2420    fn delete_3_byte_character_from_middle_1() {
2421        let doc = Doc::new();
2422        let txt = doc.get_or_insert_text("test");
2423        let mut txn = doc.transact_mut();
2424
2425        txt.insert(&mut txn, 0, "⏰⏳");
2426        // uncomment the following line will pass the test
2427        // txt.format(&mut txn, 0, "⏰".len() as u32, HashMap::new());
2428        txt.remove_range(&mut txn, "⏰".len() as u32, "⏳".len() as u32);
2429
2430        assert_eq!(txt.get_string(&txn).as_str(), "⏰");
2431    }
2432
2433    #[test]
2434    fn delete_3_byte_character_from_middle_2() {
2435        let doc = Doc::new();
2436        let txt = doc.get_or_insert_text("test");
2437        let mut txn = doc.transact_mut();
2438
2439        txt.insert(&mut txn, 0, "👯🙇‍♀️🙇‍♀️⏰👩‍❤️‍💋‍👨");
2440
2441        txt.format(
2442            &mut txn,
2443            "👯".len() as u32,
2444            "🙇‍♀️🙇‍♀️".len() as u32,
2445            HashMap::new(),
2446        );
2447        txt.remove_range(&mut txn, "👯🙇‍♀️🙇‍♀️".len() as u32, "⏰".len() as u32); // will delete ⏰ and 👩‍❤️‍💋‍👨
2448
2449        assert_eq!(txt.get_string(&txn).as_str(), "👯🙇‍♀️🙇‍♀️👩‍❤️‍💋‍👨");
2450    }
2451
2452    #[test]
2453    fn delete_3_byte_character_from_middle_after_insert_and_format() {
2454        let doc = Doc::new();
2455        let txt = doc.get_or_insert_text("test");
2456        let mut txn = doc.transact_mut();
2457
2458        txt.insert(&mut txn, 0, "🙇‍♀️🙇‍♀️⏰👩‍❤️‍💋‍👨");
2459        txt.insert(&mut txn, 0, "👯");
2460        txt.format(
2461            &mut txn,
2462            "👯".len() as u32,
2463            "🙇‍♀️🙇‍♀️".len() as u32,
2464            HashMap::new(),
2465        );
2466
2467        // will delete ⏰ and 👩‍❤️‍💋‍👨
2468        txt.remove_range(&mut txn, "👯🙇‍♀️🙇‍♀️".len() as u32, "⏰".len() as u32); // will delete ⏰ and 👩‍❤️‍💋‍👨
2469
2470        assert_eq!(&txt.get_string(&txn), "👯🙇‍♀️🙇‍♀️👩‍❤️‍💋‍👨");
2471    }
2472
2473    #[test]
2474    fn delete_multi_byte_character_from_middle_after_insert_and_format() {
2475        let doc = Doc::with_client_id(1);
2476        let txt = doc.get_or_insert_text("test");
2477        let mut txn = doc.transact_mut();
2478
2479        txt.insert(&mut txn, 0, "❤️❤️🙇‍♀️🙇‍♀️⏰👩‍❤️‍💋‍👨👩‍❤️‍💋‍👨");
2480        txt.insert(&mut txn, 0, "👯");
2481        txt.format(
2482            &mut txn,
2483            "👯".len() as u32,
2484            "❤️❤️🙇‍♀️🙇‍♀️⏰".len() as u32,
2485            HashMap::new(),
2486        );
2487        txt.insert(&mut txn, "👯❤️❤️🙇‍♀️🙇‍♀️⏰".len() as u32, "⏰");
2488        txt.format(
2489            &mut txn,
2490            "👯❤️❤️🙇‍♀️🙇‍♀️⏰⏰".len() as u32,
2491            "👩‍❤️‍💋‍👨".len() as u32,
2492            HashMap::new(),
2493        );
2494        txt.remove_range(&mut txn, "👯❤️❤️🙇‍♀️🙇‍♀️⏰⏰👩‍❤️‍💋‍👩".len() as u32, "👩‍❤️‍💋‍👨".len() as u32);
2495        assert_eq!(txt.get_string(&txn).as_str(), "👯❤️❤️🙇‍♀️🙇‍♀️⏰⏰👩‍❤️‍💋‍👨");
2496    }
2497
2498    #[test]
2499    fn insert_string_with_no_attribute() {
2500        let doc = Doc::new();
2501        let txt = doc.get_or_insert_text("test");
2502        let mut txn = doc.transact_mut();
2503
2504        let attrs = Attrs::from([("a".into(), "a".into())]);
2505        txt.insert_with_attributes(&mut txn, 0, "ac", attrs.clone());
2506        txt.insert_with_attributes(&mut txn, 1, "b", Attrs::new());
2507
2508        let expect = vec![
2509            Diff::new("a".into(), Some(Box::new(attrs.clone()))),
2510            Diff::new("b".into(), None),
2511            Diff::new("c".into(), Some(Box::new(attrs.clone()))),
2512        ];
2513
2514        assert!(txt.diff(&mut txn, YChange::identity).eq(&expect))
2515    }
2516
2517    #[test]
2518    fn insert_empty_string_with_attributes() {
2519        let doc = Doc::new();
2520        let txt = doc.get_or_insert_text("test");
2521        let mut txn = doc.transact_mut();
2522
2523        let attrs = Attrs::from([("a".into(), "a".into())]);
2524        txt.insert(&mut txn, 0, "abc");
2525        txt.insert(&mut txn, 1, ""); // nothing changes
2526        txt.insert_with_attributes(&mut txn, 1, "", attrs); // nothing changes
2527
2528        assert_eq!(txt.get_string(&txn).as_str(), "abc");
2529
2530        let bin = txn.encode_state_as_update_v1(&StateVector::default());
2531
2532        let doc = Doc::new();
2533        let txt = doc.get_or_insert_text("test");
2534        let mut txn = doc.transact_mut();
2535        let update = Update::decode_v1(bin.as_slice()).unwrap();
2536        txn.apply_update(update).unwrap();
2537
2538        assert_eq!(txt.get_string(&txn).as_str(), "abc");
2539    }
2540
2541    #[test]
2542    fn snapshots() {
2543        let doc = Doc::with_client_id(1);
2544        let text = doc.get_or_insert_text("text");
2545        text.insert(&mut doc.transact_mut(), 0, "hello");
2546        let prev = doc.transact_mut().snapshot();
2547        text.insert(&mut doc.transact_mut(), 5, " world");
2548        let next = doc.transact_mut().snapshot();
2549        let diff = text.diff_range(
2550            &mut doc.transact_mut(),
2551            Some(&next),
2552            Some(&prev),
2553            YChange::identity,
2554        );
2555
2556        assert_eq!(
2557            diff,
2558            vec![
2559                Diff::new("hello".into(), None),
2560                Diff::with_change(
2561                    " world".into(),
2562                    None,
2563                    Some(YChange::new(
2564                        ChangeKind::Added,
2565                        ID::new(ClientID::new(1), 5)
2566                    ))
2567                )
2568            ]
2569        )
2570    }
2571
2572    #[test]
2573    fn diff_with_embedded_items() {
2574        let doc = Doc::new();
2575        let text = doc.get_or_insert_text("article");
2576        let mut txn = doc.transact_mut();
2577
2578        let bold = Attrs::from([("b".into(), true.into())]);
2579        let italic = Attrs::from([("i".into(), true.into())]);
2580
2581        text.insert_with_attributes(&mut txn, 0, "hello world", italic.clone()); // "<i>hello world</i>"
2582        text.format(&mut txn, 6, 5, bold.clone()); // "<i>hello <b>world</b></i>"
2583        let image = vec![0, 0, 0, 0];
2584        text.insert_embed(&mut txn, 5, image.clone()); // insert binary after "hello"
2585        let array = text.insert_embed(&mut txn, 5, ArrayPrelim::default()); // insert array ref after "hello"
2586
2587        let italic_and_bold = Attrs::from([("b".into(), true.into()), ("i".into(), true.into())]);
2588        let chunks = text.diff(&txn, YChange::identity);
2589        assert_eq!(
2590            chunks,
2591            vec![
2592                Diff::new("hello".into(), Some(Box::new(italic.clone()))),
2593                Diff::new(Out::YArray(array), Some(Box::new(italic.clone()))),
2594                Diff::new(image.into(), Some(Box::new(italic.clone()))),
2595                Diff::new(" ".into(), Some(Box::new(italic))),
2596                Diff::new("world".into(), Some(Box::new(italic_and_bold))),
2597            ]
2598        );
2599    }
2600
2601    #[test]
2602    fn multi_threading() {
2603        use std::sync::{Arc, RwLock};
2604        use std::thread::{sleep, spawn};
2605
2606        let doc = Arc::new(RwLock::new(Doc::with_client_id(1)));
2607
2608        let d2 = doc.clone();
2609        let h2 = spawn(move || {
2610            for _ in 0..10 {
2611                let millis = fastrand::u64(1..20);
2612                sleep(Duration::from_millis(millis));
2613
2614                let doc = d2.write().unwrap();
2615                let txt = doc.get_or_insert_text("test");
2616                let mut txn = doc.transact_mut();
2617                txt.push(&mut txn, "a");
2618            }
2619        });
2620
2621        let d3 = doc.clone();
2622        let h3 = spawn(move || {
2623            for _ in 0..10 {
2624                let millis = fastrand::u64(1..20);
2625                sleep(Duration::from_millis(millis));
2626
2627                let doc = d3.write().unwrap();
2628                let txt = doc.get_or_insert_text("test");
2629                let mut txn = doc.transact_mut();
2630                txt.push(&mut txn, "b");
2631            }
2632        });
2633
2634        h3.join().unwrap();
2635        h2.join().unwrap();
2636
2637        let doc = doc.read().unwrap();
2638        let txt = doc.get_or_insert_text("test");
2639        let len = txt.len(&doc.transact());
2640        assert_eq!(len, 20);
2641    }
2642
2643    #[test]
2644    fn multiline_format() {
2645        let doc = Doc::with_client_id(1);
2646        let mut txn = doc.transact_mut();
2647        let txt = txn.get_or_insert_text("text");
2648        let bold: Option<Box<Attrs>> = Some(Box::new(Attrs::from([("bold".into(), true.into())])));
2649        txt.insert(&mut txn, 0, "Test\nMulti-line\nFormatting");
2650        txt.apply_delta(
2651            &mut txn,
2652            [
2653                Delta::Retain(4, bold.clone()),
2654                Delta::retain(1), // newline character
2655                Delta::Retain(10, bold.clone()),
2656                Delta::retain(1), // newline character
2657                Delta::Retain(10, bold.clone()),
2658            ],
2659        );
2660        let delta = txt.diff(&txn, YChange::identity);
2661        assert_eq!(
2662            delta,
2663            vec![
2664                Diff::new("Test".into(), bold.clone()),
2665                Diff::new("\n".into(), None),
2666                Diff::new("Multi-line".into(), bold.clone()),
2667                Diff::new("\n".into(), None),
2668                Diff::new("Formatting".into(), bold),
2669            ]
2670        );
2671    }
2672
2673    #[test]
2674    fn delta_with_embeds() {
2675        let doc = Doc::with_client_id(1);
2676        let mut txn = doc.transact_mut();
2677        let txt = txn.get_or_insert_text("text");
2678        let linebreak = any!({
2679            "linebreak": "s"
2680        });
2681        txt.apply_delta(&mut txn, [Delta::insert(linebreak.clone())]);
2682        let delta = txt.diff(&txn, YChange::identity);
2683        assert_eq!(delta, vec![Diff::new(linebreak.into(), None)]);
2684    }
2685
2686    #[test]
2687    fn delta_with_shared_ref() {
2688        let d1 = Doc::with_client_id(1);
2689        let mut txn1 = d1.transact_mut();
2690        let txt1 = txn1.get_or_insert_text("text");
2691        txt1.apply_delta(
2692            &mut txn1,
2693            [Delta::insert(MapPrelim::from([("key", "val")]))],
2694        );
2695        let delta = txt1.diff(&txn1, YChange::identity);
2696        let d: MapRef = delta[0].insert.clone().cast().unwrap();
2697        assert_eq!(d.get(&txn1, "key").unwrap(), Out::Any("val".into()));
2698
2699        let triggered = Arc::new(AtomicBool::new(false));
2700        let _sub = {
2701            let triggered = triggered.clone();
2702            txt1.observe(move |txn, e| {
2703                let delta = e.delta(txn).to_vec();
2704                let d: MapRef = match &delta[0] {
2705                    Delta::Inserted(insert, _) => insert.clone().cast().unwrap(),
2706                    _ => unreachable!("unexpected delta"),
2707                };
2708                assert_eq!(d.get(txn, "key").unwrap(), Out::Any("val".into()));
2709                triggered.store(true, Ordering::Relaxed);
2710            })
2711        };
2712
2713        let d2 = Doc::with_client_id(2);
2714        let mut txn2 = d2.transact_mut();
2715        let txt2 = txn2.get_or_insert_text("text");
2716        let update = Update::decode_v1(&txn1.encode_update_v1()).unwrap();
2717        txn2.apply_update(update).unwrap();
2718        drop(txn1);
2719        drop(txn2);
2720
2721        assert!(triggered.load(Ordering::Relaxed), "fired event");
2722
2723        let delta = txt2.diff(&d2.transact(), YChange::identity);
2724        assert_eq!(delta.len(), 1);
2725        let d: MapRef = delta[0].insert.clone().cast().unwrap();
2726        assert_eq!(
2727            d.get(&d2.transact(), "key").unwrap(),
2728            Out::Any("val".into())
2729        );
2730    }
2731
2732    #[test]
2733    fn delta_snapshots() {
2734        let doc = Doc::with_options(Options {
2735            client_id: ClientID::new(1),
2736            skip_gc: true,
2737            ..Default::default()
2738        });
2739        let mut txn = doc.transact_mut();
2740        let txt = txn.get_or_insert_text("text");
2741        txt.apply_delta(&mut txn, [Delta::insert("abcd")]);
2742        let snapshot1 = txn.snapshot(); // 'abcd'
2743        txt.apply_delta(
2744            &mut txn,
2745            [Delta::retain(1), Delta::insert("x"), Delta::delete(1)],
2746        );
2747        let snapshot2 = txn.snapshot(); // 'axcd'
2748        txt.apply_delta(
2749            &mut txn,
2750            [
2751                Delta::retain(2),   // ax^cd
2752                Delta::delete(1),   // ax^d
2753                Delta::insert("x"), // axx^d
2754                Delta::delete(1),   // axx^
2755            ],
2756        );
2757        let state1 = txt.diff_range(&mut txn, Some(&snapshot1), None, YChange::identity);
2758        assert_eq!(state1, vec![Diff::new("abcd".into(), None)]);
2759        let state2 = txt.diff_range(&mut txn, Some(&snapshot2), None, YChange::identity);
2760        assert_eq!(state2, vec![Diff::new("axcd".into(), None)]);
2761        let state2_diff = txt.diff_range(
2762            &mut txn,
2763            Some(&snapshot2),
2764            Some(&snapshot1),
2765            YChange::identity,
2766        );
2767        assert_eq!(
2768            state2_diff,
2769            vec![
2770                Diff {
2771                    insert: "a".into(),
2772                    attributes: None,
2773                    ychange: None
2774                },
2775                Diff {
2776                    insert: "x".into(),
2777                    attributes: None,
2778                    ychange: Some(YChange {
2779                        kind: ChangeKind::Added,
2780                        id: ID::new(ClientID::new(1), 4)
2781                    })
2782                },
2783                Diff {
2784                    insert: "b".into(),
2785                    attributes: None,
2786                    ychange: Some(YChange {
2787                        kind: ChangeKind::Removed,
2788                        id: ID::new(ClientID::new(1), 1)
2789                    })
2790                },
2791                Diff {
2792                    insert: "cd".into(),
2793                    attributes: None,
2794                    ychange: None
2795                }
2796            ]
2797        );
2798    }
2799
2800    #[test]
2801    fn snapshot_delete_after() {
2802        let doc = Doc::with_options(Options {
2803            client_id: ClientID::new(1),
2804            skip_gc: true,
2805            ..Default::default()
2806        });
2807        let mut txn = doc.transact_mut();
2808        let txt = txn.get_or_insert_text("text");
2809        txt.apply_delta(&mut txn, [Delta::insert("abcd")]);
2810        let snapshot1 = txn.snapshot();
2811        txt.apply_delta(&mut txn, [Delta::retain(4), Delta::insert("e")]);
2812        let state1 = txt.diff_range(&mut txn, Some(&snapshot1), None, YChange::identity);
2813        assert_eq!(state1, vec![Diff::new("abcd".into(), None)]);
2814    }
2815
2816    #[test]
2817    fn empty_delta_chunks() {
2818        let doc = Doc::with_client_id(1);
2819        let mut txn = doc.transact_mut();
2820        let txt = txn.get_or_insert_text("text");
2821
2822        let delta = vec![
2823            Delta::insert("a"),
2824            Delta::Inserted(
2825                "".into(),
2826                Some(Box::new(Attrs::from([(
2827                    Arc::from("bold"),
2828                    Any::from(true),
2829                )]))),
2830            ),
2831            Delta::insert("b"),
2832        ];
2833
2834        txt.apply_delta(&mut txn, delta);
2835        assert_eq!(txt.get_string(&txn), "ab");
2836
2837        let bin = txn.encode_state_as_update_v1(&StateVector::default());
2838
2839        let doc2 = Doc::with_client_id(2);
2840        let mut txn = doc2.transact_mut();
2841        let txt = txn.get_or_insert_text("text");
2842
2843        let update = Update::decode_v1(bin.as_slice()).unwrap();
2844        txn.apply_update(update).unwrap();
2845        assert_eq!(txt.get_string(&txn), "ab");
2846    }
2847}