oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1use std::collections::hash_map::Entry;
2use std::collections::{Bound, HashSet};
3use std::convert::TryFrom;
4use std::marker::PhantomData;
5use std::ops::{DerefMut, RangeBounds};
6use std::sync::Arc;
7
8use thiserror::Error;
9
10use crate::block::{EmbedPrelim, ItemContent, ItemPtr, Prelim};
11use crate::iter::{
12 AsIter, BlockIterator, BlockSliceIterator, IntoBlockIter, MoveIter, RangeIter, TxnIterator,
13 Values,
14};
15use crate::types::{AsPrelim, Branch, BranchPtr, Out, Path, SharedRef, TypeRef};
16use crate::{
17 Array, Assoc, BranchID, DeepObservable, GetString, In, IndexScope, Map, Observable, ReadTxn,
18 StickyIndex, TextRef, TransactionMut, XmlTextRef, ID,
19};
20
21/// Weak link reference represents a reference to a single element or consecutive range of elements
22/// stored in another collection in the same document.
23///
24/// The same element may be linked by many [WeakRef]s, however the ownership still belongs to
25/// a collection, where referenced elements were originally inserted in. For this reason removing
26/// [WeakRef] doesn't affect linked elements. [WeakRef] can also be outdated when the linked
27/// reference has been removed.
28///
29/// In order to create a [WeakRef], a preliminary [WeakPrelim] element must be obtained first. This
30/// can be done via either:
31///
32/// - [Map::link] to pick a reference to key-value entry of map. As entry is being updated, so will
33/// be the referenced value.
34/// - [Array::quote] to take a reference to a consecutive range of array's elements. Any elements
35/// inserted in an originally quoted range will later on appear when [WeakRef::unquote] is called.
36/// - [Text::quote] to take a reference to a slice of text. When materialized, quoted slice will
37/// contain any changes that happened within the quoted slice. It will also contain formatting
38/// information about the quotation.
39///
40/// [WeakPrelim] can be used like any preliminary type (ie. inserted into array, map or as embedded
41/// value in text), producing [WeakRef] in a result. [WeakRef] can be also cloned and converted back
42/// into [WeakPrelim], allowing to reference the same element(s) in many different places.
43///
44/// [WeakRef] can also be observed on via [WeakRef::observe]/[WeakRef::observe_deep]. These enable
45/// to react to changes which happen in other parts of the document tree.
46///
47/// # Example
48///
49/// ```rust
50/// use yrs::{Array, Doc, Map, Quotable, Transact, Assoc};
51///
52/// let doc = Doc::new();
53/// let array = doc.get_or_insert_array("array");
54/// let map = doc.get_or_insert_map("map");
55/// let mut txn = doc.transact_mut();
56///
57/// // insert values
58/// array.insert_range(&mut txn, 0, ["A", "B", "C", "D"]);
59///
60/// // link the reference for value in another collection
61/// let link = array.quote(&txn, 1..=2).unwrap(); // [B, C]
62/// let link = map.insert(&mut txn, "key", link);
63///
64/// // evaluate quoted range
65/// let values: Vec<_> = link.unquote(&txn).map(|v| v.to_string(&txn)).collect();
66/// assert_eq!(values, vec!["B".to_string(), "C".to_string()]);
67///
68/// // update quoted range
69/// array.insert(&mut txn, 2, "E"); // [A, B, E, C, D]
70///
71/// // evaluate quoted range (updated)
72/// let values: Vec<_> = link.unquote(&txn).map(|v| v.to_string(&txn)).collect();
73/// assert_eq!(values, vec!["B".to_string(), "E".to_string(), "C".to_string()]);
74/// ```
75#[repr(transparent)]
76#[derive(Debug, Clone)]
77pub struct WeakRef<P>(P);
78
79impl<P: SharedRef> SharedRef for WeakRef<P> {}
80impl SharedRef for WeakRef<BranchPtr> {}
81impl<P: SharedRef> From<WeakRef<BranchPtr>> for WeakRef<P> {
82 fn from(value: WeakRef<BranchPtr>) -> Self {
83 WeakRef(P::from(value.0))
84 }
85}
86impl<P: AsRef<Branch>> AsRef<Branch> for WeakRef<P> {
87 fn as_ref(&self) -> &Branch {
88 self.0.as_ref()
89 }
90}
91impl<P: AsRef<Branch>> WeakRef<P> {
92 /// Returns a [LinkSource] corresponding with current [WeakRef].
93 /// Returns `None` if underlying branch reference was not meant to be used as [WeakRef].
94 pub fn try_source(&self) -> Option<&Arc<LinkSource>> {
95 let branch = self.as_ref();
96 if let TypeRef::WeakLink(source) = &branch.type_ref {
97 Some(source)
98 } else {
99 None
100 }
101 }
102
103 /// Returns a [LinkSource] corresponding with current [WeakRef].
104 ///
105 /// # Panics
106 ///
107 /// This method panic if an underlying branch was not meant to be used as [WeakRef]. This can
108 /// happen if a different shared type was forcibly casted to [WeakRef]. To avoid panic, use
109 /// [WeakRef::try_source] instead.
110 pub fn source(&self) -> &Arc<LinkSource> {
111 self.try_source()
112 .expect("Defect: called WeakRef-specific method over non-WeakRef shared type")
113 }
114
115 /// Returns a block [ID] to a beginning of a quoted range.
116 /// For quotes linking to a single elements this is equal to [WeakRef::end_id].
117 pub fn start_id(&self) -> Option<&ID> {
118 self.source().quote_start.id()
119 }
120
121 /// Returns a block [ID] to an ending of a quoted range.
122 /// For quotes linking to a single elements this is equal to [WeakRef::start_id].
123 pub fn end_id(&self) -> Option<&ID> {
124 self.source().quote_end.id()
125 }
126}
127
128impl<P: From<BranchPtr>> From<BranchPtr> for WeakRef<P> {
129 fn from(inner: BranchPtr) -> Self {
130 WeakRef(P::from(inner))
131 }
132}
133
134impl<P: TryFrom<ItemPtr>> TryFrom<ItemPtr> for WeakRef<P> {
135 type Error = P::Error;
136
137 fn try_from(value: ItemPtr) -> Result<Self, Self::Error> {
138 match P::try_from(value) {
139 Ok(p) => Ok(WeakRef(p)),
140 Err(e) => Err(e),
141 }
142 }
143}
144
145impl<P: From<BranchPtr>> TryFrom<Out> for WeakRef<P> {
146 type Error = Out;
147
148 fn try_from(value: Out) -> Result<Self, Self::Error> {
149 match value {
150 Out::YWeakLink(value) => Ok(WeakRef(P::from(value.0))),
151 other => Err(other),
152 }
153 }
154}
155
156impl<P: AsRef<Branch>> Eq for WeakRef<P> {}
157impl<P: AsRef<Branch>> PartialEq for WeakRef<P> {
158 fn eq(&self, other: &Self) -> bool {
159 self.as_ref().id() == other.as_ref().id()
160 }
161}
162
163impl<P> DeepObservable for WeakRef<P> where P: AsRef<Branch> {}
164impl<P> Observable for WeakRef<P>
165where
166 P: AsRef<Branch>,
167{
168 type Event = WeakEvent;
169}
170
171impl GetString for WeakRef<TextRef> {
172 /// Returns a plain string representation of an underlying range of a quoted [TextRef].
173 ///
174 /// # Example
175 ///
176 /// ```rust
177 /// use yrs::{Assoc, Doc, GetString, Map, Quotable, Text, Transact};
178 ///
179 /// let doc = Doc::new();
180 /// let text = doc.get_or_insert_text("text");
181 /// let map = doc.get_or_insert_map("map");
182 /// let mut txn = doc.transact_mut();
183 ///
184 /// // initialize text
185 /// text.insert(&mut txn, 0, "hello world!");
186 ///
187 /// // link fragment of text
188 /// let link = text.quote(&mut txn, 0..=5).unwrap(); // 'hello '
189 /// let link = map.insert(&mut txn, "key", link);
190 ///
191 /// // check the quoted fragment
192 /// assert_eq!(link.get_string(&txn), "hello ".to_string());
193 /// ```
194 fn get_string<T: ReadTxn>(&self, txn: &T) -> String {
195 self.source().to_string(txn)
196 }
197}
198
199impl GetString for WeakRef<XmlTextRef> {
200 /// Returns a XML-formatted string representation of an underlying range of a quoted [XmlTextRef].
201 ///
202 /// # Example
203 ///
204 /// ```rust
205 /// use yrs::{Assoc, Doc, GetString, Map, Quotable, Text, Transact, XmlFragment, XmlTextPrelim};
206 /// use yrs::types::Attrs;
207 ///
208 /// let doc = Doc::new();
209 /// let f = doc.get_or_insert_xml_fragment("xml");
210 /// let map = doc.get_or_insert_map("map");
211 /// let mut txn = doc.transact_mut();
212 /// let text = f.insert(&mut txn, 0, XmlTextPrelim::new("Bold, italic text"));
213 ///
214 /// // add formatting
215 /// let italic = Attrs::from([("i".into(), true.into())]);
216 /// let bold = Attrs::from([("b".into(), true.into())]);
217 /// text.format(&mut txn, 0, 4, bold); // '<b>Bold</b>, italic text'
218 /// text.format(&mut txn, 6, 6, italic); // '<b>Bold</b>, <i>italic</i> text'
219 ///
220 /// // link fragment of text
221 /// let link = text.quote(&mut txn, 1..=10).unwrap(); // '<b>old</b>, <i>itali</i>'
222 /// let link = map.insert(&mut txn, "key", link);
223 ///
224 /// // check the quoted fragment
225 /// assert_eq!(link.get_string(&txn), "<b>old</b>, <i>itali</i>".to_string());
226 /// ```
227 fn get_string<T: ReadTxn>(&self, txn: &T) -> String {
228 self.source().to_xml_string(txn)
229 }
230}
231
232impl<P: AsRef<Branch>> WeakRef<P> {
233 pub fn into_inner(self) -> WeakRef<BranchPtr> {
234 WeakRef(BranchPtr::from(self.0.as_ref()))
235 }
236}
237
238impl<P> WeakRef<P>
239where
240 P: SharedRef + Map,
241{
242 /// Tries to dereference a value for linked [Map] entry, performing automatic conversion if
243 /// possible. If conversion was not possible or element didn't exist, an error case will be
244 /// returned.
245 ///
246 /// Use [WeakRef::try_deref_value] if conversion is not possible or desired at the current moment.
247 pub fn try_deref<T, V>(&self, txn: &T) -> Result<V, Option<V::Error>>
248 where
249 T: ReadTxn,
250 V: TryFrom<Out>,
251 {
252 if let Some(value) = self.try_deref_value(txn) {
253 match V::try_from(value) {
254 Ok(value) => Ok(value),
255 Err(value) => Err(Some(value)),
256 }
257 } else {
258 Err(None)
259 }
260 }
261
262 /// Tries to dereference a value for linked [Map] entry. If element didn't exist, `None` will
263 /// be returned.
264 ///
265 /// # Example
266 ///
267 /// ```rust
268 /// use yrs::{Doc, Map, Transact};
269 ///
270 /// let doc = Doc::new();
271 /// let map = doc.get_or_insert_map("map");
272 /// let mut txn = doc.transact_mut();
273 ///
274 /// // insert a value and the link referencing it
275 /// map.insert(&mut txn, "A", "value");
276 /// let link = map.link(&txn, "A").unwrap();
277 /// let link = map.insert(&mut txn, "B", link);
278 ///
279 /// assert_eq!(link.try_deref_value(&txn), Some("value".into()));
280 ///
281 /// // update entry and check if link has been updated
282 /// map.insert(&mut txn, "A", "other");
283 /// assert_eq!(link.try_deref_value(&txn), Some("other".into()));
284 /// ```
285 pub fn try_deref_value<T: ReadTxn>(&self, txn: &T) -> Option<Out> {
286 let source = self.try_source()?;
287 let item = source.quote_start.get_item(txn);
288 let last = item.to_iter().last()?;
289 if last.is_deleted() {
290 None
291 } else {
292 last.content.get_last()
293 }
294 }
295}
296
297impl<P> WeakRef<P>
298where
299 P: SharedRef + Array,
300{
301 /// Returns an iterator over [Out]s existing in a scope of the current [WeakRef] quotation
302 /// range.
303 pub fn unquote<'a, T: ReadTxn>(&self, txn: &'a T) -> Unquote<'a, T> {
304 if let Some(source) = self.try_source() {
305 source.unquote(txn)
306 } else {
307 Unquote::empty()
308 }
309 }
310}
311
312impl<V> AsPrelim for WeakRef<V>
313where
314 V: AsRef<Branch> + TryFrom<ItemPtr>,
315{
316 type Prelim = WeakPrelim<V>;
317
318 fn as_prelim<T: ReadTxn>(&self, _txn: &T) -> Self::Prelim {
319 let source = self.try_source().unwrap();
320 WeakPrelim::with_source(source.clone())
321 }
322}
323
324/// A preliminary type for [WeakRef]. Once inserted into document it can be used as a weak reference
325/// link to another value living inside of the document store.
326#[derive(Debug, Clone, Eq, PartialEq)]
327pub struct WeakPrelim<P> {
328 source: Arc<LinkSource>,
329 _marker: PhantomData<P>,
330}
331
332impl<P> WeakPrelim<P> {
333 pub(crate) fn new(start: StickyIndex, end: StickyIndex) -> Self {
334 let source = Arc::new(LinkSource::new(start, end));
335 WeakPrelim {
336 source,
337 _marker: PhantomData::default(),
338 }
339 }
340 pub(crate) fn with_source(source: Arc<LinkSource>) -> Self {
341 WeakPrelim {
342 source,
343 _marker: PhantomData::default(),
344 }
345 }
346
347 pub fn into_inner(&self) -> WeakPrelim<BranchPtr> {
348 WeakPrelim {
349 source: self.source.clone(),
350 _marker: PhantomData::default(),
351 }
352 }
353
354 pub fn source(&self) -> &Arc<LinkSource> {
355 &self.source
356 }
357}
358
359impl<P> WeakPrelim<P>
360where
361 P: SharedRef + Array,
362{
363 /// Returns an iterator over [Out]s existing in a scope of the current [WeakPrelim] quotation
364 /// range.
365 pub fn unquote<'a, T: ReadTxn>(&self, txn: &'a T) -> Unquote<'a, T> {
366 self.source.unquote(txn)
367 }
368}
369
370impl<P> WeakPrelim<P>
371where
372 P: SharedRef + Map,
373{
374 pub fn try_deref_raw<T: ReadTxn>(&self, txn: &T) -> Option<Out> {
375 self.source.unquote(txn).next()
376 }
377
378 pub fn try_deref<T, V>(&self, txn: &T) -> Result<V, Option<V::Error>>
379 where
380 T: ReadTxn,
381 V: TryFrom<Out>,
382 {
383 if let Some(value) = self.try_deref_raw(txn) {
384 match V::try_from(value) {
385 Ok(value) => Ok(value),
386 Err(value) => Err(Some(value)),
387 }
388 } else {
389 Err(None)
390 }
391 }
392}
393
394impl GetString for WeakPrelim<TextRef> {
395 fn get_string<T: ReadTxn>(&self, txn: &T) -> String {
396 self.source.to_string(txn)
397 }
398}
399
400impl GetString for WeakPrelim<XmlTextRef> {
401 fn get_string<T: ReadTxn>(&self, txn: &T) -> String {
402 self.source.to_xml_string(txn)
403 }
404}
405
406impl<P: AsRef<Branch>> From<WeakRef<P>> for WeakPrelim<P> {
407 fn from(value: WeakRef<P>) -> Self {
408 let branch = value.0.as_ref();
409 if let TypeRef::WeakLink(source) = &branch.type_ref {
410 WeakPrelim {
411 source: source.clone(),
412 _marker: PhantomData::default(),
413 }
414 } else {
415 panic!("Defect: WeakRef's underlying branch is not matching expected weak ref.")
416 }
417 }
418}
419
420impl<P: AsRef<Branch>> WeakPrelim<P> {
421 pub fn upcast(self) -> WeakPrelim<BranchPtr> {
422 WeakPrelim {
423 source: self.source,
424 _marker: Default::default(),
425 }
426 }
427}
428
429impl<P: TryFrom<ItemPtr>> Prelim for WeakPrelim<P> {
430 type Return = WeakRef<P>;
431
432 fn into_content(self, _txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
433 let inner = Branch::new(TypeRef::WeakLink(self.source.clone()));
434 (ItemContent::Type(inner), Some(self))
435 }
436
437 fn integrate(self, _txn: &mut TransactionMut, _inner_ref: BranchPtr) {}
438}
439
440impl<P: SharedRef> From<WeakPrelim<BranchPtr>> for WeakPrelim<P> {
441 fn from(value: WeakPrelim<BranchPtr>) -> Self {
442 WeakPrelim {
443 source: value.source,
444 _marker: Default::default(),
445 }
446 }
447}
448
449impl<P> Into<EmbedPrelim<WeakPrelim<P>>> for WeakPrelim<P> {
450 fn into(self) -> EmbedPrelim<WeakPrelim<P>> {
451 EmbedPrelim::Shared(self)
452 }
453}
454
455impl<T> From<WeakPrelim<T>> for In {
456 #[inline]
457 fn from(value: WeakPrelim<T>) -> Self {
458 In::WeakLink(value.into_inner())
459 }
460}
461
462pub struct WeakEvent {
463 pub(crate) current_target: BranchPtr,
464 target: BranchPtr,
465}
466
467impl WeakEvent {
468 pub(crate) fn new(branch_ref: BranchPtr) -> Self {
469 let current_target = branch_ref.clone();
470 WeakEvent {
471 target: branch_ref,
472 current_target,
473 }
474 }
475
476 pub fn as_target<T: From<BranchPtr>>(&self) -> WeakRef<T> {
477 WeakRef(T::from(self.target))
478 }
479
480 /// Returns a path from root type down to [Text] instance which emitted this event.
481 pub fn path(&self) -> Path {
482 Branch::path(self.current_target, self.target)
483 }
484}
485
486#[derive(Debug, Eq, PartialEq)]
487pub struct LinkSource {
488 pub(crate) quote_start: StickyIndex,
489 pub(crate) quote_end: StickyIndex,
490}
491
492impl LinkSource {
493 pub fn new(start: StickyIndex, end: StickyIndex) -> Self {
494 LinkSource {
495 quote_start: start,
496 quote_end: end,
497 }
498 }
499
500 #[inline]
501 pub fn is_single(&self) -> bool {
502 match (self.quote_start.scope(), self.quote_end.scope()) {
503 (IndexScope::Relative(x), IndexScope::Relative(y)) => x == y,
504 _ => false,
505 }
506 }
507
508 /// Remove reference to current weak link from all items it quotes.
509 pub(crate) fn unlink_all(&self, txn: &mut TransactionMut, branch_ptr: BranchPtr) {
510 let item = self.quote_start.get_item(txn);
511 let mut i = item.to_iter().moved();
512 while let Some(item) = i.next(txn) {
513 if item.info.is_linked() {
514 txn.unlink(item, branch_ptr);
515 }
516 }
517 }
518
519 pub(crate) fn unquote<'a, T: ReadTxn>(&self, txn: &'a T) -> Unquote<'a, T> {
520 let mut current = self.quote_start.get_item(txn);
521 if let Some(ptr) = &mut current {
522 if Self::try_right_most(ptr) {
523 current = Some(*ptr);
524 }
525 }
526 if let Some(item) = current.as_deref() {
527 let parent = *item.parent.as_branch().unwrap();
528 Unquote::new(
529 txn,
530 parent,
531 self.quote_start.clone(),
532 self.quote_end.clone(),
533 )
534 } else {
535 Unquote::empty()
536 }
537 }
538
539 /// If provided ref is pointing to map type which has been updated, we may want to invalidate
540 /// current pointer to point to its right most neighbor.
541 fn try_right_most(item: &mut ItemPtr) -> bool {
542 if item.parent_sub.is_some() {
543 // for map types go to the most recent one
544 if let Some(curr_block) = item.right.to_iter().last() {
545 *item = curr_block;
546 return true;
547 }
548 }
549 false
550 }
551
552 pub(crate) fn materialize(&self, txn: &mut TransactionMut, inner_ref: BranchPtr) {
553 let curr = if let Some(ptr) = self.quote_start.get_item(txn) {
554 ptr
555 } else {
556 // referenced element has already been GCed
557 return;
558 };
559 if curr.parent_sub.is_some() {
560 // for maps, advance to most recent item
561 if let Some(mut last) = Some(curr).to_iter().last() {
562 last.info.set_linked();
563 let linked_by = txn.store.linked_by.entry(last).or_default();
564 linked_by.insert(inner_ref);
565 }
566 } else {
567 let mut first = true;
568 let from = self.quote_start.clone();
569 let to = self.quote_end.clone();
570 let mut i = Some(curr).to_iter().moved().within_range(from, to);
571 while let Some(slice) = i.next(txn) {
572 let mut item = if !slice.adjacent() {
573 txn.store.materialize(slice)
574 } else {
575 slice.ptr
576 };
577 if first {
578 first = false;
579 }
580 item.info.set_linked();
581 let linked_by = txn.store.linked_by.entry(item).or_default();
582 linked_by.insert(inner_ref);
583 }
584 }
585 }
586
587 pub fn to_string<T: ReadTxn>(&self, txn: &T) -> String {
588 let mut result = String::new();
589 let mut curr = self.quote_start.get_item(txn);
590 let end = self.quote_end.id();
591 while let Some(item) = curr.as_deref() {
592 if let Some(end) = end {
593 if self.quote_end.assoc == Assoc::Before && &item.id == end {
594 // right side is open (last item excluded)
595 break;
596 }
597 }
598 if !item.is_deleted() {
599 if let ItemContent::String(s) = &item.content {
600 result.push_str(s.as_str());
601 }
602 }
603 if let Some(end) = end {
604 if self.quote_end.assoc == Assoc::After && &item.last_id() == end {
605 // right side is closed (last item included)
606 break;
607 }
608 }
609 curr = item.right;
610 }
611 result
612 }
613
614 pub fn to_xml_string<T: ReadTxn>(&self, txn: &T) -> String {
615 let curr = self.quote_start.get_item(txn);
616 if let Some(item) = curr.as_deref() {
617 if let Some(branch) = item.parent.as_branch() {
618 return XmlTextRef::get_string_fragment(
619 branch.start,
620 Some(&self.quote_start),
621 Some(&self.quote_end),
622 );
623 }
624 }
625 String::new()
626 }
627}
628
629/// Iterator over non-deleted items, bounded by the given ID range.
630pub struct Unquote<'a, T>(Option<AsIter<'a, T, Values<RangeIter<MoveIter>>>>);
631
632impl<'a, T: ReadTxn> Unquote<'a, T> {
633 fn new(txn: &'a T, parent: BranchPtr, from: StickyIndex, to: StickyIndex) -> Self {
634 let iter = parent
635 .start
636 .to_iter()
637 .moved()
638 .within_range(from, to)
639 .values();
640 Unquote(Some(AsIter::new(iter, txn)))
641 }
642
643 fn empty() -> Self {
644 Unquote(None)
645 }
646}
647
648impl<'a, T: ReadTxn> Iterator for Unquote<'a, T> {
649 type Item = Out;
650
651 fn next(&mut self) -> Option<Self::Item> {
652 let iter = self.0.as_mut()?;
653 iter.next()
654 }
655}
656
657/// Trait which defines a capability to quote a range of elements from implementing collection
658/// and referencing them later in other collections.
659pub trait Quotable: AsRef<Branch> + Sized {
660 /// Returns [WeakPrelim] to a given range of elements, if it's in a boundaries of a current
661 /// quotable collection.
662 ///
663 /// Quoted ranges inclusivity define behavior of quote in face of concurrent inserts that might
664 /// have happen, example:
665 /// - Inclusive range (eg. `1..=2`) means, that any concurrent inserts that happen between
666 /// indexes 2 and 3 will **not** be part of the quoted range.
667 /// - Exclusive range (eg. `1..3`) theoretically being similar to an upper one, will behave
668 /// differently as for concurrent inserts on 2nd and 3rd index boundary, these inserts will be
669 /// counted as a part of quoted range.
670 ///
671 /// # Errors
672 ///
673 /// This method may return an [QuoteError::OutOfBounds] if passed range params span beyond
674 /// the boundaries of a current collection ie. `0..yarray.len()` will error, as the upper index
675 /// refers to position that's not present in current collection - even though the position
676 /// itself is not included in range it still has to exists as a point of reference.
677 ///
678 /// Currently this method doesn't support unbounded ranges (ie. `..n`, `n..`). Passing such
679 /// range will cause [QuoteError::UnboundedRange] error.
680 ///
681 /// # Example
682 /// ```
683 /// use yrs::{Doc, Transact, Array, Assoc, Quotable};
684 /// let doc = Doc::new();
685 /// let array = doc.get_or_insert_array("array");
686 /// array.insert_range(&mut doc.transact_mut(), 0, [1,2,3,4]);
687 /// // quote elements 2 and 3
688 /// let prelim = array.quote(&doc.transact(), 1..3).unwrap();
689 /// let quote = array.insert(&mut doc.transact_mut(), 0, prelim);
690 /// // retrieve quoted values
691 /// let quoted: Vec<_> = quote.unquote(&doc.transact()).collect();
692 /// assert_eq!(quoted, vec![2.into(), 3.into()]);
693 /// ```
694 fn quote<T, R>(&self, txn: &T, range: R) -> Result<WeakPrelim<Self>, QuoteError>
695 where
696 T: ReadTxn,
697 R: RangeBounds<u32>,
698 {
699 let this = BranchPtr::from(self.as_ref());
700 let start = match range.start_bound() {
701 Bound::Included(&i) => Some((i, Assoc::Before)),
702 Bound::Excluded(&i) => Some((i, Assoc::After)),
703 Bound::Unbounded => None,
704 };
705 let end = match range.end_bound() {
706 Bound::Included(&i) => Some((i, Assoc::After)),
707 Bound::Excluded(&i) => Some((i, Assoc::Before)),
708 Bound::Unbounded => None,
709 };
710 let encoding = txn.store().offset_kind;
711 let mut start_index = 0;
712 let mut remaining = start_index;
713 let mut curr = None;
714 let mut i = this.start.to_iter().moved();
715
716 let start = if let Some((start_i, assoc_start)) = start {
717 start_index = start_i;
718 remaining = start_index;
719 // figure out the first ID
720 curr = i.next(txn);
721 while let Some(item) = curr.as_deref() {
722 if remaining == 0 {
723 break;
724 }
725 if !item.is_deleted() && item.is_countable() {
726 let len = item.content_len(encoding);
727 if remaining < len {
728 break;
729 }
730 remaining -= len;
731 }
732 curr = i.next(txn);
733 }
734 let start_id = if let Some(item) = curr.as_deref() {
735 let mut id = item.id.clone();
736 id.clock += if let ItemContent::String(s) = &item.content {
737 s.block_offset(remaining, encoding)
738 } else {
739 remaining
740 };
741 id
742 } else {
743 return Err(QuoteError::OutOfBounds);
744 };
745 StickyIndex::new(IndexScope::Relative(start_id), assoc_start)
746 } else {
747 curr = i.next(txn);
748 StickyIndex::new(IndexScope::from_branch(this), Assoc::Before)
749 };
750
751 let end = if let Some((end_index, assoc_end)) = end {
752 // figure out the last ID
753 remaining = end_index - start_index + remaining;
754 while let Some(item) = curr.as_deref() {
755 if !item.is_deleted() && item.is_countable() {
756 let len = item.content_len(encoding);
757 if remaining < len {
758 break;
759 }
760 remaining -= len;
761 }
762 curr = i.next(txn);
763 }
764 let end_id = if let Some(item) = curr.as_deref() {
765 let mut id = item.id.clone();
766 id.clock += if let ItemContent::String(s) = &item.content {
767 s.block_offset(remaining, encoding)
768 } else {
769 remaining
770 };
771 id
772 } else {
773 return Err(QuoteError::OutOfBounds);
774 };
775 StickyIndex::new(IndexScope::Relative(end_id), assoc_end)
776 } else {
777 StickyIndex::new(IndexScope::from_branch(this), Assoc::After)
778 };
779
780 let source = LinkSource::new(start, end);
781 Ok(WeakPrelim::with_source(Arc::new(source)))
782 }
783}
784
785/// Error that may appear in result of [Quotable::quote] method call.
786#[derive(Debug, Error)]
787pub enum QuoteError {
788 /// Range lower or upper indexes passed to [Quotable::quote] were beyond scope of quoted
789 /// collection.
790 ///
791 /// Remember: even though range itself may not include index (ie. `1..n`), that index still
792 /// needs to point to existing value within quoted collection (`n < ytype.len()`) as a point
793 /// of reference.
794 #[error("Quoted range spans beyond the bounds of current collection")]
795 OutOfBounds,
796}
797
798pub(crate) fn join_linked_range(mut block: ItemPtr, txn: &mut TransactionMut) {
799 let block_copy = block.clone();
800 let item = block.deref_mut();
801 // this item may exists within a quoted range
802 item.info.set_linked();
803 // we checked if left and right exists before this method call
804 let left = item.left.unwrap();
805 let right = item.right.unwrap();
806 let all_links = &mut txn.store.linked_by;
807 let left_links = all_links.get(&left);
808 let right_links = all_links.get(&right);
809 let mut common = HashSet::new();
810 if let Some(llinks) = left_links {
811 for link in llinks.iter() {
812 match right_links {
813 Some(rlinks) if rlinks.contains(link) => {
814 // new item existing in a quoted range in between two elements
815 common.insert(*link);
816 }
817 _ => {
818 if let TypeRef::WeakLink(source) = &link.type_ref {
819 if source.quote_end.assoc == Assoc::Before {
820 // We're at the right edge of quoted range - right neighbor is not included
821 // but the left one is. Since quotation is open on the right side, we need to
822 // include current item.
823 common.insert(*link);
824 }
825 }
826 }
827 }
828 }
829 }
830 if let Some(rlinks) = right_links {
831 for link in rlinks.iter() {
832 match left_links {
833 Some(llinks) if llinks.contains(link) => {
834 /* already visited by previous if-loop */
835 }
836 _ => {
837 if let TypeRef::WeakLink(source) = &link.type_ref {
838 if source.quote_start.assoc == Assoc::After {
839 let start_id = source.quote_start.id().cloned();
840 let prev_id = item.left.map(|i| i.last_id());
841 if start_id == prev_id {
842 // even though current boundary if left-side exclusive, current item
843 // has been inserted on the right of it, therefore it's within range
844 common.insert(*link);
845 }
846 }
847 }
848 }
849 }
850 }
851 }
852 if !common.is_empty() {
853 match all_links.entry(block) {
854 Entry::Occupied(mut e) => {
855 let links = e.get_mut();
856 for link in common {
857 links.insert(link);
858 }
859 }
860 Entry::Vacant(e) => {
861 e.insert(common);
862 }
863 }
864 }
865}
866
867#[cfg(test)]
868mod test {
869 use std::collections::{Bound, HashMap};
870 use std::ops::RangeBounds;
871 use std::sync::{Arc, Mutex};
872
873 use arc_swap::ArcSwapOption;
874
875 use crate::test_utils::exchange_updates;
876 use crate::types::text::YChange;
877 use crate::types::weak::{WeakPrelim, WeakRef};
878 use crate::types::{Attrs, EntryChange, Event, Out, ToJson};
879 use crate::Assoc::{After, Before};
880 use crate::{
881 Array, ArrayRef, DeepObservable, Doc, GetString, Map, MapPrelim, MapRef, Observable,
882 Quotable, ReadTxn, Text, TextRef, Transact, WriteTxn, XmlTextRef,
883 };
884
885 #[test]
886 fn basic_map_link() {
887 let doc = Doc::new();
888 let map = doc.get_or_insert_map("map");
889 let mut txn = doc.transact_mut();
890 let nested = MapPrelim::from([("a1".to_owned(), "hello".to_owned())]);
891 let nested = map.insert(&mut txn, "a", nested);
892 let link = map.link(&txn, "a").unwrap();
893 map.insert(&mut txn, "b", link);
894
895 let link = map
896 .get(&txn, "b")
897 .unwrap()
898 .cast::<WeakRef<MapRef>>()
899 .unwrap();
900
901 let expected = nested.to_json(&txn);
902 let deref: MapRef = link.try_deref(&txn).unwrap();
903 let actual = deref.to_json(&txn);
904
905 assert_eq!(actual, expected);
906 }
907
908 #[test]
909 fn basic_array_link() {
910 let d1 = Doc::with_client_id(1);
911 let a1 = d1.get_or_insert_array("array");
912 {
913 let mut txn = d1.transact_mut();
914
915 a1.insert_range(&mut txn, 0, [1, 2, 3]);
916 let link = a1.quote(&txn, 1..2).unwrap();
917 a1.insert(&mut txn, 3, link);
918
919 assert_eq!(a1.get(&txn, 0), Some(1.into()));
920 assert_eq!(a1.get(&txn, 1), Some(2.into()));
921 assert_eq!(a1.get(&txn, 2), Some(3.into()));
922 let mut u = a1
923 .get(&txn, 3)
924 .unwrap()
925 .cast::<WeakRef<ArrayRef>>()
926 .unwrap()
927 .unquote(&txn);
928 assert_eq!(u.next(), Some(2.into()));
929 assert_eq!(u.next(), None);
930 }
931
932 let d2 = Doc::new();
933 let a2 = d2.get_or_insert_array("array");
934
935 exchange_updates(&[&d1, &d2]);
936 let txn = d2.transact_mut();
937
938 assert_eq!(a2.get(&txn, 0), Some(1.into()));
939 assert_eq!(a2.get(&txn, 1), Some(2.into()));
940 assert_eq!(a2.get(&txn, 2), Some(3.into()));
941 let actual: Vec<_> = a2
942 .get(&txn, 3)
943 .unwrap()
944 .cast::<WeakRef<ArrayRef>>()
945 .unwrap()
946 .unquote(&txn)
947 .collect();
948 assert_eq!(actual, vec![2.into()]);
949 }
950
951 #[test]
952 fn array_quote_multi_elements() {
953 let d1 = Doc::with_client_id(1);
954 let a1 = d1.get_or_insert_array("array");
955 let d2 = Doc::with_client_id(2);
956 let a2 = d2.get_or_insert_array("array");
957
958 let nested = {
959 let mut txn = d1.transact_mut();
960 a1.insert_range(&mut txn, 0, [1, 2]);
961 let nested = a1.push_back(&mut txn, MapPrelim::from([("key", "value")]));
962 a1.push_back(&mut txn, 3);
963 nested
964 };
965 let l1 = {
966 let mut t1 = d1.transact_mut();
967 let prelim = a1.quote(&t1, 1..=3).unwrap();
968 a1.insert(&mut t1, 0, prelim)
969 };
970
971 let t1 = d1.transact();
972 assert_eq!(
973 l1.unquote(&t1).collect::<Vec<Out>>(),
974 vec![2.into(), Out::YMap(nested.clone()), 3.into()]
975 );
976 assert_eq!(a1.get(&t1, 1), Some(1.into()));
977 assert_eq!(a1.get(&t1, 2), Some(2.into()));
978 assert_eq!(a1.get(&t1, 3), Some(Out::YMap(nested.clone())));
979 assert_eq!(a1.get(&t1, 4), Some(3.into()));
980 drop(t1);
981
982 exchange_updates(&[&d1, &d2]);
983
984 let t2 = d2.transact();
985 let l2 = a2.get(&t2, 0).unwrap().cast::<WeakRef<ArrayRef>>().unwrap();
986 let unquoted: Vec<_> = l2.unquote(&t2).map(|v| v.to_string(&t2)).collect();
987 assert_eq!(
988 unquoted,
989 vec![
990 "2".to_string(),
991 r#"{key: value}"#.to_string(),
992 "3".to_string()
993 ]
994 );
995 assert_eq!(a2.get(&t2, 1), Some(1.into()));
996 assert_eq!(a2.get(&t2, 2), Some(2.into()));
997 assert_eq!(
998 a2.get(&t2, 3).map(|v| v.to_string(&t2)),
999 Some(r#"{key: value}"#.to_string())
1000 );
1001 assert_eq!(a2.get(&t2, 4), Some(3.into()));
1002 drop(t2);
1003
1004 a2.insert_range(&mut d2.transact_mut(), 3, ["A", "B"]);
1005
1006 let t2 = d2.transact();
1007 let unquoted: Vec<_> = l2.unquote(&t2).map(|v| v.to_string(&t2)).collect();
1008 assert_eq!(
1009 unquoted,
1010 vec![
1011 "2".to_string(),
1012 "A".to_string(),
1013 "B".to_string(),
1014 r#"{key: value}"#.to_string(),
1015 "3".to_string()
1016 ]
1017 );
1018 drop(t2);
1019
1020 exchange_updates(&[&d1, &d2]);
1021
1022 assert_eq!(
1023 l1.unquote(&d1.transact()).collect::<Vec<Out>>(),
1024 vec![
1025 2.into(),
1026 "A".into(),
1027 "B".into(),
1028 Out::YMap(nested.clone()),
1029 3.into()
1030 ]
1031 );
1032 }
1033
1034 #[test]
1035 fn self_quotation() {
1036 let d1 = Doc::with_client_id(1);
1037 let a1 = d1.get_or_insert_array("array");
1038 let d2 = Doc::with_client_id(2);
1039 let a2 = d2.get_or_insert_array("array");
1040
1041 a1.insert_range(&mut d1.transact_mut(), 0, [1, 2, 3, 4]);
1042 let l1 = a1.quote(&d1.transact(), 0..3).unwrap();
1043 // link is inserted into its own range
1044 let l1 = a1.insert(&mut d1.transact_mut(), 1, l1);
1045 let t1 = d1.transact();
1046 let mut u = l1.unquote(&t1);
1047 assert_eq!(u.next(), Some(1.into()));
1048 assert_eq!(u.next(), Some(Out::YWeakLink(l1.clone().into_inner())));
1049 assert_eq!(u.next(), Some(2.into()));
1050 assert_eq!(u.next(), Some(3.into()));
1051
1052 assert_eq!(a1.get(&t1, 0), Some(1.into()));
1053 assert_eq!(
1054 a1.get(&t1, 1),
1055 Some(Out::YWeakLink(l1.clone().into_inner()))
1056 );
1057 assert_eq!(a1.get(&t1, 2), Some(2.into()));
1058 assert_eq!(a1.get(&t1, 3), Some(3.into()));
1059 assert_eq!(a1.get(&t1, 4), Some(4.into()));
1060 drop(t1);
1061
1062 exchange_updates(&[&d1, &d2]);
1063
1064 let t2 = d2.transact();
1065 let l2 = a2.get(&t2, 1).unwrap().cast::<WeakRef<ArrayRef>>().unwrap();
1066 let unquote: Vec<_> = l2.unquote(&t2).collect();
1067 assert_eq!(
1068 unquote,
1069 vec![
1070 1.into(),
1071 Out::YWeakLink(l2.clone().into_inner()),
1072 2.into(),
1073 3.into()
1074 ]
1075 );
1076 assert_eq!(a2.get(&t2, 0), Some(1.into()));
1077 assert_eq!(a2.get(&t2, 1), Some(Out::YWeakLink(l2.into_inner())));
1078 assert_eq!(a2.get(&t2, 2), Some(2.into()));
1079 assert_eq!(a2.get(&t2, 3), Some(3.into()));
1080 assert_eq!(a2.get(&t2, 4), Some(4.into()));
1081 }
1082
1083 #[test]
1084 fn update() {
1085 let d1 = Doc::new();
1086 let m1 = d1.get_or_insert_map("map");
1087
1088 let d2 = Doc::new();
1089 let m2 = d2.get_or_insert_map("map");
1090
1091 let link1 = {
1092 let mut txn = d1.transact_mut();
1093 let nested = MapPrelim::from([("a1".to_owned(), "hello".to_owned())]);
1094 m1.insert(&mut txn, "a", nested);
1095 let link = m1.link(&txn, "a").unwrap();
1096 m1.insert(&mut txn, "b", link)
1097 };
1098
1099 exchange_updates(&[&d1, &d2]);
1100
1101 let link2 = m2
1102 .get(&d2.transact(), "b")
1103 .unwrap()
1104 .cast::<WeakRef<MapRef>>()
1105 .unwrap();
1106 let l1: MapRef = link1.try_deref(&d1.transact()).unwrap();
1107 let l2: MapRef = link2.try_deref(&d2.transact()).unwrap();
1108 assert_eq!(l1.get(&d1.transact(), "a1"), l2.get(&d2.transact(), "a1"));
1109
1110 m2.insert(&mut d2.transact_mut(), "a2", "world");
1111
1112 exchange_updates(&[&d1, &d2]);
1113
1114 let l1: MapRef = link1.try_deref(&d1.transact()).unwrap();
1115 let l2: MapRef = link2.try_deref(&d2.transact()).unwrap();
1116 assert_eq!(l1.get(&d1.transact(), "a2"), l2.get(&d2.transact(), "a2"));
1117 }
1118
1119 #[test]
1120 #[cfg_attr(target_os = "windows", ignore)]
1121 fn delete_weak_link() {
1122 let d1 = Doc::new();
1123 let m1 = d1.get_or_insert_map("map");
1124
1125 let d2 = Doc::new();
1126 let m2 = d2.get_or_insert_map("map");
1127
1128 let link1 = {
1129 let mut txn = d1.transact_mut();
1130 let nested = MapPrelim::from([("a1".to_owned(), "hello".to_owned())]);
1131 m1.insert(&mut txn, "a", nested);
1132 let link = m1.link(&txn, "a").unwrap();
1133 m1.insert(&mut txn, "b", link)
1134 };
1135
1136 exchange_updates(&[&d1, &d2]);
1137
1138 let link2 = m2
1139 .get(&d2.transact(), "b")
1140 .unwrap()
1141 .cast::<WeakRef<MapRef>>()
1142 .unwrap();
1143 let l1: MapRef = link1.try_deref(&d1.transact()).unwrap();
1144 let l2: MapRef = link2.try_deref(&d2.transact()).unwrap();
1145 assert_eq!(l1.get(&d1.transact(), "a1"), l2.get(&d2.transact(), "a1"));
1146
1147 m2.remove(&mut d2.transact_mut(), "b"); // delete links
1148
1149 exchange_updates(&[&d1, &d2]);
1150
1151 // since links have been deleted, they no longer refer to any content
1152 assert_eq!(link1.try_deref_value(&d1.transact()), None);
1153 assert_eq!(link2.try_deref_value(&d2.transact()), None);
1154 }
1155
1156 #[test]
1157 fn delete_source() {
1158 let d1 = Doc::new();
1159 let m1 = d1.get_or_insert_map("map");
1160
1161 let d2 = Doc::new();
1162 let m2 = d2.get_or_insert_map("map");
1163
1164 let link1 = {
1165 let mut txn = d1.transact_mut();
1166 let nested = MapPrelim::from([("a1".to_owned(), "hello".to_owned())]);
1167 m1.insert(&mut txn, "a", nested);
1168 let link = m1.link(&txn, "a").unwrap();
1169 m1.insert(&mut txn, "b", link)
1170 };
1171
1172 exchange_updates(&[&d1, &d2]);
1173
1174 let link2 = m2
1175 .get(&d2.transact(), "b")
1176 .unwrap()
1177 .cast::<WeakRef<MapRef>>()
1178 .unwrap();
1179 let l1: MapRef = link1.try_deref(&d1.transact()).unwrap();
1180 let l2: MapRef = link2.try_deref(&d2.transact()).unwrap();
1181 assert_eq!(l1.get(&d1.transact(), "a1"), l2.get(&d2.transact(), "a1"));
1182
1183 m2.remove(&mut d2.transact_mut(), "a"); // delete source of the link
1184
1185 exchange_updates(&[&d1, &d2]);
1186
1187 // since links have been deleted, they no longer refer to any content
1188 assert_eq!(link1.try_deref_value(&d1.transact()), None);
1189 assert_eq!(link2.try_deref_value(&d2.transact()), None);
1190 }
1191
1192 #[test]
1193 fn observe_map_update() {
1194 let d1 = Doc::new();
1195 let m1 = d1.get_or_insert_map("map");
1196 let d2 = Doc::new();
1197 let m2 = d2.get_or_insert_map("map");
1198
1199 let link1 = {
1200 let mut txn = d1.transact_mut();
1201 m1.insert(&mut txn, "a", "value");
1202 let link1 = m1.link(&txn, "a").unwrap();
1203 m1.insert(&mut txn, "b", link1)
1204 };
1205
1206 let target1 = Arc::new(ArcSwapOption::default());
1207 let _sub1 = {
1208 let target = target1.clone();
1209 link1.observe(move |_, e| target.store(Some(Arc::new(e.target.clone()))))
1210 };
1211
1212 exchange_updates(&[&d1, &d2]);
1213
1214 let link2 = m2
1215 .get(&d2.transact(), "b")
1216 .unwrap()
1217 .cast::<WeakRef<MapRef>>()
1218 .unwrap();
1219 assert_eq!(link2.try_deref_value(&d2.transact()), Some("value".into()));
1220
1221 let target2 = Arc::new(ArcSwapOption::default());
1222 let _sub2 = {
1223 let target = target2.clone();
1224 link2.observe(move |_, e| target.store(Some(Arc::new(e.target.clone()))))
1225 };
1226
1227 m1.insert(&mut d1.transact_mut(), "a", "value2");
1228 assert_eq!(link1.try_deref_value(&d1.transact()), Some("value2".into()));
1229
1230 exchange_updates(&[&d1, &d2]);
1231 assert_eq!(link2.try_deref_value(&d2.transact()), Some("value2".into()));
1232 }
1233
1234 #[test]
1235 fn observe_map_delete() {
1236 let d1 = Doc::new();
1237 let m1 = d1.get_or_insert_map("map");
1238 let d2 = Doc::new();
1239 let m2 = d2.get_or_insert_map("map");
1240
1241 let link1 = {
1242 let mut txn = d1.transact_mut();
1243 m1.insert(&mut txn, "a", "value");
1244 let link1 = m1.link(&txn, "a").unwrap();
1245 m1.insert(&mut txn, "b", link1)
1246 };
1247
1248 let target1 = Arc::new(ArcSwapOption::default());
1249 let _sub1 = {
1250 let target = target1.clone();
1251 link1.observe(move |_, e| target.store(Some(Arc::new(e.as_target::<MapRef>()))))
1252 };
1253
1254 exchange_updates(&[&d1, &d2]);
1255
1256 let link2 = m2
1257 .get(&d2.transact(), "b")
1258 .unwrap()
1259 .cast::<WeakRef<MapRef>>()
1260 .unwrap();
1261 assert_eq!(link2.try_deref_value(&d2.transact()), Some("value".into()));
1262
1263 let target2 = Arc::new(ArcSwapOption::default());
1264 let _sub2 = {
1265 let target = target2.clone();
1266 link2.observe(move |_, e| target.store(Some(Arc::new(e.as_target::<MapRef>()))))
1267 };
1268
1269 m1.remove(&mut d1.transact_mut(), "a");
1270 let l1 = target1.swap(None).unwrap();
1271 assert_eq!(l1.try_deref_value(&d1.transact()), None);
1272
1273 exchange_updates(&[&d1, &d2]);
1274 let l2 = target2.swap(None).unwrap();
1275 assert_eq!(l2.try_deref_value(&d2.transact()), None);
1276 }
1277
1278 #[test]
1279 fn observe_array() {
1280 let d1 = Doc::with_client_id(1);
1281 let a1 = d1.get_or_insert_array("array");
1282 let d2 = Doc::with_client_id(2);
1283 let a2 = d2.get_or_insert_array("array");
1284
1285 let link1 = {
1286 let mut txn = d1.transact_mut();
1287 a1.insert_range(&mut txn, 0, ["A", "B", "C"]);
1288 let link1 = a1.quote(&txn, 1..=2).unwrap();
1289 a1.insert(&mut txn, 0, link1)
1290 };
1291
1292 let target1 = Arc::new(ArcSwapOption::default());
1293 let _sub1 = {
1294 let target = target1.clone();
1295 link1.observe(move |_, e| target.store(Some(Arc::new(e.as_target::<ArrayRef>()))))
1296 };
1297
1298 exchange_updates(&[&d1, &d2]);
1299
1300 let link2 = a2
1301 .get(&d2.transact(), 0)
1302 .unwrap()
1303 .cast::<WeakRef<ArrayRef>>()
1304 .unwrap();
1305 let actual: Vec<_> = link2.unquote(&d2.transact()).collect();
1306 assert_eq!(actual, vec!["B".into(), "C".into()]);
1307
1308 let target2 = Arc::new(ArcSwapOption::default());
1309 let _sub2 = {
1310 let target = target2.clone();
1311 link2.observe(move |_, e| target.store(Some(Arc::new(e.as_target::<ArrayRef>()))))
1312 };
1313
1314 a1.remove(&mut d1.transact_mut(), 2);
1315 let actual: Vec<_> = link1.unquote(&d1.transact()).collect();
1316 assert_eq!(actual, vec!["C".into()]);
1317
1318 exchange_updates(&[&d1, &d2]);
1319 let l2 = target2.swap(None).unwrap();
1320 let actual: Vec<_> = l2.unquote(&d2.transact()).collect();
1321 assert_eq!(actual, vec!["C".into()]);
1322
1323 a2.remove(&mut d2.transact_mut(), 2);
1324 let l2 = target2.swap(None).unwrap();
1325 let actual: Vec<_> = l2.unquote(&d2.transact()).collect();
1326 assert_eq!(actual, vec![]);
1327
1328 exchange_updates(&[&d1, &d2]);
1329 let l1 = target1.swap(None).unwrap();
1330 let actual: Vec<_> = l1.unquote(&d1.transact()).collect();
1331 assert_eq!(actual, vec![]);
1332
1333 a1.remove(&mut d1.transact_mut(), 1);
1334 assert_eq!(target1.swap(None), None);
1335 }
1336
1337 #[test]
1338 fn deep_observe_transitive() {
1339 /*
1340 Structure:
1341 - map1
1342 - link-key: <=+-+
1343 - map2: | |
1344 - key: value1-+ |
1345 - link-link: <--+
1346 */
1347 let doc = Doc::new();
1348 let m1 = doc.get_or_insert_map("map1");
1349 let m2 = doc.get_or_insert_map("map2");
1350 let mut txn = doc.transact_mut();
1351
1352 // test observers in a face of linked chains of values
1353 m2.insert(&mut txn, "key", "value1");
1354 let link1 = m2.link(&txn, "key").unwrap();
1355 m1.insert(&mut txn, "link-key", link1);
1356 let link2 = m1.link(&txn, "link-key").unwrap();
1357 let link2 = m2.insert(&mut txn, "link-link", link2);
1358 drop(txn);
1359
1360 let events = Arc::new(Mutex::new(vec![]));
1361 let _sub1 = {
1362 let events = events.clone();
1363 link2.observe_deep(move |_, evts| {
1364 let mut er = events.lock().unwrap();
1365 for e in evts.iter() {
1366 er.push(e.target());
1367 }
1368 })
1369 };
1370 m2.insert(&mut doc.transact_mut(), "key", "value2");
1371 let actual: Vec<_> = events
1372 .lock()
1373 .unwrap()
1374 .iter()
1375 .flat_map(|v| {
1376 v.clone()
1377 .cast::<WeakRef<MapRef>>()
1378 .unwrap()
1379 .try_deref_value(&doc.transact())
1380 })
1381 .collect();
1382 assert_eq!(actual, vec!["value2".into()])
1383 }
1384
1385 #[test]
1386 fn deep_observe_transitive2() {
1387 /*
1388 Structure:
1389 - map1
1390 - link-key: <=+-+
1391 - map2: | |
1392 - key: value1-+ |
1393 - link-link: <==+--+
1394 - map3: |
1395 - link-link-link:<-+
1396 */
1397 let doc = Doc::new();
1398 let m1 = doc.get_or_insert_map("map1");
1399 let m2 = doc.get_or_insert_map("map2");
1400 let m3 = doc.get_or_insert_map("map3");
1401 let mut txn = doc.transact_mut();
1402
1403 // test observers in a face of multi-layer linked chains of values
1404 m2.insert(&mut txn, "key", "value1");
1405 let link1 = m2.link(&txn, "key").unwrap();
1406 m1.insert(&mut txn, "link-key", link1);
1407 let link2 = m1.link(&txn, "link-key").unwrap();
1408 m2.insert(&mut txn, "link-link", link2);
1409 let link3 = m2.link(&txn, "link-link").unwrap();
1410 let link3 = m3.insert(&mut txn, "link-link-link", link3);
1411 drop(txn);
1412
1413 let events = Arc::new(Mutex::new(vec![]));
1414 let _sub1 = {
1415 let events = events.clone();
1416 link3.observe_deep(move |_, evts| {
1417 let mut er = events.lock().unwrap();
1418 for e in evts.iter() {
1419 er.push(e.target());
1420 }
1421 })
1422 };
1423 m2.insert(&mut doc.transact_mut(), "key", "value2");
1424 let mut guard = events.lock().unwrap();
1425 let actual = std::mem::take(&mut *guard);
1426 let actual: Vec<_> = actual
1427 .into_iter()
1428 .flat_map(|v| {
1429 v.cast::<WeakRef<MapRef>>()
1430 .unwrap()
1431 .try_deref_value(&doc.transact())
1432 })
1433 .collect();
1434 assert_eq!(actual, vec!["value2".into()])
1435 }
1436
1437 #[test]
1438 fn deep_observe_map() {
1439 /*
1440 Structure:
1441 - map (observed):
1442 - link:<----+
1443 - array: |
1444 0: nested:-+
1445 - key: value
1446 */
1447 let doc = Doc::with_client_id(1);
1448 let map = doc.get_or_insert_map("map");
1449 let array = doc.get_or_insert_array("array");
1450
1451 let events = Arc::new(Mutex::new(vec![]));
1452 let _sub = {
1453 let events = events.clone();
1454 map.observe_deep(move |txn, e| {
1455 let mut rs = events.lock().unwrap();
1456 for e in e.iter() {
1457 match e {
1458 Event::Map(e) => {
1459 let value = Out::YMap(e.target().clone());
1460 rs.push((value, Some(e.keys(txn).clone())));
1461 }
1462 Event::Weak(e) => {
1463 let value = Out::YWeakLink(e.as_target());
1464 rs.push((value, None));
1465 }
1466 _ => {}
1467 }
1468 }
1469 })
1470 };
1471
1472 let mut txn = doc.transact_mut();
1473 let nested = array.insert(&mut txn, 0, MapPrelim::default());
1474 let link = array.quote(&txn, 0..=0).unwrap();
1475 let link = map.insert(&mut txn, "link", link);
1476 drop(txn);
1477
1478 // update entry in linked map
1479 events.lock().unwrap().clear();
1480 nested.insert(&mut doc.transact_mut(), "key", "value");
1481 let actual = {
1482 let mut guard = events.lock().unwrap();
1483 std::mem::take(&mut *guard)
1484 };
1485 assert_eq!(
1486 actual,
1487 vec![(
1488 Out::YMap(nested.clone()),
1489 Some(HashMap::from([(
1490 Arc::from("key"),
1491 EntryChange::Inserted("value".into())
1492 )]))
1493 )]
1494 );
1495
1496 // delete entry in linked map
1497 nested.remove(&mut doc.transact_mut(), "key");
1498 let actual = {
1499 let mut guard = events.lock().unwrap();
1500 std::mem::take(&mut *guard)
1501 };
1502 assert_eq!(
1503 actual,
1504 vec![(
1505 Out::YMap(nested.clone()),
1506 Some(HashMap::from([(
1507 Arc::from("key"),
1508 EntryChange::Removed("value".into())
1509 )]))
1510 )]
1511 );
1512
1513 // delete linked map
1514 array.remove(&mut doc.transact_mut(), 0);
1515 let actual = {
1516 let mut guard = events.lock().unwrap();
1517 std::mem::take(&mut *guard)
1518 };
1519 assert_eq!(actual, vec![(Out::YWeakLink(link.into_inner()), None)]);
1520 }
1521
1522 #[test]
1523 fn deep_observe_array() {
1524 // test observers in a face of linked chains of values
1525 /*
1526 Structure:
1527 - map:
1528 - nested: --------+
1529 - key: value |
1530 - array (observed): |
1531 0: <--------------+
1532 */
1533 let doc = Doc::with_client_id(1);
1534 let map = doc.get_or_insert_map("map");
1535 let array = doc.get_or_insert_array("array");
1536
1537 let nested = map.insert(&mut doc.transact_mut(), "nested", MapPrelim::default());
1538 let link = map.link(&doc.transact(), "nested").unwrap();
1539 let link = array.insert(&mut doc.transact_mut(), 0, link);
1540
1541 let events = Arc::new(Mutex::new(vec![]));
1542 let _sub = {
1543 let events = events.clone();
1544 array.observe_deep(move |txn, e| {
1545 let mut events = events.lock().unwrap();
1546 for e in e.iter() {
1547 match e {
1548 Event::Map(e) => {
1549 events.push((Out::YMap(e.target().clone()), Some(e.keys(&txn).clone())))
1550 }
1551 Event::Weak(e) => events.push((Out::YWeakLink(e.as_target()), None)),
1552 _ => {}
1553 }
1554 }
1555 })
1556 };
1557 nested.insert(&mut doc.transact_mut(), "key", "value");
1558 let actual = {
1559 let mut guard = events.lock().unwrap();
1560 std::mem::take(&mut *guard)
1561 };
1562 assert_eq!(
1563 actual,
1564 vec![(
1565 Out::YMap(nested.clone()),
1566 Some(HashMap::from([(
1567 Arc::from("key"),
1568 EntryChange::Inserted("value".into())
1569 )]))
1570 )]
1571 );
1572 // update existing entry
1573 nested.insert(&mut doc.transact_mut(), "key", "value2");
1574 let actual = {
1575 let mut guard = events.lock().unwrap();
1576 std::mem::take(&mut *guard)
1577 };
1578 assert_eq!(
1579 actual,
1580 vec![(
1581 Out::YMap(nested.clone()),
1582 Some(HashMap::from([(
1583 Arc::from("key"),
1584 EntryChange::Updated("value".into(), "value2".into())
1585 )]))
1586 )]
1587 );
1588
1589 // delete entry in linked map
1590 nested.remove(&mut doc.transact_mut(), "key");
1591 let actual = {
1592 let mut guard = events.lock().unwrap();
1593 std::mem::take(&mut *guard)
1594 };
1595 assert_eq!(
1596 actual,
1597 vec![(
1598 Out::YMap(nested.clone()),
1599 Some(HashMap::from([(
1600 Arc::from("key"),
1601 EntryChange::Removed("value2".into())
1602 )]))
1603 )]
1604 );
1605
1606 // delete linked map
1607 map.remove(&mut doc.transact_mut(), "nested");
1608 let actual = {
1609 let mut guard = events.lock().unwrap();
1610 std::mem::take(&mut *guard)
1611 };
1612 assert_eq!(actual, vec![(Out::YWeakLink(link.into_inner()), None)]);
1613 }
1614
1615 #[test]
1616 fn deep_observe_new_element_within_quoted_range() {
1617 let d1 = Doc::with_client_id(1);
1618 let a1 = d1.get_or_insert_array("array");
1619 let d2 = Doc::with_client_id(2);
1620 let a2 = d2.get_or_insert_array("array");
1621
1622 {
1623 let mut t1 = d1.transact_mut();
1624 a1.push_back(&mut t1, 1);
1625 a1.push_back(&mut t1, MapPrelim::default());
1626 a1.push_back(&mut t1, MapPrelim::default());
1627 a1.push_back(&mut t1, 2);
1628 }
1629 let l1 = {
1630 let mut t1 = d1.transact_mut();
1631 let link = a1.quote(&t1, 1..=2).unwrap();
1632 a1.insert(&mut t1, 0, link)
1633 };
1634
1635 exchange_updates(&[&d1, &d2]);
1636
1637 let e1 = Arc::new(Mutex::new(vec![]));
1638 let _s1 = {
1639 let events = e1.clone();
1640 l1.observe_deep(move |txn, e| {
1641 let mut events = events.lock().unwrap();
1642 events.clear();
1643 for e in e.iter() {
1644 match e {
1645 Event::Map(e) => {
1646 events.push((Out::YMap(e.target().clone()), Some(e.keys(txn).clone())))
1647 }
1648 Event::Weak(e) => events.push((Out::YWeakLink(e.as_target()), None)),
1649 _ => {}
1650 }
1651 }
1652 })
1653 };
1654
1655 let l2 = a2
1656 .get(&d2.transact(), 0)
1657 .unwrap()
1658 .cast::<WeakRef<ArrayRef>>()
1659 .unwrap();
1660 let e2 = Arc::new(Mutex::new(vec![]));
1661 let _s2 = {
1662 let events = e2.clone();
1663 l2.observe_deep(move |txn, e| {
1664 let mut events = events.lock().unwrap();
1665 events.clear();
1666 for e in e.iter() {
1667 match e {
1668 Event::Map(e) => {
1669 events.push((Out::YMap(e.target().clone()), Some(e.keys(txn).clone())))
1670 }
1671 Event::Weak(e) => events.push((Out::YWeakLink(e.as_target()), None)),
1672 _ => {}
1673 }
1674 }
1675 })
1676 };
1677
1678 let m20 = a1.insert(&mut d1.transact_mut(), 3, MapPrelim::default());
1679 exchange_updates(&[&d1, &d2]);
1680 m20.insert(&mut d1.transact_mut(), "key", "value");
1681 assert_eq!(
1682 &*e1.lock().unwrap(),
1683 &vec![(
1684 Out::YMap(m20.clone()),
1685 Some(HashMap::from([(
1686 Arc::from("key"),
1687 EntryChange::Inserted("value".into())
1688 )]))
1689 )]
1690 );
1691
1692 exchange_updates(&[&d1, &d2]);
1693
1694 let m21 = a2.get(&d2.transact(), 3).unwrap().cast::<MapRef>().unwrap();
1695 assert_eq!(
1696 &*e2.lock().unwrap(),
1697 &vec![(
1698 Out::YMap(m21.clone()),
1699 Some(HashMap::from([(
1700 Arc::from("key"),
1701 EntryChange::Inserted("value".into())
1702 )]))
1703 )]
1704 );
1705 }
1706
1707 #[test]
1708 fn deep_observe_recursive() {
1709 // test observers in a face of cycled chains of values
1710 /*
1711 Structure:
1712 array (observed):
1713 m0:--------+
1714 - k1:<-+ |
1715 | |
1716 m1------+ |
1717 - k2:<-+ |
1718 | |
1719 m2------+ |
1720 - k0:<----+
1721 */
1722 let doc = Doc::new();
1723 let root = doc.get_or_insert_array("array");
1724 let mut txn = doc.transact_mut();
1725
1726 let m0 = root.insert(&mut txn, 0, MapPrelim::default());
1727 let m1 = root.insert(&mut txn, 1, MapPrelim::default());
1728 let m2 = root.insert(&mut txn, 2, MapPrelim::default());
1729
1730 let l0 = root.quote(&txn, 0..=0).unwrap();
1731 let l1 = root.quote(&txn, 1..=1).unwrap();
1732 let l2 = root.quote(&txn, 2..=2).unwrap();
1733
1734 // create cyclic reference between links
1735 m0.insert(&mut txn, "k1", l1);
1736 m1.insert(&mut txn, "k2", l2);
1737 m2.insert(&mut txn, "k0", l0);
1738 drop(txn);
1739
1740 let events = Arc::new(Mutex::new(vec![]));
1741 let _sub = {
1742 let events = events.clone();
1743 m0.observe_deep(move |txn, e| {
1744 let mut rs = events.lock().unwrap();
1745 for e in e.iter() {
1746 if let Event::Map(e) = e {
1747 let value = e.target().clone();
1748 rs.push((value, e.keys(txn).clone()));
1749 }
1750 }
1751 })
1752 };
1753
1754 m1.insert(&mut doc.transact_mut(), "test-key1", "value1");
1755 let actual = {
1756 let mut guard = events.lock().unwrap();
1757 std::mem::take(&mut *guard)
1758 };
1759 assert_eq!(
1760 actual,
1761 vec![(
1762 m1.clone(),
1763 HashMap::from([(
1764 Arc::from("test-key1"),
1765 EntryChange::Inserted("value1".into())
1766 )])
1767 )]
1768 );
1769
1770 m2.insert(&mut doc.transact_mut(), "test-key2", "value2");
1771 let actual = {
1772 let mut guard = events.lock().unwrap();
1773 std::mem::take(&mut *guard)
1774 };
1775 assert_eq!(
1776 actual,
1777 vec![(
1778 m2.clone(),
1779 HashMap::from([(
1780 Arc::from("test-key2"),
1781 EntryChange::Inserted("value2".into())
1782 )])
1783 )]
1784 );
1785
1786 m1.remove(&mut doc.transact_mut(), "test-key1");
1787 let actual = {
1788 let mut guard = events.lock().unwrap();
1789 std::mem::take(&mut *guard)
1790 };
1791 assert_eq!(
1792 actual,
1793 vec![(
1794 m1.clone(),
1795 HashMap::from([(
1796 Arc::from("test-key1"),
1797 EntryChange::Removed("value1".into())
1798 )])
1799 )]
1800 );
1801 }
1802
1803 #[test]
1804 fn remote_map_update() {
1805 let d1 = Doc::with_client_id(1);
1806 let m1 = d1.get_or_insert_map("map");
1807 let d2 = Doc::with_client_id(2);
1808 let m2 = d2.get_or_insert_map("map");
1809 let d3 = Doc::with_client_id(3);
1810 let m3 = d3.get_or_insert_map("map");
1811
1812 m1.insert(&mut d1.transact_mut(), "key", 1);
1813
1814 exchange_updates(&[&d1, &d2, &d3]);
1815
1816 let l2 = m2.link(&d2.transact(), "key").unwrap();
1817 m2.insert(&mut d2.transact_mut(), "link", l2);
1818 m1.insert(&mut d1.transact_mut(), "key", 2);
1819 m1.insert(&mut d1.transact_mut(), "key", 3);
1820
1821 // apply updated content first, link second
1822 exchange_updates(&[&d3, &d1]);
1823 exchange_updates(&[&d3, &d2]);
1824
1825 // make sure that link can find the most recent block
1826 let l3 = m3
1827 .get(&d3.transact(), "link")
1828 .unwrap()
1829 .cast::<WeakRef<MapRef>>()
1830 .unwrap();
1831 assert_eq!(l3.try_deref_value(&d3.transact()), Some(3.into()));
1832
1833 exchange_updates(&[&d1, &d2, &d3]);
1834
1835 let l1 = m1
1836 .get(&d1.transact(), "link")
1837 .unwrap()
1838 .cast::<WeakRef<MapRef>>()
1839 .unwrap();
1840 let l2 = m2
1841 .get(&d2.transact(), "link")
1842 .unwrap()
1843 .cast::<WeakRef<MapRef>>()
1844 .unwrap();
1845
1846 assert_eq!(l1.try_deref_value(&d1.transact()), Some(3.into()));
1847 assert_eq!(l2.try_deref_value(&d2.transact()), Some(3.into()));
1848 assert_eq!(l3.try_deref_value(&d3.transact()), Some(3.into()));
1849 }
1850
1851 #[test]
1852 fn basic_text() {
1853 let d1 = Doc::with_client_id(1);
1854 let txt1 = d1.get_or_insert_text("text");
1855 let a1 = d1.get_or_insert_array("array");
1856 let d2 = Doc::with_client_id(2);
1857 let txt2 = d2.get_or_insert_text("text");
1858
1859 txt1.insert(&mut d1.transact_mut(), 0, "abcd"); // 'abcd'
1860 let l1 = {
1861 let mut txn = d1.transact_mut();
1862 let q = txt1.quote(&mut txn, 1..=2); // quote: [bc]
1863 a1.insert(&mut txn, 0, q.unwrap())
1864 };
1865 assert_eq!(l1.get_string(&d1.transact()), "bc".to_string());
1866
1867 txt1.insert(&mut d1.transact_mut(), 2, "ef"); // 'abefcd', quote: [befc]
1868 assert_eq!(l1.get_string(&d1.transact()), "befc".to_string());
1869
1870 txt1.remove_range(&mut d1.transact_mut(), 3, 3); // 'abe', quote: [be]
1871 assert_eq!(l1.get_string(&d1.transact()), "be".to_string());
1872
1873 txt1.insert_embed(&mut d1.transact_mut(), 3, WeakPrelim::from(l1.clone())); // 'abe[be]'
1874
1875 exchange_updates(&[&d1, &d2]);
1876
1877 let diff = txt2.diff(&d2.transact(), YChange::identity);
1878 let l2 = diff[1].insert.clone().cast::<WeakRef<TextRef>>().unwrap();
1879 assert_eq!(l2.get_string(&d2.transact()), "be".to_string());
1880 }
1881
1882 #[test]
1883 fn basic_xml_text() {
1884 let d1 = Doc::with_client_id(1);
1885 let txt1 = d1.get_or_insert_text("text");
1886 let txt1: &XmlTextRef = txt1.as_ref();
1887 let a1 = d1.get_or_insert_array("array");
1888 let d2 = Doc::with_client_id(2);
1889 let txt2 = d2.get_or_insert_text("text");
1890 let txt2: &XmlTextRef = txt2.as_ref();
1891
1892 txt1.insert(&mut d1.transact_mut(), 0, "abcd"); // 'abcd'
1893 let l1 = {
1894 let mut txn = d1.transact_mut();
1895 let q = txt1.quote(&mut txn, 1..=2); // quote: [bc]
1896 a1.insert(&mut txn, 0, q.unwrap())
1897 };
1898 assert_eq!(l1.get_string(&d1.transact()), "bc".to_string());
1899
1900 txt1.insert(&mut d1.transact_mut(), 2, "ef"); // 'abefcd', quote: [befc]
1901 assert_eq!(l1.get_string(&d1.transact()), "befc".to_string());
1902
1903 txt1.remove_range(&mut d1.transact_mut(), 3, 3); // 'abe', quote: [be]
1904 assert_eq!(l1.get_string(&d1.transact()), "be".to_string());
1905
1906 txt1.insert_embed(&mut d1.transact_mut(), 3, WeakPrelim::from(l1.clone())); // 'abe[be]'
1907
1908 exchange_updates(&[&d1, &d2]);
1909
1910 let diff = txt2.diff(&d2.transact(), YChange::identity);
1911 let l2 = diff[1].insert.clone().cast::<WeakRef<TextRef>>().unwrap();
1912 assert_eq!(l2.get_string(&d2.transact()), "be".to_string());
1913 }
1914
1915 #[test]
1916 fn quote_formatted_text() {
1917 let doc = Doc::with_client_id(1);
1918 let txt1 = doc.get_or_insert_text("text1");
1919 let txt1: &XmlTextRef = txt1.as_ref();
1920 let txt2 = doc.get_or_insert_text("text2");
1921 let txt2: &XmlTextRef = txt2.as_ref();
1922 let array = doc.get_or_insert_array("array");
1923 txt1.insert(&mut doc.transact_mut(), 0, "abcde");
1924 let b = Attrs::from([("b".into(), true.into())]);
1925 let i = Attrs::from([("i".into(), true.into())]);
1926 txt1.format(&mut doc.transact_mut(), 0, 1, b.clone()); // '<b>a</b>bcde'
1927 txt1.format(&mut doc.transact_mut(), 1, 3, i.clone()); // '<b>a</b><i>bcd</i>e'
1928 let l1 = {
1929 let mut txn = doc.transact_mut();
1930 let l = txt1.quote(&mut txn, 0..=1).unwrap();
1931 array.insert(&mut txn, 0, l) // <b>a</b><i>b</i>
1932 };
1933 let l2 = {
1934 let mut txn = doc.transact_mut();
1935 let l = txt1.quote(&mut txn, 2..=2).unwrap();
1936 array.insert(&mut txn, 0, l) // <i>c</i>
1937 };
1938 let l3 = {
1939 let mut txn = doc.transact_mut();
1940 let l = txt1.quote(&mut txn, 3..=4).unwrap();
1941 array.insert(&mut txn, 0, l) // <i>d</i>e
1942 };
1943 assert_eq!(l1.get_string(&doc.transact()), "<b>a</b><i>b</i>");
1944 assert_eq!(l2.get_string(&doc.transact()), "<i>c</i>");
1945 assert_eq!(l3.get_string(&doc.transact()), "<i>d</i>e");
1946
1947 txt2.insert_embed(&mut doc.transact_mut(), 0, WeakPrelim::from(l1.clone()));
1948 txt2.insert_embed(&mut doc.transact_mut(), 1, WeakPrelim::from(l2.clone()));
1949 txt2.insert_embed(&mut doc.transact_mut(), 2, WeakPrelim::from(l3.clone()));
1950
1951 let txn = doc.transact();
1952 let diff: Vec<_> = txt2
1953 .diff(&txn, YChange::identity)
1954 .into_iter()
1955 .map(|d| {
1956 d.insert
1957 .cast::<WeakRef<XmlTextRef>>()
1958 .unwrap()
1959 .get_string(&txn)
1960 })
1961 .collect();
1962 assert_eq!(
1963 diff,
1964 vec![
1965 "<b>a</b><i>b</i>".to_string(),
1966 "<i>c</i>".to_string(),
1967 "<i>d</i>e".to_string()
1968 ]
1969 );
1970 }
1971
1972 #[test]
1973 fn quote_moved_elements() {
1974 let doc = Doc::with_client_id(1);
1975 let array = doc.get_or_insert_array("values");
1976 let quotes = doc.get_or_insert_array("quotes");
1977 let mut txn = doc.transact_mut();
1978
1979 array.insert_range(&mut txn, 0, [2, 3, 1, 7, 4, 6, 5]);
1980 array.move_to(&mut txn, 2, 0); // [1, 2, 3, 7, 4, 6, 5]
1981 array.move_to(&mut txn, 3, 7); // [1, 2, 3, 4, 6, 5, 7]
1982 array.move_to(&mut txn, 4, 6); // [1, 2, 3, 4, 5, 6, 7]
1983
1984 let values: Vec<_> = array.iter(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
1985 assert_eq!(values, vec![1, 2, 3, 4, 5, 6, 7]);
1986
1987 let mut assert_quote = |start: u32, len: u32, expected: Vec<u32>| {
1988 let end = start + len - 1;
1989 let q = array.quote(&mut txn, start..=end).unwrap();
1990 let q = quotes.push_back(&mut txn, q);
1991 let values: Vec<_> = q.unquote(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
1992 assert_eq!(values, expected)
1993 };
1994
1995 assert_quote(0, 1, vec![1]);
1996 assert_quote(0, 3, vec![1, 2, 3]);
1997 assert_quote(1, 3, vec![2, 3, 4]);
1998 assert_quote(2, 1, vec![3]);
1999 assert_quote(2, 3, vec![3, 4, 5]);
2000 assert_quote(3, 4, vec![4, 5, 6, 7]);
2001 }
2002
2003 #[test]
2004 fn quote_moved_range_elements() {
2005 let doc = Doc::with_client_id(1);
2006 let array = doc.get_or_insert_array("values");
2007 let quotes = doc.get_or_insert_array("quotes");
2008 let mut txn = doc.transact_mut();
2009
2010 array.insert_range(&mut txn, 0, [1, 5, 6, 2, 3, 4, 7]);
2011 array.move_range_to(&mut txn, 3, Before, 5, After, 1);
2012
2013 let values: Vec<_> = array.iter(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2014 assert_eq!(values, vec![1, 2, 3, 4, 5, 6, 7]);
2015
2016 let mut assert_quote = |start: u32, len: u32, expected: Vec<u32>| {
2017 let end = start + len - 1;
2018 let q = array.quote(&mut txn, start..=end).unwrap();
2019 let q = quotes.push_back(&mut txn, q);
2020 let values: Vec<_> = q.unquote(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2021 assert_eq!(values, expected)
2022 };
2023
2024 assert_quote(0, 1, vec![1]);
2025 assert_quote(0, 3, vec![1, 2, 3]);
2026 assert_quote(1, 3, vec![2, 3, 4]);
2027 assert_quote(2, 1, vec![3]);
2028 assert_quote(2, 3, vec![3, 4, 5]);
2029 assert_quote(3, 4, vec![4, 5, 6, 7]);
2030 }
2031
2032 #[ignore]
2033 #[test]
2034 fn move_range_of_quoted_elements() {
2035 let doc = Doc::with_client_id(1);
2036 let array = doc.get_or_insert_array("values");
2037 let quotes = doc.get_or_insert_array("quotes");
2038 let mut txn = doc.transact_mut();
2039
2040 array.insert_range(&mut txn, 0, [1, 2, 3, 4, 5, 6, 7]);
2041
2042 let mut quote = |start: u32, len: u32| {
2043 let end = start + len - 1;
2044 let q = array.quote(&mut txn, start..=end).unwrap();
2045 quotes.push_back(&mut txn, q)
2046 };
2047 let q1 = quote(0, 3); // [1,2,3]
2048 let q2 = quote(1, 3); // [2,3,4]
2049 let q3 = quote(2, 3); // [3,4,5]
2050 let q4 = quote(3, 3); // [4,5,6]
2051 let q5 = quote(4, 3); // [5,6,7]
2052
2053 array.move_range_to(&mut txn, 3, Before, 5, After, 1);
2054 let values: Vec<_> = array.iter(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2055 assert_eq!(values, vec![1, 4, 5, 6, 2, 3, 7]);
2056
2057 let actual: Vec<_> = q1.unquote(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2058 assert_eq!(actual, vec![1, 4, 5, 6, 2, 3]);
2059
2060 let actual: Vec<_> = q2.unquote(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2061 assert_eq!(actual, vec![2, 3]);
2062
2063 let actual: Vec<_> = q3.unquote(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2064 assert_eq!(actual, vec![3]);
2065
2066 let actual: Vec<_> = q4.unquote(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2067 assert_eq!(actual, vec![4, 5, 6]);
2068
2069 let actual: Vec<_> = q5.unquote(&txn).map(|v| v.cast::<u32>().unwrap()).collect();
2070 assert_eq!(actual, vec![5, 6, 2, 3, 7]);
2071 }
2072
2073 fn to_weak_xml_text(weak: &WeakRef<TextRef>) -> WeakRef<XmlTextRef> {
2074 WeakRef::from(weak.clone().into_inner())
2075 }
2076
2077 #[test]
2078 fn quoted_text_start_boundary_inserts() {
2079 let d1 = Doc::with_client_id(1);
2080 let arr1 = d1.get_or_insert_array("array");
2081 let txt1 = d1.get_or_insert_text("text");
2082 {
2083 let mut txn = d1.transact_mut();
2084 txt1.insert(&mut txn, 0, "abcdef"); // t1: 'abcdef'
2085 }
2086
2087 let d2 = Doc::with_client_id(2);
2088 let _arr2 = d2.get_or_insert_array("array");
2089 let txt2 = d2.get_or_insert_text("text");
2090
2091 exchange_updates(&[&d1, &d2]); // t2: 'abcdef'
2092
2093 txt2.insert(&mut d2.transact_mut(), 1, "xyz"); // t2: 'axyzbcdef'
2094
2095 let link_excl = {
2096 struct RangeLeftExclusive(u32, u32);
2097 impl RangeBounds<u32> for RangeLeftExclusive {
2098 fn start_bound(&self) -> Bound<&u32> {
2099 Bound::Excluded(&self.0)
2100 }
2101
2102 fn end_bound(&self) -> Bound<&u32> {
2103 Bound::Excluded(&self.1)
2104 }
2105 }
2106
2107 let mut txn = d1.transact_mut();
2108 let q = txt1.quote(&txn, RangeLeftExclusive(0, 5)).unwrap(); // [bcde]
2109 arr1.insert(&mut txn, 0, q)
2110 };
2111 let link_incl = {
2112 let mut txn = d1.transact_mut();
2113 let q = txt1.quote(&txn, 1..5).unwrap(); // [bcde]
2114 arr1.insert(&mut txn, 0, q)
2115 };
2116 {
2117 let txn = d1.transact();
2118 let str = link_excl.get_string(&txn);
2119 assert_eq!(&str, "bcde");
2120 let str = to_weak_xml_text(&link_excl).get_string(&txn);
2121 assert_eq!(&str, "bcde");
2122 let str = link_incl.get_string(&txn);
2123 assert_eq!(&str, "bcde");
2124 let str = to_weak_xml_text(&link_incl).get_string(&txn);
2125 assert_eq!(&str, "bcde");
2126 }
2127
2128 exchange_updates(&[&d1, &d2]);
2129
2130 {
2131 let txn = d1.transact();
2132 let str = link_excl.get_string(&txn);
2133 assert_eq!(&str, "xyzbcde");
2134 let str = to_weak_xml_text(&link_excl).get_string(&txn);
2135 assert_eq!(&str, "xyzbcde");
2136 let str = link_incl.get_string(&txn);
2137 assert_eq!(&str, "bcde");
2138 let str = to_weak_xml_text(&link_incl).get_string(&txn);
2139 assert_eq!(&str, "bcde");
2140 }
2141 }
2142
2143 #[test]
2144 fn quoted_text_end_boundary_inserts() {
2145 let d1 = Doc::with_client_id(1);
2146 let arr1 = d1.get_or_insert_array("array");
2147 let txt1 = d1.get_or_insert_text("text");
2148 {
2149 let mut txn = d1.transact_mut();
2150 txt1.insert(&mut txn, 0, "abcdef");
2151 }
2152
2153 let d2 = Doc::with_client_id(2);
2154 let _arr2 = d2.get_or_insert_array("array");
2155 let txt2 = d2.get_or_insert_text("text");
2156
2157 exchange_updates(&[&d1, &d2]);
2158
2159 txt2.insert(&mut d2.transact_mut(), 5, "xyz");
2160
2161 let link_excl = {
2162 let mut txn = d1.transact_mut();
2163 let q = txt1.quote(&txn, 1..5).unwrap();
2164 arr1.insert(&mut txn, 0, q)
2165 };
2166 let link_incl = {
2167 let mut txn = d1.transact_mut();
2168 let q = txt1.quote(&txn, 1..=4).unwrap();
2169 arr1.insert(&mut txn, 0, q)
2170 };
2171
2172 {
2173 let txn = d1.transact();
2174 let str = link_excl.get_string(&txn);
2175 assert_eq!(&str, "bcde");
2176 let str = to_weak_xml_text(&link_excl).get_string(&txn);
2177 assert_eq!(&str, "bcde");
2178 let str = link_incl.get_string(&txn);
2179 assert_eq!(&str, "bcde");
2180 let str = to_weak_xml_text(&link_incl).get_string(&txn);
2181 assert_eq!(&str, "bcde");
2182 }
2183
2184 exchange_updates(&[&d1, &d2]);
2185
2186 {
2187 let txn = d1.transact();
2188 let str = link_excl.get_string(&txn);
2189 assert_eq!(&str, "bcdexyz");
2190 let str = to_weak_xml_text(&link_excl).get_string(&txn);
2191 assert_eq!(&str, "bcdexyz");
2192 let str = link_incl.get_string(&txn);
2193 assert_eq!(&str, "bcde");
2194 let str = to_weak_xml_text(&link_incl).get_string(&txn);
2195 assert_eq!(&str, "bcde");
2196 }
2197 }
2198
2199 #[test]
2200 fn quote_end_unbounded_text() {
2201 let d1 = Doc::with_client_id(1);
2202 let mut txn = d1.transact_mut();
2203 let txt1 = txn.get_or_insert_text("text");
2204 let arr1 = txn.get_or_insert_array("array");
2205 txt1.insert(&mut txn, 0, "abc");
2206 let link1 = txt1.quote(&txn, 1..).unwrap();
2207 let link1 = arr1.insert(&mut txn, 0, link1);
2208 let str = link1.get_string(&txn);
2209 assert_eq!(str, "bc");
2210
2211 txt1.push(&mut txn, "def");
2212 let str = link1.get_string(&txn);
2213 assert_eq!(str, "bcdef");
2214 drop(txn);
2215
2216 let d2 = Doc::with_client_id(2);
2217
2218 exchange_updates(&[&d1, &d2]);
2219
2220 let mut txn = d2.transact_mut();
2221 let txt2 = txn.get_or_insert_text("text");
2222 let arr2 = txn.get_or_insert_array("array");
2223
2224 let link2 = arr2
2225 .get(&txn, 0)
2226 .unwrap()
2227 .cast::<WeakRef<TextRef>>()
2228 .unwrap();
2229 let str = link2.get_string(&txn);
2230 assert_eq!(str, "bcdef");
2231 }
2232
2233 #[test]
2234 fn quote_start_unbounded_text() {
2235 let d1 = Doc::with_client_id(1);
2236 let mut txn = d1.transact_mut();
2237 let txt1 = txn.get_or_insert_text("text");
2238 let arr1 = txn.get_or_insert_array("array");
2239 txt1.insert(&mut txn, 0, "xyz");
2240 let link1 = txt1.quote(&txn, ..=1).unwrap();
2241 let link1 = arr1.insert(&mut txn, 0, link1);
2242 let str = link1.get_string(&txn);
2243 assert_eq!(str, "xy");
2244
2245 txt1.insert(&mut txn, 0, "uwv"); // 'uwvxyz'
2246 let str = link1.get_string(&txn);
2247 assert_eq!(str, "uwvxy");
2248 drop(txn);
2249
2250 let d2 = Doc::with_client_id(2);
2251
2252 exchange_updates(&[&d1, &d2]);
2253
2254 let mut txn = d2.transact_mut();
2255 let _txt2 = txn.get_or_insert_text("text");
2256 let arr2 = txn.get_or_insert_array("array");
2257
2258 let link2 = arr2
2259 .get(&txn, 0)
2260 .unwrap()
2261 .cast::<WeakRef<TextRef>>()
2262 .unwrap();
2263 let str = link2.get_string(&txn);
2264 assert_eq!(str, "uwvxy");
2265 }
2266
2267 #[test]
2268 fn quote_both_sides_unbounded_text() {
2269 let d1 = Doc::with_client_id(1);
2270 let mut txn = d1.transact_mut();
2271 let txt1 = txn.get_or_insert_text("text");
2272 let arr1 = txn.get_or_insert_array("array");
2273 txt1.insert(&mut txn, 0, "xyz");
2274 let link1 = txt1.quote(&txn, ..).unwrap();
2275 let link1 = arr1.insert(&mut txn, 0, link1);
2276 let str = link1.get_string(&txn);
2277 assert_eq!(str, "xyz");
2278
2279 txt1.insert(&mut txn, 0, "uwv"); // 'uwvxyz'
2280 txt1.push(&mut txn, "abc"); // 'uwvxyzabc'
2281 let str = link1.get_string(&txn);
2282 assert_eq!(str, "uwvxyzabc");
2283 drop(txn);
2284
2285 let d2 = Doc::with_client_id(2);
2286
2287 exchange_updates(&[&d1, &d2]);
2288
2289 let mut txn = d2.transact_mut();
2290 let txt2 = txn.get_or_insert_text("text");
2291 let arr2 = txn.get_or_insert_array("array");
2292
2293 let link2 = arr2
2294 .get(&txn, 0)
2295 .unwrap()
2296 .cast::<WeakRef<TextRef>>()
2297 .unwrap();
2298 let str = link2.get_string(&txn);
2299 assert_eq!(str, "uwvxyzabc");
2300 }
2301}
2302