oficina / docs Public

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

Plain git — no account needed to clone.

Download

Download this file

1use crate::block::{ClientID, ItemContent, ItemPtr, Prelim};
2use crate::branch::BranchPtr;
3use crate::encoding::read::Error;
4use crate::event::{SubdocsEvent, TransactionCleanupEvent, UpdateEvent};
5use crate::store::{DocStore, StoreInner};
6use crate::transaction::{Origin, TransactionMut};
7use crate::types::{RootRef, ToJson};
8use crate::updates::decoder::{Decode, Decoder};
9use crate::updates::encoder::{Encode, Encoder};
10use crate::utils::OptionExt;
11use crate::{
12 uuid_v4, uuid_v4_from, ArrayRef, BranchID, MapRef, Out, ReadTxn, TextRef, Transact,
13 TransactionAcqError, Uuid, WriteTxn, XmlFragmentRef,
14};
15use crate::{Any, Subscription};
16use std::collections::HashMap;
17use std::convert::TryFrom;
18use std::fmt::Formatter;
19use std::sync::Arc;
20
21/// A Yrs document type. Documents are the most important units of collaborative resources management.
22/// All shared collections live within a scope of their corresponding documents. All updates are
23/// generated on per-document basis (rather than individual shared type). All operations on shared
24/// collections happen via [Transaction](crate::Transaction), which lifetime is also bound to a document.
25///
26/// Document manages so-called root types, which are top-level shared types definitions (as opposed
27/// to recursively nested types).
28///
29/// # Example
30///
31/// ```rust
32/// use yrs::{Doc, ReadTxn, StateVector, Text, Transact, Update};
33/// use yrs::updates::decoder::Decode;
34/// use yrs::updates::encoder::Encode;
35///
36/// let doc = Doc::new();
37/// let root = doc.get_or_insert_text("root-type-name");
38/// let mut txn = doc.transact_mut(); // all Yrs operations happen in scope of a transaction
39/// root.push(&mut txn, "hello world"); // append text to our collaborative document
40///
41/// // in order to exchange data with other documents we first need to create a state vector
42/// let remote_doc = Doc::new();
43/// let mut remote_txn = remote_doc.transact_mut();
44/// let state_vector = remote_txn.state_vector().encode_v1();
45///
46/// // now compute a differential update based on remote document's state vector
47/// let update = txn.encode_diff_v1(&StateVector::decode_v1(&state_vector).unwrap());
48///
49/// // both update and state vector are serializable, we can pass the over the wire
50/// // now apply update to a remote document
51/// remote_txn.apply_update(Update::decode_v1(update.as_slice()).unwrap());
52/// ```
53#[repr(transparent)]
54#[derive(Debug, Clone)]
55pub struct Doc {
56 pub(crate) store: DocStore,
57}
58
59unsafe impl Send for Doc {}
60unsafe impl Sync for Doc {}
61
62impl TryFrom<Out> for Doc {
63 type Error = Out;
64
65 fn try_from(value: Out) -> Result<Self, Self::Error> {
66 match value {
67 Out::YDoc(value) => Ok(value),
68 other => Err(other),
69 }
70 }
71}
72
73impl Doc {
74 /// Creates a new document with a randomized client identifier.
75 pub fn new() -> Self {
76 Self::with_options(Options::default())
77 }
78
79 #[doc(hidden)]
80 pub fn into_raw(self) -> *const Doc {
81 let ptr = Arc::into_raw(self.store.0);
82 ptr as *const Doc
83 }
84
85 #[doc(hidden)]
86 pub unsafe fn from_raw(ptr: *const Doc) -> Doc {
87 let ptr = ptr as *const StoreInner;
88 let cell = Arc::from_raw(ptr);
89 Doc {
90 store: DocStore(cell),
91 }
92 }
93
94 #[doc(hidden)]
95 pub fn as_raw(self) -> *const Doc {
96 let ptr = Arc::as_ptr(&self.store.0);
97 ptr as *const Doc
98 }
99
100 /// Creates a new document with a specified `client_id`. It's up to a caller to guarantee that
101 /// this identifier is unique across all communicating replicas of that document.
102 pub fn with_client_id(client_id: ClientID) -> Self {
103 Self::with_options(Options::with_client_id(client_id))
104 }
105
106 /// Creates a new document with a configured set of [Options].
107 pub fn with_options(options: Options) -> Self {
108 Doc {
109 store: DocStore::new(options, None),
110 }
111 }
112
113 pub(crate) fn subdoc(parent: ItemPtr, options: Options) -> Self {
114 Doc {
115 store: DocStore::new(options, Some(parent)),
116 }
117 }
118
119 pub(crate) fn store(&self) -> &DocStore {
120 &self.store
121 }
122
123 /// A unique client identifier, that's also a unique identifier of current document replica
124 /// and it's subdocuments.
125 ///
126 /// Default: randomly generated.
127 pub fn client_id(&self) -> ClientID {
128 self.store.options().client_id
129 }
130
131 /// A globally unique identifier, that's also a unique identifier of current document replica,
132 /// and unlike [Doc::client_id] it's not shared with its subdocuments.
133 ///
134 /// Default: randomly generated UUID v4.
135 pub fn guid(&self) -> Uuid {
136 self.store.options().guid.clone()
137 }
138
139 /// Returns a unique collection identifier, if defined.
140 ///
141 /// Default: `None`.
142 pub fn collection_id(&self) -> Option<Arc<str>> {
143 self.store.options().collection_id.clone()
144 }
145
146 /// Informs if current document is skipping garbage collection on deleted collections
147 /// on transaction commit.
148 ///
149 /// Default: `false`.
150 pub fn skip_gc(&self) -> bool {
151 self.store.options().skip_gc
152 }
153
154 /// If current document is subdocument, it will automatically for a document to load.
155 ///
156 /// Default: `false`.
157 pub fn auto_load(&self) -> bool {
158 self.store.options().auto_load
159 }
160
161 /// Whether the document should be synced by the provider now.
162 /// This is toggled to true when you call [Doc::load]
163 ///
164 /// Default value: `true`.
165 pub fn should_load(&self) -> bool {
166 self.store.options().should_load
167 }
168
169 /// Returns encoding used to count offsets and lengths in text operations.
170 pub fn offset_kind(&self) -> OffsetKind {
171 self.store.options().offset_kind
172 }
173
174 /// Returns a [TextRef] data structure stored under a given `name`. Text structures are used for
175 /// collaborative text editing: they expose operations to append and remove chunks of text,
176 /// which are free to execute concurrently by multiple peers over remote boundaries.
177 ///
178 /// If no structure under defined `name` existed before, it will be created and returned
179 /// instead.
180 ///
181 /// If a structure under defined `name` already existed, but its type was different it will be
182 /// reinterpreted as a text (in such case a sequence component of complex data type will be
183 /// interpreted as a list of text chunks).
184 ///
185 /// # Panics
186 ///
187 /// This method requires exclusive access to an underlying document store. If there
188 /// is another transaction in process, it will panic. It's advised to define all root shared
189 /// types during the document creation.
190 pub fn get_or_insert_text<N: Into<Arc<str>>>(&self, name: N) -> TextRef {
191 TextRef::root(name).get_or_create(&mut self.transact_mut())
192 }
193
194 /// Returns a [MapRef] data structure stored under a given `name`. Maps are used to store key-value
195 /// pairs associated. These values can be primitive data (similar but not limited to
196 /// a JavaScript Object Notation) as well as other shared types (Yrs maps, arrays, text
197 /// structures etc.), enabling to construct a complex recursive tree structures.
198 ///
199 /// If no structure under defined `name` existed before, it will be created and returned
200 /// instead.
201 ///
202 /// If a structure under defined `name` already existed, but its type was different it will be
203 /// reinterpreted as a map (in such case a map component of complex data type will be
204 /// interpreted as native map).
205 ///
206 /// # Panics
207 ///
208 /// This method requires exclusive access to an underlying document store. If there
209 /// is another transaction in process, it will panic. It's advised to define all root shared
210 /// types during the document creation.
211 pub fn get_or_insert_map<N: Into<Arc<str>>>(&self, name: N) -> MapRef {
212 MapRef::root(name).get_or_create(&mut self.transact_mut())
213 }
214
215 /// Returns an [ArrayRef] data structure stored under a given `name`. Array structures are used for
216 /// storing a sequences of elements in ordered manner, positioning given element accordingly
217 /// to its index.
218 ///
219 /// If no structure under defined `name` existed before, it will be created and returned
220 /// instead.
221 ///
222 /// If a structure under defined `name` already existed, but its type was different it will be
223 /// reinterpreted as an array (in such case a sequence component of complex data type will be
224 /// interpreted as a list of inserted values).
225 ///
226 /// # Panics
227 ///
228 /// This method requires exclusive access to an underlying document store. If there
229 /// is another transaction in process, it will panic. It's advised to define all root shared
230 /// types during the document creation.
231 pub fn get_or_insert_array<N: Into<Arc<str>>>(&self, name: N) -> ArrayRef {
232 ArrayRef::root(name).get_or_create(&mut self.transact_mut())
233 }
234
235 /// Returns a [XmlFragmentRef] data structure stored under a given `name`. XML elements represent
236 /// nodes of XML document. They can contain attributes (key-value pairs, both of string type)
237 /// and other nested XML elements or text values, which are stored in their insertion
238 /// order.
239 ///
240 /// If no structure under defined `name` existed before, it will be created and returned
241 /// instead.
242 ///
243 /// If a structure under defined `name` already existed, but its type was different it will be
244 /// reinterpreted as a XML element (in such case a map component of complex data type will be
245 /// interpreted as map of its attributes, while a sequence component - as a list of its child
246 /// XML nodes).
247 ///
248 /// # Panics
249 ///
250 /// This method requires exclusive access to an underlying document store. If there
251 /// is another transaction in process, it will panic. It's advised to define all root shared
252 /// types during the document creation.
253 pub fn get_or_insert_xml_fragment<N: Into<Arc<str>>>(&self, name: N) -> XmlFragmentRef {
254 XmlFragmentRef::root(name).get_or_create(&mut self.transact_mut())
255 }
256
257 /// Subscribe callback function for any changes performed within transaction scope. These
258 /// changes are encoded using lib0 v1 encoding and can be decoded using [Update::decode_v1] if
259 /// necessary or passed to remote peers right away. This callback is triggered on function
260 /// commit.
261 ///
262 /// Returns a subscription, which will unsubscribe function when dropped.
263 #[cfg(feature = "sync")]
264 pub fn observe_update_v1<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
265 where
266 F: Fn(&TransactionMut, &UpdateEvent) + Send + Sync + 'static,
267 {
268 let mut store = self
269 .store
270 .try_write()
271 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
272 let events = store.events.get_or_init();
273 Ok(events.update_v1_events.subscribe(Box::new(f)))
274 }
275
276 /// Subscribe callback function for any changes performed within transaction scope. These
277 /// changes are encoded using lib0 v1 encoding and can be decoded using [Update::decode_v1] if
278 /// necessary or passed to remote peers right away. This callback is triggered on function
279 /// commit.
280 ///
281 /// Returns a subscription, which will unsubscribe function when dropped.
282 #[cfg(not(feature = "sync"))]
283 pub fn observe_update_v1<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
284 where
285 F: Fn(&TransactionMut, &UpdateEvent) + 'static,
286 {
287 let mut store = self
288 .store
289 .try_write()
290 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
291 let events = store.events.get_or_init();
292 Ok(events.update_v1_events.subscribe(Box::new(f)))
293 }
294
295 /// Subscribe callback function for any changes performed within transaction scope. These
296 /// changes are encoded using lib0 v1 encoding and can be decoded using [Update::decode_v1] if
297 /// necessary or passed to remote peers right away. This callback is triggered on function
298 /// commit.
299 ///
300 /// Provided `key` will be used to identify a subscription, which will be used to unsubscribe.
301 #[cfg(feature = "sync")]
302 pub fn observe_update_v1_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
303 where
304 K: Into<Origin>,
305 F: Fn(&TransactionMut, &UpdateEvent) + Send + Sync + 'static,
306 {
307 let mut store = self
308 .store
309 .try_write()
310 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
311 let events = store.events.get_or_init();
312 events
313 .update_v1_events
314 .subscribe_with(key.into(), Box::new(f));
315 Ok(())
316 }
317
318 /// Subscribe callback function for any changes performed within transaction scope. These
319 /// changes are encoded using lib0 v1 encoding and can be decoded using [Update::decode_v1] if
320 /// necessary or passed to remote peers right away. This callback is triggered on function
321 /// commit.
322 ///
323 /// Provided `key` will be used to identify a subscription, which will be used to unsubscribe.
324 #[cfg(not(feature = "sync"))]
325 pub fn observe_update_v1_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
326 where
327 K: Into<Origin>,
328 F: Fn(&TransactionMut, &UpdateEvent) + 'static,
329 {
330 let mut store = self
331 .store
332 .try_write()
333 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
334 let events = store.events.get_or_init();
335 events
336 .update_v1_events
337 .subscribe_with(key.into(), Box::new(f));
338 Ok(())
339 }
340
341 pub fn unobserve_update_v1<K>(&self, key: K) -> Result<bool, TransactionAcqError>
342 where
343 K: Into<Origin>,
344 {
345 let mut store = self
346 .store
347 .try_write()
348 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
349 let events = store.events.get_or_init();
350 Ok(events.update_v1_events.unsubscribe(&key.into()))
351 }
352
353 /// Subscribe callback function for any changes performed within transaction scope. These
354 /// changes are encoded using lib0 v2 encoding and can be decoded using [Update::decode_v2] if
355 /// necessary or passed to remote peers right away. This callback is triggered on function
356 /// commit.
357 ///
358 /// Returns a subscription, which will unsubscribe function when dropped.
359 #[cfg(feature = "sync")]
360 pub fn observe_update_v2<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
361 where
362 F: Fn(&TransactionMut, &UpdateEvent) + Send + Sync + 'static,
363 {
364 let mut store = self
365 .store
366 .try_write()
367 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
368 let events = store.events.get_or_init();
369 Ok(events.update_v2_events.subscribe(Box::new(f)))
370 }
371
372 /// Subscribe callback function for any changes performed within transaction scope. These
373 /// changes are encoded using lib0 v2 encoding and can be decoded using [Update::decode_v2] if
374 /// necessary or passed to remote peers right away. This callback is triggered on function
375 /// commit.
376 ///
377 /// Returns a subscription, which will unsubscribe function when dropped.
378 #[cfg(not(feature = "sync"))]
379 pub fn observe_update_v2<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
380 where
381 F: Fn(&TransactionMut, &UpdateEvent) + 'static,
382 {
383 let mut store = self
384 .store
385 .try_write()
386 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
387 let events = store.events.get_or_init();
388 Ok(events.update_v2_events.subscribe(Box::new(f)))
389 }
390
391 /// Subscribe callback function for any changes performed within transaction scope. These
392 /// changes are encoded using lib0 v2 encoding and can be decoded using [Update::decode_v2] if
393 /// necessary or passed to remote peers right away. This callback is triggered on function
394 /// commit.
395 ///
396 /// Provided `key` will be used to identify a subscription, which will be used to unsubscribe.
397 #[cfg(feature = "sync")]
398 pub fn observe_update_v2_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
399 where
400 K: Into<Origin>,
401 F: Fn(&TransactionMut, &UpdateEvent) + Send + Sync + 'static,
402 {
403 let mut store = self
404 .store
405 .try_write()
406 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
407 let events = store.events.get_or_init();
408 events
409 .update_v2_events
410 .subscribe_with(key.into(), Box::new(f));
411 Ok(())
412 }
413
414 /// Subscribe callback function for any changes performed within transaction scope. These
415 /// changes are encoded using lib0 v2 encoding and can be decoded using [Update::decode_v2] if
416 /// necessary or passed to remote peers right away. This callback is triggered on function
417 /// commit.
418 ///
419 /// Provided `key` will be used to identify a subscription, which will be used to unsubscribe.
420 #[cfg(not(feature = "sync"))]
421 pub fn observe_update_v2_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
422 where
423 K: Into<Origin>,
424 F: Fn(&TransactionMut, &UpdateEvent) + 'static,
425 {
426 let mut store = self
427 .store
428 .try_write()
429 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
430 let events = store.events.get_or_init();
431 events
432 .update_v2_events
433 .subscribe_with(key.into(), Box::new(f));
434 Ok(())
435 }
436
437 pub fn unobserve_update_v2<K>(&self, key: K) -> Result<bool, TransactionAcqError>
438 where
439 K: Into<Origin>,
440 {
441 let mut store = self
442 .store
443 .try_write()
444 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
445 let events = store.events.get_or_init();
446 Ok(events.update_v2_events.unsubscribe(&key.into()))
447 }
448
449 /// Subscribe callback function to updates on the `Doc`. The callback will receive state updates and
450 /// deletions when a document transaction is committed.
451 #[cfg(feature = "sync")]
452 pub fn observe_transaction_cleanup<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
453 where
454 F: Fn(&TransactionMut, &TransactionCleanupEvent) + Send + Sync + 'static,
455 {
456 let mut store = self
457 .store
458 .try_write()
459 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
460 let events = store.events.get_or_init();
461 Ok(events.transaction_cleanup_events.subscribe(Box::new(f)))
462 }
463
464 /// Subscribe callback function to updates on the `Doc`. The callback will receive state updates and
465 /// deletions when a document transaction is committed.
466 #[cfg(not(feature = "sync"))]
467 pub fn observe_transaction_cleanup<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
468 where
469 F: Fn(&TransactionMut, &TransactionCleanupEvent) + 'static,
470 {
471 let mut store = self
472 .store
473 .try_write()
474 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
475 let events = store.events.get_or_init();
476 Ok(events.transaction_cleanup_events.subscribe(Box::new(f)))
477 }
478
479 /// Subscribe callback function to updates on the `Doc`. The callback will receive state updates and
480 /// deletions when a document transaction is committed.
481 #[cfg(feature = "sync")]
482 pub fn observe_transaction_cleanup_with<K, F>(
483 &self,
484 key: K,
485 f: F,
486 ) -> Result<(), TransactionAcqError>
487 where
488 K: Into<Origin>,
489 F: Fn(&TransactionMut, &TransactionCleanupEvent) + Send + Sync + 'static,
490 {
491 let mut store = self
492 .store
493 .try_write()
494 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
495 let events = store.events.get_or_init();
496 events
497 .transaction_cleanup_events
498 .subscribe_with(key.into(), Box::new(f));
499 Ok(())
500 }
501
502 /// Subscribe callback function to updates on the `Doc`. The callback will receive state updates and
503 /// deletions when a document transaction is committed.
504 #[cfg(not(feature = "sync"))]
505 pub fn observe_transaction_cleanup_with<K, F>(
506 &self,
507 key: K,
508 f: F,
509 ) -> Result<(), TransactionAcqError>
510 where
511 K: Into<Origin>,
512 F: Fn(&TransactionMut, &TransactionCleanupEvent) + 'static,
513 {
514 let mut store = self
515 .store
516 .try_write()
517 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
518 let events = store.events.get_or_init();
519 events
520 .transaction_cleanup_events
521 .subscribe_with(key.into(), Box::new(f));
522 Ok(())
523 }
524
525 pub fn unobserve_transaction_cleanup<K>(&self, key: K) -> Result<bool, TransactionAcqError>
526 where
527 K: Into<Origin>,
528 {
529 let mut store = self
530 .store
531 .try_write()
532 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
533 let events = store.events.get_or_init();
534 Ok(events.transaction_cleanup_events.unsubscribe(&key.into()))
535 }
536
537 #[cfg(feature = "sync")]
538 pub fn observe_after_transaction<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
539 where
540 F: Fn(&mut TransactionMut) + Send + Sync + 'static,
541 {
542 let mut store = self
543 .store
544 .try_write()
545 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
546 let events = store.events.get_or_init();
547 Ok(events.after_transaction_events.subscribe(Box::new(f)))
548 }
549
550 #[cfg(feature = "sync")]
551 pub fn observe_after_transaction_with<K, F>(
552 &self,
553 key: K,
554 f: F,
555 ) -> Result<(), TransactionAcqError>
556 where
557 K: Into<Origin>,
558 F: Fn(&mut TransactionMut) + Send + Sync + 'static,
559 {
560 let mut store = self
561 .store
562 .try_write()
563 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
564 let events = store.events.get_or_init();
565 events
566 .after_transaction_events
567 .subscribe_with(key.into(), Box::new(f));
568 Ok(())
569 }
570
571 #[cfg(not(feature = "sync"))]
572 pub fn observe_after_transaction_with<K, F>(
573 &self,
574 key: K,
575 f: F,
576 ) -> Result<(), TransactionAcqError>
577 where
578 K: Into<Origin>,
579 F: Fn(&mut TransactionMut) + 'static,
580 {
581 let mut store = self
582 .store
583 .try_write()
584 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
585 let events = store.events.get_or_init();
586 events
587 .after_transaction_events
588 .subscribe_with(key.into(), Box::new(f));
589 Ok(())
590 }
591
592 pub fn unobserve_after_transaction<K>(&self, key: K) -> Result<bool, TransactionAcqError>
593 where
594 K: Into<Origin>,
595 {
596 let mut store = self
597 .store
598 .try_write()
599 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
600 let events = store.events.get_or_init();
601 Ok(events.after_transaction_events.unsubscribe(&key.into()))
602 }
603
604 /// Subscribe callback function, that will be called whenever a subdocuments inserted in this
605 /// [Doc] will request a load.
606 #[cfg(feature = "sync")]
607 pub fn observe_subdocs<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
608 where
609 F: Fn(&TransactionMut, &SubdocsEvent) + Send + Sync + 'static,
610 {
611 let mut store = self
612 .store
613 .try_write()
614 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
615 let events = store.events.get_or_init();
616 Ok(events.subdocs_events.subscribe(Box::new(f)))
617 }
618
619 /// Subscribe callback function, that will be called whenever a subdocuments inserted in this
620 /// [Doc] will request a load.
621 #[cfg(not(feature = "sync"))]
622 pub fn observe_subdocs<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
623 where
624 F: Fn(&TransactionMut, &SubdocsEvent) + 'static,
625 {
626 let mut store = self
627 .store
628 .try_write()
629 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
630 let events = store.events.get_or_init();
631 Ok(events.subdocs_events.subscribe(Box::new(f)))
632 }
633
634 /// Subscribe callback function, that will be called whenever a subdocuments inserted in this
635 /// [Doc] will request a load.
636 #[cfg(feature = "sync")]
637 pub fn observe_subdocs_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
638 where
639 K: Into<Origin>,
640 F: Fn(&TransactionMut, &SubdocsEvent) + Send + Sync + 'static,
641 {
642 let mut store = self
643 .store
644 .try_write()
645 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
646 let events = store.events.get_or_init();
647 events
648 .subdocs_events
649 .subscribe_with(key.into(), Box::new(f));
650 Ok(())
651 }
652
653 /// Subscribe callback function, that will be called whenever a subdocuments inserted in this
654 /// [Doc] will request a load.
655 #[cfg(not(feature = "sync"))]
656 pub fn observe_subdocs_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
657 where
658 K: Into<Origin>,
659 F: Fn(&TransactionMut, &SubdocsEvent) + 'static,
660 {
661 let mut store = self
662 .store
663 .try_write()
664 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
665 let events = store.events.get_or_init();
666 events
667 .subdocs_events
668 .subscribe_with(key.into(), Box::new(f));
669 Ok(())
670 }
671
672 pub fn unobserve_subdocs<K>(&self, key: K) -> Result<bool, TransactionAcqError>
673 where
674 K: Into<Origin>,
675 {
676 let mut store = self
677 .store
678 .try_write()
679 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
680 let events = store.events.get_or_init();
681 Ok(events.subdocs_events.unsubscribe(&key.into()))
682 }
683
684 /// Subscribe callback function, that will be called whenever a [DocRef::destroy] has been called.
685 #[cfg(feature = "sync")]
686 pub fn observe_destroy<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
687 where
688 F: Fn(&TransactionMut, &Doc) + Send + Sync + 'static,
689 {
690 let mut store = self
691 .store
692 .try_write()
693 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
694 let events = store.events.get_or_init();
695 Ok(events.destroy_events.subscribe(Box::new(f)))
696 }
697
698 /// Subscribe callback function, that will be called whenever a [DocRef::destroy] has been called.
699 #[cfg(not(feature = "sync"))]
700 pub fn observe_destroy<F>(&self, f: F) -> Result<Subscription, TransactionAcqError>
701 where
702 F: Fn(&TransactionMut, &Doc) + 'static,
703 {
704 let mut store = self
705 .store
706 .try_write()
707 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
708 let events = store.events.get_or_init();
709 Ok(events.destroy_events.subscribe(Box::new(f)))
710 }
711
712 /// Subscribe callback function, that will be called whenever a [DocRef::destroy] has been called.
713 #[cfg(feature = "sync")]
714 pub fn observe_destroy_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
715 where
716 K: Into<Origin>,
717 F: Fn(&TransactionMut, &Doc) + Send + Sync + 'static,
718 {
719 let mut store = self
720 .store
721 .try_write()
722 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
723 let events = store.events.get_or_init();
724 events
725 .destroy_events
726 .subscribe_with(key.into(), Box::new(f));
727 Ok(())
728 }
729
730 pub fn unobserve_destroy<K>(&self, key: K) -> Result<bool, TransactionAcqError>
731 where
732 K: Into<Origin>,
733 {
734 let mut store = self
735 .store
736 .try_write()
737 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
738 let events = store.events.get_or_init();
739 Ok(events.destroy_events.unsubscribe(&key.into()))
740 }
741
742 /// Subscribe callback function, that will be called whenever a [DocRef::destroy] has been called.
743 #[cfg(not(feature = "sync"))]
744 pub fn observe_destroy_with<K, F>(&self, key: K, f: F) -> Result<(), TransactionAcqError>
745 where
746 K: Into<Origin>,
747 F: Fn(&TransactionMut, &Doc) + 'static,
748 {
749 let mut store = self
750 .store
751 .try_write()
752 .ok_or(TransactionAcqError::ExclusiveAcqFailed)?;
753 let events = store.events.get_or_init();
754 events
755 .destroy_events
756 .subscribe_with(key.into(), Box::new(f));
757 Ok(())
758 }
759
760 /// Sends a load request to a parent document. Works only if current document is a sub-document
761 /// of a document.
762 pub fn load<T>(&self, parent_txn: &mut T)
763 where
764 T: WriteTxn,
765 {
766 let should_load = self.store.set_should_load(true);
767 if !should_load {
768 let txn = self.transact();
769 if txn.store().is_subdoc() {
770 parent_txn
771 .subdocs_mut()
772 .loaded
773 .insert(self.addr(), self.clone());
774 }
775 }
776 }
777
778 /// Starts destroy procedure for a current document, triggering an "destroy" callback and
779 /// invalidating all event callback subscriptions.
780 pub fn destroy<T>(&self, parent_txn: &mut T)
781 where
782 T: WriteTxn,
783 {
784 let mut txn = self.transact_mut();
785 let store = txn.store_mut();
786 let subdocs: Vec<_> = store.subdocs.values().cloned().collect();
787 for subdoc in subdocs {
788 subdoc.destroy(&mut txn);
789 }
790 if let Some(mut item) = txn.store.parent.take() {
791 let parent_ref = item.clone();
792 let is_deleted = item.is_deleted();
793 if let ItemContent::Doc(_, content) = &mut item.content {
794 let mut options = (**content.store.options()).clone();
795 options.should_load = false;
796 let new_ref = Doc::subdoc(parent_ref, options);
797 if !is_deleted {
798 parent_txn
799 .subdocs_mut()
800 .added
801 .insert(new_ref.addr(), new_ref.clone());
802 }
803 parent_txn
804 .subdocs_mut()
805 .removed
806 .insert(new_ref.addr(), new_ref.clone());
807
808 *content = new_ref;
809 }
810 }
811 // super.destroy(): cleanup the events
812 if let Some(events) = txn.store_mut().events.take() {
813 events.destroy_events.trigger(|cb| cb(&txn, self));
814 }
815 }
816
817 /// If current document has been inserted as a sub-document, returns a reference to a parent
818 /// document, which contains it.
819 pub fn parent_doc(&self) -> Option<Doc> {
820 let txn = self.transact();
821 txn.parent_doc()
822 }
823
824 pub fn branch_id(&self) -> Option<BranchID> {
825 let txn = self.transact();
826 txn.branch_id()
827 }
828
829 pub fn ptr_eq(a: &Doc, b: &Doc) -> bool {
830 Arc::ptr_eq(&a.store.0, &b.store.0)
831 }
832
833 pub(crate) fn addr(&self) -> DocAddr {
834 DocAddr::new(&self)
835 }
836}
837
838impl PartialEq for Doc {
839 fn eq(&self, other: &Self) -> bool {
840 self.guid() == other.guid()
841 }
842}
843
844impl std::fmt::Display for Doc {
845 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
846 write!(f, "Doc(id: {}, guid: {})", self.client_id(), self.guid())
847 }
848}
849
850impl TryFrom<ItemPtr> for Doc {
851 type Error = ItemPtr;
852
853 fn try_from(item: ItemPtr) -> Result<Self, Self::Error> {
854 if let ItemContent::Doc(_, doc) = &item.content {
855 Ok(doc.clone())
856 } else {
857 Err(item)
858 }
859 }
860}
861
862impl Default for Doc {
863 fn default() -> Self {
864 Doc::new()
865 }
866}
867
868impl ToJson for Doc {
869 fn to_json<T: ReadTxn>(&self, txn: &T) -> Any {
870 let mut m = HashMap::new();
871 for (key, value) in txn.root_refs() {
872 m.insert(key.to_string(), value.to_json(txn));
873 }
874 Any::from(m)
875 }
876}
877
878/// Configuration options of [Doc] instance.
879#[derive(Debug, Clone, PartialEq, Eq)]
880pub struct Options {
881 /// Globally unique client identifier. This value must be unique across all active collaborating
882 /// peers, otherwise a update collisions will happen, causing document store state to be corrupted.
883 ///
884 /// Default value: randomly generated.
885 pub client_id: ClientID,
886 /// A globally unique identifier for this document.
887 ///
888 /// Default value: randomly generated UUID v4.
889 pub guid: Uuid,
890 /// Associate this document with a collection. This only plays a role if your provider has
891 /// a concept of collection.
892 ///
893 /// Default value: `None`.
894 pub collection_id: Option<Arc<str>>,
895 /// How to we count offsets and lengths used in text operations.
896 ///
897 /// Default value: [OffsetKind::Bytes].
898 pub offset_kind: OffsetKind,
899 /// Determines if transactions commits should try to perform GC-ing of deleted items.
900 ///
901 /// Default value: `false`.
902 pub skip_gc: bool,
903 /// If a subdocument, automatically load document. If this is a subdocument, remote peers will
904 /// load the document as well automatically.
905 ///
906 /// Default value: `false`.
907 pub auto_load: bool,
908 /// Whether the document should be synced by the provider now.
909 /// This is toggled to true when you call ydoc.load().
910 ///
911 /// Default value: `true`.
912 pub should_load: bool,
913}
914
915impl Options {
916 pub fn with_client_id(client_id: ClientID) -> Self {
917 Options {
918 client_id,
919 guid: uuid_v4(),
920 collection_id: None,
921 offset_kind: OffsetKind::Bytes,
922 skip_gc: false,
923 auto_load: false,
924 should_load: true,
925 }
926 }
927
928 pub fn with_guid_and_client_id(guid: Uuid, client_id: ClientID) -> Self {
929 Options {
930 client_id,
931 guid,
932 collection_id: None,
933 offset_kind: OffsetKind::Bytes,
934 skip_gc: false,
935 auto_load: false,
936 should_load: true,
937 }
938 }
939
940 fn as_any(&self) -> Any {
941 let mut m = HashMap::new();
942 m.insert("gc".to_owned(), (!self.skip_gc).into());
943 if let Some(collection_id) = self.collection_id.as_ref() {
944 m.insert("collectionId".to_owned(), collection_id.clone().into());
945 }
946 let encoding = match self.offset_kind {
947 OffsetKind::Bytes => 1,
948 OffsetKind::Utf16 => 0, // 0 for compatibility with Yjs, which doesn't have this option
949 };
950 m.insert("encoding".to_owned(), Any::BigInt(encoding));
951 m.insert("autoLoad".to_owned(), self.auto_load.into());
952 m.insert("shouldLoad".to_owned(), self.should_load.into());
953 Any::from(m)
954 }
955}
956
957impl Default for Options {
958 fn default() -> Self {
959 let mut rng = fastrand::Rng::new();
960 let client_id: u32 = rng.u32(0..u32::MAX);
961 let uuid = uuid_v4_from(rng.u128(..));
962 Self::with_guid_and_client_id(uuid, client_id as ClientID)
963 }
964}
965
966impl Encode for Options {
967 fn encode<E: Encoder>(&self, encoder: &mut E) {
968 let guid = self.guid.to_string();
969 encoder.write_string(&guid);
970 encoder.write_any(&self.as_any())
971 }
972}
973
974impl Decode for Options {
975 fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, Error> {
976 let mut options = Options::default();
977 options.should_load = false; // for decoding shouldLoad is false by default
978 let guid = decoder.read_string()?;
979 options.guid = guid.into();
980
981 if let Any::Map(opts) = decoder.read_any()? {
982 for (k, v) in opts.iter() {
983 match (k.as_str(), v) {
984 ("gc", Any::Bool(gc)) => options.skip_gc = !*gc,
985 ("autoLoad", Any::Bool(auto_load)) => options.auto_load = *auto_load,
986 ("collectionId", Any::String(cid)) => options.collection_id = Some(cid.clone()),
987 ("encoding", Any::BigInt(1)) => options.offset_kind = OffsetKind::Bytes,
988 ("encoding", _) => options.offset_kind = OffsetKind::Utf16,
989 _ => { /* do nothing */ }
990 }
991 }
992 }
993
994 Ok(options)
995 }
996}
997
998/// Determines how string length and offsets of [Text]/[XmlText] are being determined.
999#[repr(u8)]
1000#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1001pub enum OffsetKind {
1002 /// Compute editable strings length and offset using UTF-8 byte count.
1003 Bytes,
1004 /// Compute editable strings length and offset using UTF-16 chars count.
1005 Utf16,
1006}
1007
1008impl Prelim for Doc {
1009 type Return = Doc;
1010
1011 fn into_content(self, txn: &mut TransactionMut) -> (ItemContent, Option<Self>) {
1012 if txn.parent_doc().is_some() {
1013 panic!("Cannot integrate the document, because it's already being used as a sub-document elsewhere");
1014 }
1015 (ItemContent::Doc(None, self), None)
1016 }
1017
1018 fn integrate(self, _txn: &mut TransactionMut, _inner_ref: BranchPtr) {}
1019}
1020
1021/// For a Yjs compatibility reasons we expect subdocuments to be compared based on their reference
1022/// equality. This concept however doesn't really exists in Rust. Therefore we use a store reference
1023/// instead and specialize it for this single scenario.
1024#[repr(transparent)]
1025#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
1026pub(crate) struct DocAddr(usize);
1027
1028impl DocAddr {
1029 pub fn new(doc: &Doc) -> Self {
1030 let ptr = Arc::as_ptr(&doc.store.0);
1031 DocAddr(ptr as usize)
1032 }
1033}
1034
1035#[cfg(test)]
1036mod test {
1037 use crate::block::{BlockCell, ItemContent};
1038 use crate::test_utils::exchange_updates;
1039 use crate::transaction::{ReadTxn, TransactionMut};
1040 use crate::types::ToJson;
1041 use crate::update::Update;
1042 use crate::updates::decoder::Decode;
1043 use crate::updates::encoder::{Encode, Encoder, EncoderV1};
1044 use crate::{
1045 any, uuid_v4, Any, Array, ArrayPrelim, ArrayRef, DeleteSet, Doc, GetString, Map, MapRef,
1046 OffsetKind, Options, StateVector, Subscription, Text, TextPrelim, TextRef, Transact, Uuid,
1047 WriteTxn, XmlElementPrelim, XmlFragment, XmlFragmentRef, XmlTextPrelim, XmlTextRef, ID,
1048 };
1049 use arc_swap::ArcSwapOption;
1050 use assert_matches2::assert_matches;
1051 use std::collections::BTreeSet;
1052 use std::iter::FromIterator;
1053 use std::sync::atomic::{AtomicU32, Ordering};
1054 use std::sync::{Arc, Mutex};
1055
1056 #[test]
1057 fn apply_update_basic_v1() {
1058 /* Result of calling following code:
1059 ```javascript
1060 const doc = new Y.Doc()
1061 const ytext = doc.getText('type')
1062 doc.transact(function () {
1063 for (let i = 0; i < 3; i++) {
1064 ytext.insert(0, (i % 10).toString())
1065 }
1066 })
1067 const update = Y.encodeStateAsUpdate(doc)
1068 ```
1069 */
1070 let update = &[
1071 1, 3, 227, 214, 245, 198, 5, 0, 4, 1, 4, 116, 121, 112, 101, 1, 48, 68, 227, 214, 245,
1072 198, 5, 0, 1, 49, 68, 227, 214, 245, 198, 5, 1, 1, 50, 0,
1073 ];
1074 let doc = Doc::new();
1075 let txt = doc.get_or_insert_text("type");
1076 let mut txn = doc.transact_mut();
1077 txn.apply_update(Update::decode_v1(update).unwrap())
1078 .unwrap();
1079
1080 let actual = txt.get_string(&txn);
1081 assert_eq!(actual, "210".to_owned());
1082 }
1083
1084 #[test]
1085 fn apply_update_basic_v2() {
1086 /* Result of calling following code:
1087 ```javascript
1088 const doc = new Y.Doc()
1089 const ytext = doc.getText('type')
1090 doc.transact(function () {
1091 for (let i = 0; i < 3; i++) {
1092 ytext.insert(0, (i % 10).toString())
1093 }
1094 })
1095 const update = Y.encodeStateAsUpdateV2(doc)
1096 ```
1097 */
1098 let update = &[
1099 0, 0, 6, 195, 187, 207, 162, 7, 1, 0, 2, 0, 2, 3, 4, 0, 68, 11, 7, 116, 121, 112, 101,
1100 48, 49, 50, 4, 65, 1, 1, 1, 0, 0, 1, 3, 0, 0,
1101 ];
1102 let doc = Doc::new();
1103 let txt = doc.get_or_insert_text("type");
1104 let mut txn = doc.transact_mut();
1105 txn.apply_update(Update::decode_v2(update).unwrap())
1106 .unwrap();
1107
1108 let actual = txt.get_string(&txn);
1109 assert_eq!(actual, "210".to_owned());
1110 }
1111
1112 #[test]
1113 fn encode_basic() {
1114 let doc = Doc::with_client_id(1490905955);
1115 let txt = doc.get_or_insert_text("type");
1116 let mut t = doc.transact_mut();
1117 txt.insert(&mut t, 0, "0");
1118 txt.insert(&mut t, 0, "1");
1119 txt.insert(&mut t, 0, "2");
1120
1121 let encoded = t.encode_state_as_update_v1(&StateVector::default());
1122 let expected = &[
1123 1, 3, 227, 214, 245, 198, 5, 0, 4, 1, 4, 116, 121, 112, 101, 1, 48, 68, 227, 214, 245,
1124 198, 5, 0, 1, 49, 68, 227, 214, 245, 198, 5, 1, 1, 50, 0,
1125 ];
1126 assert_eq!(encoded.as_slice(), expected);
1127 }
1128
1129 #[test]
1130 fn integrate() {
1131 // create new document at A and add some initial text to it
1132 let d1 = Doc::new();
1133 let txt = d1.get_or_insert_text("test");
1134 let mut t1 = d1.transact_mut();
1135 // Question: why YText.insert uses positions of blocks instead of actual cursor positions
1136 // in text as seen by user?
1137 txt.insert(&mut t1, 0, "hello");
1138 txt.insert(&mut t1, 5, " ");
1139 txt.insert(&mut t1, 6, "world");
1140
1141 assert_eq!(txt.get_string(&t1), "hello world".to_string());
1142
1143 // create document at B
1144 let d2 = Doc::new();
1145 let txt = d2.get_or_insert_text("test");
1146 let mut t2 = d2.transact_mut();
1147 let sv = t2.state_vector().encode_v1();
1148
1149 // create an update A->B based on B's state vector
1150 let mut encoder = EncoderV1::new();
1151 t1.encode_diff(
1152 &StateVector::decode_v1(sv.as_slice()).unwrap(),
1153 &mut encoder,
1154 );
1155 let binary = encoder.to_vec();
1156
1157 // decode an update incoming from A and integrate it at B
1158 let update = Update::decode_v1(binary.as_slice()).unwrap();
1159 let pending = update.integrate(&mut t2).unwrap();
1160
1161 assert!(pending.0.is_none());
1162 assert!(pending.1.is_none());
1163
1164 // check if B sees the same thing that A does
1165 assert_eq!(txt.get_string(&t1), "hello world".to_string());
1166 }
1167
1168 #[test]
1169 fn on_update() {
1170 let counter = Arc::new(AtomicU32::new(0));
1171 let doc = Doc::new();
1172 let doc2 = Doc::new();
1173 let c = counter.clone();
1174 let sub = doc2.observe_update_v1(move |_, e| {
1175 let u = Update::decode_v1(&e.update).unwrap();
1176 for block in u.blocks.blocks() {
1177 c.fetch_add(block.len(), Ordering::SeqCst);
1178 }
1179 });
1180 let txt = doc.get_or_insert_text("test");
1181 let mut txn = doc.transact_mut();
1182 {
1183 txt.insert(&mut txn, 0, "abc");
1184 let mut txn2 = doc2.transact_mut();
1185 let sv = txn2.state_vector().encode_v1();
1186 let u = txn.encode_diff_v1(&StateVector::decode_v1(sv.as_slice()).unwrap());
1187 txn2.apply_update(Update::decode_v1(u.as_slice()).unwrap())
1188 .unwrap();
1189 }
1190 assert_eq!(counter.load(Ordering::SeqCst), 3); // update has been propagated
1191
1192 drop(sub);
1193
1194 {
1195 txt.insert(&mut txn, 3, "de");
1196 let mut txn2 = doc2.transact_mut();
1197 let sv = txn2.state_vector().encode_v1();
1198 let u = txn.encode_diff_v1(&StateVector::decode_v1(sv.as_slice()).unwrap());
1199 txn2.apply_update(Update::decode_v1(u.as_slice()).unwrap())
1200 .unwrap();
1201 }
1202 assert_eq!(counter.load(Ordering::SeqCst), 3); // since subscription has been dropped, update was not propagated
1203 }
1204
1205 #[test]
1206 fn pending_update_integration() {
1207 let doc = Doc::new();
1208 let txt = doc.get_or_insert_text("source");
1209
1210 let updates = [
1211 vec![
1212 1, 2, 242, 196, 218, 129, 3, 0, 40, 1, 5, 115, 116, 97, 116, 101, 5, 100, 105, 114,
1213 116, 121, 1, 121, 40, 1, 7, 99, 111, 110, 116, 101, 120, 116, 4, 112, 97, 116, 104,
1214 1, 119, 13, 117, 110, 116, 105, 116, 108, 101, 100, 52, 46, 116, 120, 116, 0,
1215 ],
1216 vec![
1217 1, 1, 242, 196, 218, 129, 3, 2, 40, 1, 7, 99, 111, 110, 116, 101, 120, 116, 13,
1218 108, 97, 115, 116, 95, 109, 111, 100, 105, 102, 105, 101, 100, 1, 119, 27, 50, 48,
1219 50, 50, 45, 48, 52, 45, 49, 51, 84, 49, 48, 58, 49, 48, 58, 53, 55, 46, 48, 55, 51,
1220 54, 50, 51, 90, 0,
1221 ],
1222 vec![
1223 1, 2, 242, 196, 218, 129, 3, 3, 4, 1, 6, 115, 111, 117, 114, 99, 101, 1, 97, 168,
1224 242, 196, 218, 129, 3, 0, 1, 120, 0,
1225 ],
1226 vec![
1227 1, 1, 242, 196, 218, 129, 3, 4, 168, 242, 196, 218, 129, 3, 0, 1, 120, 1, 242, 196,
1228 218, 129, 3, 1, 0, 1,
1229 ],
1230 vec![
1231 1, 1, 152, 182, 129, 244, 193, 193, 227, 4, 0, 168, 242, 196, 218, 129, 3, 4, 1,
1232 121, 1, 242, 196, 218, 129, 3, 2, 0, 1, 4, 1,
1233 ],
1234 vec![
1235 1, 2, 242, 196, 218, 129, 3, 5, 132, 242, 196, 218, 129, 3, 3, 1, 98, 168, 152,
1236 190, 167, 244, 1, 0, 1, 120, 0,
1237 ],
1238 vec![
1239 1, 1, 242, 196, 218, 129, 3, 6, 168, 152, 190, 167, 244, 1, 0, 1, 120, 1, 152, 190,
1240 167, 244, 1, 1, 0, 1,
1241 ],
1242 vec![
1243 1, 1, 242, 196, 218, 129, 3, 7, 132, 242, 196, 218, 129, 3, 5, 1, 99, 0,
1244 ],
1245 vec![
1246 1, 1, 242, 196, 218, 129, 3, 8, 132, 242, 196, 218, 129, 3, 7, 1, 100, 0,
1247 ],
1248 ];
1249
1250 for u in updates {
1251 let mut txn = doc.transact_mut();
1252 let u = Update::decode_v1(u.as_slice()).unwrap();
1253 txn.apply_update(u).unwrap();
1254 }
1255 assert_eq!(txt.get_string(&doc.transact()), "abcd".to_string());
1256 }
1257
1258 #[test]
1259 fn ypy_issue_32() {
1260 let d1 = Doc::with_client_id(1971027812);
1261 let source_1 = d1.get_or_insert_text("source");
1262 source_1.push(&mut d1.transact_mut(), "a");
1263
1264 let updates = [
1265 vec![
1266 1, 2, 201, 210, 153, 56, 0, 40, 1, 5, 115, 116, 97, 116, 101, 5, 100, 105, 114,
1267 116, 121, 1, 121, 40, 1, 7, 99, 111, 110, 116, 101, 120, 116, 4, 112, 97, 116, 104,
1268 1, 119, 13, 117, 110, 116, 105, 116, 108, 101, 100, 52, 46, 116, 120, 116, 0,
1269 ],
1270 vec![
1271 1, 1, 201, 210, 153, 56, 2, 168, 201, 210, 153, 56, 0, 1, 120, 1, 201, 210, 153,
1272 56, 1, 0, 1,
1273 ],
1274 vec![
1275 1, 1, 201, 210, 153, 56, 3, 40, 1, 7, 99, 111, 110, 116, 101, 120, 116, 13, 108,
1276 97, 115, 116, 95, 109, 111, 100, 105, 102, 105, 101, 100, 1, 119, 27, 50, 48, 50,
1277 50, 45, 48, 52, 45, 49, 54, 84, 49, 52, 58, 48, 51, 58, 53, 51, 46, 57, 51, 48, 52,
1278 54, 56, 90, 0,
1279 ],
1280 vec![
1281 1, 1, 201, 210, 153, 56, 4, 168, 201, 210, 153, 56, 2, 1, 121, 1, 201, 210, 153,
1282 56, 1, 2, 1,
1283 ],
1284 ];
1285 for u in updates {
1286 let u = Update::decode_v1(&u).unwrap();
1287 d1.transact_mut().apply_update(u).unwrap();
1288 }
1289
1290 assert_eq!("a", source_1.get_string(&d1.transact()));
1291
1292 let d2 = Doc::new();
1293 let source_2 = d2.get_or_insert_text("source");
1294 let state_2 = d2.transact().state_vector().encode_v1();
1295 let update = d1
1296 .transact()
1297 .encode_state_as_update_v1(&StateVector::decode_v1(&state_2).unwrap());
1298 let update = Update::decode_v1(&update).unwrap();
1299 d2.transact_mut().apply_update(update).unwrap();
1300
1301 assert_eq!("a", source_2.get_string(&d2.transact()));
1302
1303 let update = Update::decode_v1(&[
1304 1, 2, 201, 210, 153, 56, 5, 132, 228, 254, 237, 171, 7, 0, 1, 98, 168, 201, 210, 153,
1305 56, 4, 1, 120, 0,
1306 ])
1307 .unwrap();
1308 d1.transact_mut().apply_update(update).unwrap();
1309 assert_eq!("ab", source_1.get_string(&d1.transact()));
1310
1311 let d3 = Doc::new();
1312 let source_3 = d3.get_or_insert_text("source");
1313 let state_3 = d3.transact().state_vector().encode_v1();
1314 let state_3 = StateVector::decode_v1(&state_3).unwrap();
1315 let update = d1.transact().encode_state_as_update_v1(&state_3);
1316 let update = Update::decode_v1(&update).unwrap();
1317 d3.transact_mut().apply_update(update).unwrap();
1318
1319 assert_eq!("ab", source_3.get_string(&d3.transact()));
1320 }
1321
1322 #[test]
1323 fn observe_transaction_cleanup() {
1324 // Setup
1325 let doc = Doc::new();
1326 let text = doc.get_or_insert_text("test");
1327 let before_state = Arc::new(ArcSwapOption::default());
1328 let after_state = Arc::new(ArcSwapOption::default());
1329 let delete_set = Arc::new(ArcSwapOption::default());
1330 // Create interior mutable references for the callback.
1331 let before_ref = before_state.clone();
1332 let after_ref = after_state.clone();
1333 let delete_ref = delete_set.clone();
1334 // Subscribe callback
1335
1336 let sub: Subscription = doc
1337 .observe_transaction_cleanup(move |_: &TransactionMut, event| {
1338 before_ref.store(Some(event.before_state.clone().into()));
1339 after_ref.store(Some(event.after_state.clone().into()));
1340 delete_ref.store(Some(event.delete_set.clone().into()));
1341 })
1342 .unwrap();
1343
1344 {
1345 let mut txn = doc.transact_mut();
1346
1347 // Update the document
1348 text.insert(&mut txn, 0, "abc");
1349 text.remove_range(&mut txn, 1, 2);
1350 txn.commit();
1351
1352 // Compare values
1353 assert_eq!(
1354 before_state.swap(None),
1355 Some(Arc::new(txn.before_state.clone()))
1356 );
1357 assert_eq!(
1358 after_state.swap(None),
1359 Some(Arc::new(txn.after_state.clone()))
1360 );
1361 assert_eq!(
1362 delete_set.swap(None),
1363 Some(Arc::new(txn.delete_set.clone()))
1364 );
1365 }
1366
1367 // Ensure that the subscription is successfully dropped.
1368 drop(sub);
1369 let mut txn = doc.transact_mut();
1370 text.insert(&mut txn, 0, "should not update");
1371 txn.commit();
1372 assert_ne!(
1373 after_state.swap(None),
1374 Some(Arc::new(txn.after_state.clone()))
1375 );
1376 }
1377
1378 #[test]
1379 fn partially_duplicated_update() {
1380 let d1 = Doc::with_client_id(1);
1381 let txt1 = d1.get_or_insert_text("text");
1382 txt1.insert(&mut d1.transact_mut(), 0, "hello");
1383 let u = d1
1384 .transact()
1385 .encode_state_as_update_v1(&StateVector::default());
1386
1387 let d2 = Doc::with_client_id(2);
1388 let txt2 = d2.get_or_insert_text("text");
1389 d2.transact_mut()
1390 .apply_update(Update::decode_v1(&u).unwrap())
1391 .unwrap();
1392
1393 txt1.insert(&mut d1.transact_mut(), 5, "world");
1394 let u = d1
1395 .transact()
1396 .encode_state_as_update_v1(&StateVector::default());
1397 d2.transact_mut()
1398 .apply_update(Update::decode_v1(&u).unwrap())
1399 .unwrap();
1400
1401 assert_eq!(
1402 txt1.get_string(&d1.transact()),
1403 txt2.get_string(&d2.transact())
1404 );
1405 }
1406
1407 #[test]
1408 fn incremental_observe_update() {
1409 const INPUT: &'static str = "hello";
1410
1411 let d1 = Doc::with_client_id(1);
1412 let txt1 = d1.get_or_insert_text("text");
1413 let acc = Arc::new(Mutex::new(String::new()));
1414
1415 let a = acc.clone();
1416 let _sub = d1.observe_update_v1(move |_: &TransactionMut, e| {
1417 let u = Update::decode_v1(&e.update).unwrap();
1418 for mut block in u.blocks.into_blocks(false) {
1419 match block.as_item_ptr().as_deref() {
1420 Some(item) => {
1421 if let ItemContent::String(s) = &item.content {
1422 // each character is appended in individual transaction 1-by-1,
1423 // therefore each update should contain a single string with only
1424 // one element
1425 let mut aref = a.lock().unwrap();
1426 aref.push_str(s.as_str());
1427 } else {
1428 panic!("unexpected content type")
1429 }
1430 }
1431 _ => {}
1432 }
1433 }
1434 });
1435
1436 for c in INPUT.chars() {
1437 // append characters 1-by-1 (1 transactions per character)
1438 txt1.push(&mut d1.transact_mut(), &c.to_string());
1439 }
1440
1441 assert_eq!(acc.lock().unwrap().as_str(), INPUT);
1442
1443 // test incremental deletes
1444 let acc = Arc::new(Mutex::new(vec![]));
1445 let a = acc.clone();
1446 let _sub = d1.observe_update_v1(move |_: &TransactionMut, e| {
1447 let u = Update::decode_v1(&e.update).unwrap();
1448 for (&client_id, range) in u.delete_set.iter() {
1449 if client_id == 1 {
1450 let mut aref = a.lock().unwrap();
1451 for r in range.iter() {
1452 aref.push(r.clone());
1453 }
1454 }
1455 }
1456 });
1457
1458 for _ in 0..INPUT.len() as u32 {
1459 txt1.remove_range(&mut d1.transact_mut(), 0, 1);
1460 }
1461
1462 let expected = vec![(0..1), (1..2), (2..3), (3..4), (4..5)];
1463 assert_eq!(&*acc.lock().unwrap(), &expected);
1464 }
1465
1466 #[test]
1467 fn ycrdt_issue_174() {
1468 let doc = Doc::new();
1469 let bin = &[
1470 0, 0, 11, 176, 133, 128, 149, 31, 205, 190, 199, 196, 21, 7, 3, 0, 3, 5, 0, 17, 168, 1,
1471 8, 0, 40, 0, 8, 0, 40, 0, 8, 0, 40, 0, 33, 1, 39, 110, 91, 49, 49, 49, 114, 111, 111,
1472 116, 105, 51, 50, 114, 111, 111, 116, 115, 116, 114, 105, 110, 103, 114, 111, 111, 116,
1473 97, 95, 108, 105, 115, 116, 114, 111, 111, 116, 97, 95, 109, 97, 112, 114, 111, 111,
1474 116, 105, 51, 50, 95, 108, 105, 115, 116, 114, 111, 111, 116, 105, 51, 50, 95, 109, 97,
1475 112, 114, 111, 111, 116, 115, 116, 114, 105, 110, 103, 95, 108, 105, 115, 116, 114,
1476 111, 111, 116, 115, 116, 114, 105, 110, 103, 95, 109, 97, 112, 65, 1, 4, 3, 4, 6, 4, 6,
1477 4, 5, 4, 8, 4, 7, 4, 11, 4, 10, 3, 0, 5, 1, 6, 0, 1, 0, 1, 0, 1, 2, 65, 8, 2, 8, 0,
1478 125, 2, 119, 5, 119, 111, 114, 108, 100, 118, 2, 1, 98, 119, 1, 97, 1, 97, 125, 1, 118,
1479 2, 1, 98, 119, 1, 98, 1, 97, 125, 2, 125, 1, 125, 2, 119, 1, 97, 119, 1, 98, 8, 0, 1,
1480 141, 223, 163, 226, 10, 1, 0, 1,
1481 ];
1482 let update = Update::decode_v2(bin).unwrap();
1483 doc.transact_mut().apply_update(update).unwrap();
1484
1485 let root = doc.get_or_insert_map("root");
1486 let actual = root.to_json(&doc.transact());
1487 let expected = Any::from_json(
1488 r#"{
1489 "string": "world",
1490 "a_list": [{"b": "a", "a": 1}],
1491 "i32_map": {"1": 2},
1492 "a_map": {
1493 "1": {"a": 2, "b": "b"}
1494 },
1495 "string_list": ["a"],
1496 "i32": 2,
1497 "string_map": {"1": "b"},
1498 "i32_list": [1]
1499 }"#,
1500 )
1501 .unwrap();
1502 assert_eq!(actual, expected);
1503 }
1504
1505 #[test]
1506 fn snapshots_splitting_text() {
1507 let mut options = Options::with_client_id(1);
1508 options.skip_gc = true;
1509
1510 let d1 = Doc::with_options(options);
1511 let txt1 = d1.get_or_insert_text("text");
1512 txt1.insert(&mut d1.transact_mut(), 0, "hello");
1513 let snapshot = d1.transact_mut().snapshot();
1514 txt1.insert(&mut d1.transact_mut(), 5, "_world");
1515
1516 let mut encoder = EncoderV1::new();
1517 d1.transact_mut()
1518 .encode_state_from_snapshot(&snapshot, &mut encoder)
1519 .unwrap();
1520 let update = Update::decode_v1(&encoder.to_vec()).unwrap();
1521
1522 let d2 = Doc::with_client_id(2);
1523 let txt2 = d2.get_or_insert_text("text");
1524 d2.transact_mut().apply_update(update).unwrap();
1525
1526 assert_eq!(txt2.get_string(&d2.transact()), "hello".to_string());
1527 }
1528
1529 #[test]
1530 fn snapshot_non_splitting_text() {
1531 let mut options = Options::default();
1532 options.skip_gc = true;
1533
1534 let doc = Doc::with_options(options.clone().into());
1535 let txt = doc.get_or_insert_text("name");
1536
1537 let mut txn = doc.transact_mut();
1538 txt.insert(&mut txn, 0, "Lucas");
1539 drop(txn);
1540
1541 let txn = doc.transact();
1542 let snapshot = txn.snapshot();
1543
1544 let mut encoder = EncoderV1::new();
1545 txn.encode_state_from_snapshot(&snapshot, &mut encoder)
1546 .unwrap();
1547 let state_diff = encoder.to_vec();
1548
1549 let remote_doc = Doc::with_options(options);
1550 let remote_txt = remote_doc.get_or_insert_text("name");
1551 let mut txn = remote_doc.transact_mut();
1552 let update = Update::decode_v1(&state_diff).unwrap();
1553 txn.apply_update(update).unwrap();
1554
1555 let actual = remote_txt.get_string(&txn);
1556
1557 assert_eq!(actual, "Lucas");
1558 }
1559
1560 #[test]
1561 fn yrb_issue_45() {
1562 let diffs: Vec<Vec<u8>> = vec![
1563 vec![
1564 1, 3, 197, 134, 244, 186, 10, 0, 7, 1, 7, 100, 101, 102, 97, 117, 108, 116, 3, 9,
1565 112, 97, 114, 97, 103, 114, 97, 112, 104, 7, 0, 197, 134, 244, 186, 10, 0, 6, 4, 0,
1566 197, 134, 244, 186, 10, 1, 1, 115, 0,
1567 ],
1568 vec![
1569 1, 1, 197, 134, 244, 186, 10, 3, 132, 197, 134, 244, 186, 10, 2, 3, 227, 129, 149,
1570 1, 197, 134, 244, 186, 10, 1, 2, 1,
1571 ],
1572 vec![
1573 1, 4, 197, 134, 244, 186, 10, 0, 7, 1, 7, 100, 101, 102, 97, 117, 108, 116, 3, 9,
1574 112, 97, 114, 97, 103, 114, 97, 112, 104, 7, 0, 197, 134, 244, 186, 10, 0, 6, 1, 0,
1575 197, 134, 244, 186, 10, 1, 1, 132, 197, 134, 244, 186, 10, 2, 3, 227, 129, 149, 1,
1576 197, 134, 244, 186, 10, 1, 2, 1,
1577 ],
1578 vec![
1579 1, 1, 197, 134, 244, 186, 10, 4, 132, 197, 134, 244, 186, 10, 3, 1, 120, 0,
1580 ],
1581 vec![
1582 1, 1, 197, 134, 244, 186, 10, 5, 132, 197, 134, 244, 186, 10, 4, 3, 227, 129, 129,
1583 1, 197, 134, 244, 186, 10, 1, 4, 1,
1584 ],
1585 vec![
1586 1, 1, 197, 134, 244, 186, 10, 6, 132, 197, 134, 244, 186, 10, 5, 1, 107, 0,
1587 ],
1588 vec![
1589 1, 2, 197, 134, 244, 186, 10, 4, 129, 197, 134, 244, 186, 10, 3, 1, 132, 197, 134,
1590 244, 186, 10, 4, 3, 227, 129, 129, 1, 197, 134, 244, 186, 10, 1, 4, 1,
1591 ],
1592 vec![
1593 1, 1, 197, 134, 244, 186, 10, 7, 132, 197, 134, 244, 186, 10, 6, 3, 227, 129, 147,
1594 1, 197, 134, 244, 186, 10, 1, 6, 1,
1595 ],
1596 vec![
1597 1, 2, 197, 134, 244, 186, 10, 6, 129, 197, 134, 244, 186, 10, 5, 1, 132, 197, 134,
1598 244, 186, 10, 6, 3, 227, 129, 147, 1, 197, 134, 244, 186, 10, 1, 6, 1,
1599 ],
1600 vec![
1601 1, 1, 197, 134, 244, 186, 10, 8, 132, 197, 134, 244, 186, 10, 7, 1, 114, 0,
1602 ],
1603 vec![
1604 1, 1, 197, 134, 244, 186, 10, 9, 132, 197, 134, 244, 186, 10, 8, 3, 227, 130, 140,
1605 1, 197, 134, 244, 186, 10, 1, 8, 1,
1606 ],
1607 vec![
1608 1, 1, 197, 134, 244, 186, 10, 8, 132, 197, 134, 244, 186, 10, 7, 1, 114, 0,
1609 ],
1610 vec![
1611 1, 1, 197, 134, 244, 186, 10, 10, 132, 197, 134, 244, 186, 10, 9, 1, 107, 0,
1612 ],
1613 vec![
1614 1, 1, 197, 134, 244, 186, 10, 11, 132, 197, 134, 244, 186, 10, 10, 3, 227, 129,
1615 139, 1, 197, 134, 244, 186, 10, 1, 10, 1,
1616 ],
1617 vec![
1618 1, 1, 197, 134, 244, 186, 10, 12, 132, 197, 134, 244, 186, 10, 11, 1, 114, 0,
1619 ],
1620 vec![
1621 1, 1, 197, 134, 244, 186, 10, 13, 132, 197, 134, 244, 186, 10, 12, 3, 227, 130,
1622 137, 1, 197, 134, 244, 186, 10, 1, 12, 1,
1623 ],
1624 vec![
1625 1, 1, 197, 134, 244, 186, 10, 9, 132, 197, 134, 244, 186, 10, 8, 3, 227, 130, 140,
1626 1, 197, 134, 244, 186, 10, 1, 8, 1,
1627 ],
1628 vec![
1629 1, 1, 197, 134, 244, 186, 10, 10, 132, 197, 134, 244, 186, 10, 9, 1, 107, 0,
1630 ],
1631 vec![
1632 1, 1, 197, 134, 244, 186, 10, 11, 132, 197, 134, 244, 186, 10, 10, 3, 227, 129,
1633 139, 1, 197, 134, 244, 186, 10, 1, 10, 1,
1634 ],
1635 vec![
1636 1, 1, 197, 134, 244, 186, 10, 12, 132, 197, 134, 244, 186, 10, 11, 1, 114, 0,
1637 ],
1638 vec![
1639 1, 1, 197, 134, 244, 186, 10, 14, 132, 197, 134, 244, 186, 10, 13, 1, 98, 0,
1640 ],
1641 vec![
1642 1, 1, 197, 134, 244, 186, 10, 16, 132, 197, 134, 244, 186, 10, 15, 1, 103, 0,
1643 ],
1644 vec![
1645 1, 1, 197, 134, 244, 186, 10, 15, 132, 197, 134, 244, 186, 10, 14, 3, 227, 129,
1646 176, 1, 197, 134, 244, 186, 10, 1, 14, 1,
1647 ],
1648 vec![
1649 1, 1, 197, 134, 244, 186, 10, 17, 132, 197, 134, 244, 186, 10, 16, 3, 227, 129,
1650 144, 1, 197, 134, 244, 186, 10, 1, 16, 1,
1651 ],
1652 vec![
1653 1, 1, 197, 134, 244, 186, 10, 17, 132, 197, 134, 244, 186, 10, 16, 3, 227, 129,
1654 144, 1, 197, 134, 244, 186, 10, 1, 16, 1,
1655 ],
1656 vec![
1657 1, 1, 197, 134, 244, 186, 10, 18, 132, 197, 134, 244, 186, 10, 17, 6, 227, 131,
1658 144, 227, 130, 176, 1, 197, 134, 244, 186, 10, 2, 15, 1, 17, 1,
1659 ],
1660 vec![
1661 1, 1, 197, 134, 244, 186, 10, 20, 132, 197, 134, 244, 186, 10, 19, 1, 103, 0,
1662 ],
1663 vec![
1664 1, 3, 197, 134, 244, 186, 10, 13, 132, 197, 134, 244, 186, 10, 12, 3, 227, 130,
1665 137, 129, 197, 134, 244, 186, 10, 13, 1, 132, 197, 134, 244, 186, 10, 14, 4, 227,
1666 129, 176, 103, 1, 197, 134, 244, 186, 10, 2, 12, 1, 14, 1,
1667 ],
1668 vec![
1669 1, 1, 197, 134, 244, 186, 10, 21, 132, 197, 134, 244, 186, 10, 20, 3, 227, 129,
1670 140, 1, 197, 134, 244, 186, 10, 1, 20, 1,
1671 ],
1672 vec![
1673 1, 1, 197, 134, 244, 186, 10, 23, 132, 197, 134, 244, 186, 10, 22, 3, 227, 129,
1674 170, 1, 197, 134, 244, 186, 10, 1, 22, 1,
1675 ],
1676 vec![
1677 1, 3, 197, 134, 244, 186, 10, 18, 132, 197, 134, 244, 186, 10, 17, 6, 227, 131,
1678 144, 227, 130, 176, 129, 197, 134, 244, 186, 10, 19, 1, 132, 197, 134, 244, 186,
1679 10, 20, 3, 227, 129, 140, 1, 197, 134, 244, 186, 10, 3, 15, 1, 17, 1, 20, 1,
1680 ],
1681 vec![
1682 1, 1, 197, 134, 244, 186, 10, 24, 132, 197, 134, 244, 186, 10, 23, 3, 227, 129,
1683 132, 0,
1684 ],
1685 vec![
1686 1, 1, 197, 134, 244, 186, 10, 22, 132, 197, 134, 244, 186, 10, 21, 1, 110, 0,
1687 ],
1688 vec![
1689 1, 1, 197, 134, 244, 186, 10, 26, 132, 197, 134, 244, 186, 10, 25, 3, 227, 129,
1690 139, 1, 197, 134, 244, 186, 10, 1, 25, 1,
1691 ],
1692 vec![
1693 1, 1, 197, 134, 244, 186, 10, 25, 132, 197, 134, 244, 186, 10, 24, 1, 107, 0,
1694 ],
1695 vec![
1696 1, 4, 197, 134, 244, 186, 10, 22, 129, 197, 134, 244, 186, 10, 21, 1, 132, 197,
1697 134, 244, 186, 10, 22, 6, 227, 129, 170, 227, 129, 132, 129, 197, 134, 244, 186,
1698 10, 24, 1, 132, 197, 134, 244, 186, 10, 25, 3, 227, 129, 139, 1, 197, 134, 244,
1699 186, 10, 2, 22, 1, 25, 1,
1700 ],
1701 vec![
1702 1, 1, 197, 134, 244, 186, 10, 27, 132, 197, 134, 244, 186, 10, 26, 1, 100, 0,
1703 ],
1704 vec![
1705 1, 1, 197, 134, 244, 186, 10, 28, 132, 197, 134, 244, 186, 10, 27, 3, 227, 129,
1706 169, 1, 197, 134, 244, 186, 10, 1, 27, 1,
1707 ],
1708 vec![
1709 1, 2, 197, 134, 244, 186, 10, 27, 129, 197, 134, 244, 186, 10, 26, 1, 132, 197,
1710 134, 244, 186, 10, 27, 3, 227, 129, 169, 1, 197, 134, 244, 186, 10, 1, 27, 1,
1711 ],
1712 vec![
1713 1, 1, 197, 134, 244, 186, 10, 29, 132, 197, 134, 244, 186, 10, 28, 3, 227, 129,
1714 134, 0,
1715 ],
1716 vec![
1717 1, 1, 197, 134, 244, 186, 10, 30, 132, 197, 134, 244, 186, 10, 29, 1, 107, 0,
1718 ],
1719 vec![
1720 1, 1, 197, 134, 244, 186, 10, 29, 132, 197, 134, 244, 186, 10, 28, 3, 227, 129,
1721 134, 0,
1722 ],
1723 vec![
1724 1, 1, 197, 134, 244, 186, 10, 31, 132, 197, 134, 244, 186, 10, 30, 3, 227, 129,
1725 139, 1, 197, 134, 244, 186, 10, 1, 30, 1,
1726 ],
1727 vec![
1728 1, 1, 197, 134, 244, 186, 10, 30, 132, 197, 134, 244, 186, 10, 29, 1, 107, 0,
1729 ],
1730 vec![
1731 1, 1, 197, 134, 244, 186, 10, 31, 132, 197, 134, 244, 186, 10, 30, 3, 227, 129,
1732 139, 1, 197, 134, 244, 186, 10, 1, 30, 1,
1733 ],
1734 vec![
1735 1, 1, 197, 134, 244, 186, 10, 32, 135, 197, 134, 244, 186, 10, 0, 3, 9, 112, 97,
1736 114, 97, 103, 114, 97, 112, 104, 0,
1737 ],
1738 vec![
1739 1, 1, 197, 134, 244, 186, 10, 32, 135, 197, 134, 244, 186, 10, 0, 3, 9, 112, 97,
1740 114, 97, 103, 114, 97, 112, 104, 0,
1741 ],
1742 vec![
1743 1, 2, 197, 134, 244, 186, 10, 33, 7, 0, 197, 134, 244, 186, 10, 32, 6, 4, 0, 197,
1744 134, 244, 186, 10, 33, 1, 107, 0,
1745 ],
1746 vec![
1747 1, 1, 197, 134, 244, 186, 10, 35, 132, 197, 134, 244, 186, 10, 34, 3, 227, 129,
1748 139, 1, 197, 134, 244, 186, 10, 1, 34, 1,
1749 ],
1750 vec![
1751 1, 1, 197, 134, 244, 186, 10, 36, 132, 197, 134, 244, 186, 10, 35, 1, 107, 0,
1752 ],
1753 ];
1754
1755 let doc = Doc::new();
1756 let mut txn = doc.transact_mut();
1757 for diff in diffs {
1758 let u = Update::decode_v1(diff.as_slice()).unwrap();
1759 txn.apply_update(u).unwrap();
1760 }
1761 }
1762
1763 #[test]
1764 fn root_refs() {
1765 let doc = Doc::new();
1766 {
1767 let _txt = doc.get_or_insert_text("text");
1768 let _array = doc.get_or_insert_array("array");
1769 let _map = doc.get_or_insert_map("map");
1770 let _xml_elem = doc.get_or_insert_xml_fragment("xml_elem");
1771 }
1772
1773 let txn = doc.transact();
1774 for (key, value) in txn.root_refs() {
1775 match key {
1776 "text" => assert!(value.cast::<TextRef>().is_ok()),
1777 "array" => assert!(value.cast::<ArrayRef>().is_ok()),
1778 "map" => assert!(value.cast::<MapRef>().is_ok()),
1779 "xml_elem" => assert!(value.cast::<XmlFragmentRef>().is_ok()),
1780 "xml_text" => assert!(value.cast::<XmlTextRef>().is_ok()),
1781 other => panic!("unrecognized root type: '{}'", other),
1782 }
1783 }
1784 }
1785
1786 #[test]
1787 fn integrate_block_with_parent_gc() {
1788 let d1 = Doc::with_client_id(1);
1789 let d2 = Doc::with_client_id(2);
1790 let d3 = Doc::with_client_id(3);
1791
1792 {
1793 let root = d1.get_or_insert_array("array");
1794 let mut txn = d1.transact_mut();
1795 root.push_back(&mut txn, ArrayPrelim::from(["A"]));
1796 }
1797
1798 exchange_updates(&[&d1, &d2, &d3]);
1799
1800 {
1801 let root = d2.get_or_insert_array("array");
1802 let mut t2 = d2.transact_mut();
1803 root.remove(&mut t2, 0);
1804 d1.transact_mut()
1805 .apply_update(Update::decode_v1(&t2.encode_update_v1()).unwrap())
1806 .unwrap();
1807 }
1808
1809 {
1810 let root = d3.get_or_insert_array("array");
1811 let mut t3 = d3.transact_mut();
1812 let a3 = root.get(&t3, 0).unwrap().cast::<ArrayRef>().unwrap();
1813 a3.push_back(&mut t3, "B");
1814 // D1 got update which already removed a3, but this must not cause panic
1815 d1.transact_mut()
1816 .apply_update(Update::decode_v1(&t3.encode_update_v1()).unwrap())
1817 .unwrap();
1818 }
1819
1820 exchange_updates(&[&d1, &d2, &d3]);
1821
1822 let r1 = d1.get_or_insert_array("array").to_json(&d1.transact());
1823 let r2 = d2.get_or_insert_array("array").to_json(&d2.transact());
1824 let r3 = d3.get_or_insert_array("array").to_json(&d3.transact());
1825
1826 assert_eq!(r1, r2);
1827 assert_eq!(r2, r3);
1828 assert_eq!(r3, r1);
1829 }
1830
1831 #[test]
1832 fn subdoc() {
1833 let doc = Doc::with_client_id(1);
1834 let event = Arc::new(ArcSwapOption::default());
1835 let event_c = event.clone();
1836 let _sub = doc.observe_subdocs(move |_, e| {
1837 let added = e.added().map(|d| d.guid().clone()).collect();
1838 let removed = e.removed().map(|d| d.guid().clone()).collect();
1839 let loaded = e.loaded().map(|d| d.guid().clone()).collect();
1840 event_c.store(Some(Arc::new((added, removed, loaded))));
1841 });
1842 let subdocs = doc.get_or_insert_map("mysubdocs");
1843 let uuid_a: Uuid = "A".into();
1844 let doc_a = Doc::with_options({
1845 let mut o = Options::default();
1846 o.guid = uuid_a.clone();
1847 o
1848 });
1849 {
1850 let mut txn = doc.transact_mut();
1851 let doc_a_ref = subdocs.insert(&mut txn, "a", doc_a);
1852 doc_a_ref.load(&mut txn);
1853 }
1854
1855 let actual = event.swap(None);
1856 assert_eq!(
1857 actual,
1858 Some((vec![uuid_a.clone()], vec![], vec![uuid_a.clone()]).into())
1859 );
1860
1861 {
1862 let mut txn = doc.transact_mut();
1863 let doc_a_ref = subdocs.get(&txn, "a").unwrap().cast::<Doc>().unwrap();
1864 doc_a_ref.load(&mut txn);
1865 }
1866 let actual = event.swap(None);
1867 assert_eq!(actual, None);
1868
1869 {
1870 let mut txn = doc.transact_mut();
1871 let doc_a_ref = subdocs.get(&txn, "a").unwrap().cast::<Doc>().unwrap();
1872 doc_a_ref.destroy(&mut txn);
1873 }
1874 let actual = event.swap(None);
1875 assert_eq!(
1876 actual,
1877 Some(Arc::new((
1878 vec![uuid_a.clone()],
1879 vec![uuid_a.clone()],
1880 vec![]
1881 )))
1882 );
1883
1884 {
1885 let mut txn = doc.transact_mut();
1886 let doc_a_ref = subdocs.get(&txn, "a").unwrap().cast::<Doc>().unwrap();
1887 doc_a_ref.load(&mut txn);
1888 }
1889 let actual = event.swap(None);
1890 assert_eq!(
1891 actual,
1892 Some(Arc::new((vec![], vec![], vec![uuid_a.clone()])))
1893 );
1894
1895 let doc_b = Doc::with_options({
1896 let mut o = Options::default();
1897 o.guid = uuid_a.clone();
1898 o.should_load = false;
1899 o
1900 });
1901 subdocs.insert(&mut doc.transact_mut(), "b", doc_b);
1902 let actual = event.swap(None);
1903 assert_eq!(
1904 actual,
1905 Some(Arc::new((vec![uuid_a.clone()], vec![], vec![])))
1906 );
1907
1908 {
1909 let mut txn = doc.transact_mut();
1910 let doc_b_ref = subdocs.get(&txn, "b").unwrap().cast::<Doc>().unwrap();
1911 doc_b_ref.load(&mut txn);
1912 }
1913 let actual = event.swap(None);
1914 assert_eq!(
1915 actual,
1916 Some(Arc::new((vec![], vec![], vec![uuid_a.clone()])))
1917 );
1918
1919 let uuid_c: Uuid = "C".into();
1920 let doc_c = Doc::with_options({
1921 let mut o = Options::default();
1922 o.guid = uuid_c.clone();
1923 o
1924 });
1925 {
1926 let mut txn = doc.transact_mut();
1927 let doc_c_ref = subdocs.insert(&mut txn, "c", doc_c);
1928 doc_c_ref.load(&mut txn);
1929 }
1930 let actual = event.swap(None);
1931 assert_eq!(
1932 actual,
1933 Some(Arc::new((
1934 vec![uuid_c.clone()],
1935 vec![],
1936 vec![uuid_c.clone()]
1937 )))
1938 );
1939
1940 let guids: BTreeSet<_> = doc.transact().subdoc_guids().collect();
1941 assert_eq!(guids, BTreeSet::from([uuid_a.clone(), uuid_c.clone()]));
1942
1943 let data = doc
1944 .transact()
1945 .encode_state_as_update_v1(&StateVector::default());
1946
1947 let doc2 = Doc::new();
1948 let event = Arc::new(ArcSwapOption::default());
1949 let event_c = event.clone();
1950 let _sub = doc2.observe_subdocs(move |_, e| {
1951 let added: Vec<_> = e.added().map(|d| d.guid().clone()).collect();
1952 let removed: Vec<_> = e.removed().map(|d| d.guid().clone()).collect();
1953 let loaded: Vec<_> = e.loaded().map(|d| d.guid().clone()).collect();
1954 event_c.store(Some(Arc::new((added, removed, loaded))));
1955 });
1956 let update = Update::decode_v1(&data).unwrap();
1957 doc2.transact_mut().apply_update(update).unwrap();
1958 let mut actual = event.swap(None).unwrap();
1959 Arc::get_mut(&mut actual).unwrap().0.sort();
1960 assert_eq!(
1961 actual,
1962 Arc::new((
1963 vec![uuid_a.clone(), uuid_a.clone(), uuid_c.clone()],
1964 vec![],
1965 vec![]
1966 ))
1967 );
1968
1969 let subdocs = doc2.transact().get_map("mysubdocs").unwrap();
1970 {
1971 let mut txn = doc2.transact_mut();
1972 let doc_ref = subdocs.get(&mut txn, "a").unwrap().cast::<Doc>().unwrap();
1973 doc_ref.load(&mut txn);
1974 }
1975 let actual = event.swap(None);
1976 assert_eq!(
1977 actual,
1978 Some(Arc::new((vec![], vec![], vec![uuid_a.clone()])))
1979 );
1980
1981 let guids: BTreeSet<_> = doc2.transact().subdoc_guids().collect();
1982 assert_eq!(guids, BTreeSet::from([uuid_a.clone(), uuid_c.clone()]));
1983 {
1984 let mut txn = doc2.transact_mut();
1985 subdocs.remove(&mut txn, "a");
1986 }
1987
1988 let actual = event.swap(None);
1989 assert_eq!(
1990 actual,
1991 Some(Arc::new((vec![], vec![uuid_a.clone()], vec![])))
1992 );
1993
1994 let mut guids: Vec<_> = doc2.transact().subdoc_guids().collect();
1995 guids.sort();
1996 assert_eq!(guids, vec![uuid_a.clone(), uuid_c.clone()]);
1997 }
1998
1999 #[test]
2000 fn subdoc_load_edge_cases() {
2001 let doc = Doc::with_client_id(1);
2002 let array = doc.get_or_insert_array("test");
2003 let subdoc_1 = Doc::new();
2004 let uuid_1 = subdoc_1.guid().clone();
2005
2006 let event = Arc::new(ArcSwapOption::default());
2007 let event_c = event.clone();
2008 let _sub = doc.observe_subdocs(move |_, e| {
2009 let added = e.added().map(|d| d.guid().clone()).collect();
2010 let removed = e.removed().map(|d| d.guid().clone()).collect();
2011 let loaded = e.loaded().map(|d| d.guid().clone()).collect();
2012
2013 event_c.store(Some(Arc::new((added, removed, loaded))));
2014 });
2015 let doc_ref = {
2016 let mut txn = doc.transact_mut();
2017 let doc_ref = array.insert(&mut txn, 0, subdoc_1);
2018 assert!(doc_ref.should_load());
2019 assert!(!doc_ref.auto_load());
2020 doc_ref
2021 };
2022 let last_event = event.swap(None);
2023 assert_eq!(
2024 last_event,
2025 Some((vec![uuid_1.clone()], vec![], vec![uuid_1.clone()]).into())
2026 );
2027
2028 // destroy and check whether lastEvent adds it again to added (it shouldn't)
2029 doc_ref.destroy(&mut doc.transact_mut());
2030 let doc_ref_2 = array
2031 .get(&doc.transact(), 0)
2032 .unwrap()
2033 .cast::<Doc>()
2034 .unwrap();
2035 let uuid_2 = doc_ref_2.guid();
2036 assert!(!Doc::ptr_eq(&doc_ref, &doc_ref_2));
2037
2038 let last_event = event.swap(None);
2039 assert_eq!(
2040 last_event,
2041 Some((vec![uuid_2.clone()], vec![uuid_2.clone()], vec![]).into())
2042 );
2043
2044 // load
2045 doc_ref_2.load(&mut doc.transact_mut());
2046 let last_event = event.swap(None);
2047 assert_eq!(
2048 last_event,
2049 Some(Arc::new((vec![], vec![], vec![uuid_2.clone()])))
2050 );
2051
2052 // apply from remote
2053 let doc2 = Doc::with_client_id(2);
2054 let event_c = event.clone();
2055 let _sub = doc2.observe_subdocs(move |_, e| {
2056 let added = e.added().map(|d| d.guid().clone()).collect();
2057 let removed = e.removed().map(|d| d.guid().clone()).collect();
2058 let loaded = e.loaded().map(|d| d.guid().clone()).collect();
2059
2060 event_c.store(Some(Arc::new((added, removed, loaded))));
2061 });
2062 let u = Update::decode_v1(
2063 &doc.transact()
2064 .encode_state_as_update_v1(&StateVector::default()),
2065 );
2066 doc2.transact_mut().apply_update(u.unwrap()).unwrap();
2067 let doc_ref_3 = {
2068 let array = doc2.get_or_insert_array("test");
2069 array
2070 .get(&doc2.transact(), 0)
2071 .unwrap()
2072 .cast::<Doc>()
2073 .unwrap()
2074 };
2075 assert!(!doc_ref_3.should_load());
2076 assert!(!doc_ref_3.auto_load());
2077 let uuid_3 = doc_ref_3.guid();
2078 let last_event = event.swap(None);
2079 assert_eq!(
2080 last_event,
2081 Some(Arc::new((vec![uuid_3.clone()], vec![], vec![])))
2082 );
2083
2084 // load
2085 doc_ref_3.load(&mut doc2.transact_mut());
2086 assert!(doc_ref_3.should_load());
2087 let last_event = event.swap(None);
2088 assert_eq!(
2089 last_event,
2090 Some(Arc::new((vec![], vec![], vec![uuid_3.clone()])))
2091 );
2092 }
2093
2094 #[test]
2095 fn subdoc_auto_load_edge_cases() {
2096 let doc = Doc::with_client_id(1);
2097 let array = doc.get_or_insert_array("test");
2098 let subdoc_1 = Doc::with_options({
2099 let mut o = Options::default();
2100 o.auto_load = true;
2101 o
2102 });
2103
2104 let event = Arc::new(ArcSwapOption::default());
2105 let event_c = event.clone();
2106 let _sub = doc.observe_subdocs(move |_, e| {
2107 let added = e.added().map(|d| d.guid().clone()).collect();
2108 let removed = e.removed().map(|d| d.guid().clone()).collect();
2109 let loaded = e.loaded().map(|d| d.guid().clone()).collect();
2110
2111 event_c.store(Some(Arc::new((added, removed, loaded))));
2112 });
2113
2114 let subdoc_1 = {
2115 let mut txn = doc.transact_mut();
2116 array.insert(&mut txn, 0, subdoc_1)
2117 };
2118 assert!(subdoc_1.should_load());
2119 assert!(subdoc_1.auto_load());
2120
2121 let uuid_1 = subdoc_1.guid();
2122 let last_event = event.swap(None);
2123 assert_eq!(
2124 last_event,
2125 Some(Arc::new((
2126 vec![uuid_1.clone()],
2127 vec![],
2128 vec![uuid_1.clone()]
2129 )))
2130 );
2131
2132 // destroy and check whether lastEvent adds it again to added (it shouldn't)
2133 subdoc_1.destroy(&mut doc.transact_mut());
2134
2135 let subdoc_2 = array
2136 .get(&doc.transact(), 0)
2137 .unwrap()
2138 .cast::<Doc>()
2139 .unwrap();
2140 let uuid_2 = subdoc_2.guid();
2141 assert!(!Doc::ptr_eq(&subdoc_1, &subdoc_2));
2142
2143 let last_event = event.swap(None);
2144 assert_eq!(
2145 last_event,
2146 Some(Arc::new((
2147 vec![uuid_2.clone()],
2148 vec![uuid_2.clone()],
2149 vec![]
2150 )))
2151 );
2152
2153 subdoc_2.load(&mut doc.transact_mut());
2154 let last_event = event.swap(None);
2155 assert_eq!(
2156 last_event,
2157 Some(Arc::new((vec![], vec![], vec![uuid_2.clone()])))
2158 );
2159
2160 // apply from remote
2161 let doc2 = Doc::with_client_id(2);
2162 let event_c = event.clone();
2163 let _sub = doc2.observe_subdocs(move |_, e| {
2164 let added = e.added().map(|d| d.guid()).collect();
2165 let removed = e.removed().map(|d| d.guid()).collect();
2166 let loaded = e.loaded().map(|d| d.guid()).collect();
2167
2168 event_c.store(Some(Arc::new((added, removed, loaded))));
2169 });
2170 let u = Update::decode_v1(
2171 &doc.transact()
2172 .encode_state_as_update_v1(&StateVector::default()),
2173 );
2174 doc2.transact_mut().apply_update(u.unwrap()).unwrap();
2175 let subdoc_3 = {
2176 let array = doc2.get_or_insert_array("test");
2177 array
2178 .get(&doc2.transact(), 0)
2179 .unwrap()
2180 .cast::<Doc>()
2181 .unwrap()
2182 };
2183 assert!(subdoc_1.should_load());
2184 assert!(subdoc_1.auto_load());
2185 let uuid_3 = subdoc_3.guid();
2186 let last_event = event.swap(None);
2187 assert_eq!(
2188 last_event,
2189 Some(Arc::new((
2190 vec![uuid_3.clone()],
2191 vec![],
2192 vec![uuid_3.clone()]
2193 )))
2194 );
2195 }
2196
2197 #[test]
2198 fn to_json() {
2199 let doc = Doc::new();
2200 let mut txn = doc.transact_mut();
2201 let text = txn.get_or_insert_text("text");
2202 let array = txn.get_or_insert_array("array");
2203 let map = txn.get_or_insert_map("map");
2204 let xml_fragment = txn.get_or_insert_xml_fragment("xml-fragment");
2205 let xml_element = xml_fragment.insert(&mut txn, 0, XmlElementPrelim::empty("xml-element"));
2206 let xml_text = xml_fragment.insert(&mut txn, 0, XmlTextPrelim::new(""));
2207
2208 text.push(&mut txn, "hello");
2209 xml_text.push(&mut txn, "world");
2210 xml_fragment.insert(&mut txn, 0, XmlElementPrelim::empty("div"));
2211 xml_element.insert(&mut txn, 0, XmlElementPrelim::empty("body"));
2212 array.insert_range(&mut txn, 0, [1, 2, 3]);
2213 map.insert(&mut txn, "key1", "value1");
2214
2215 // sub documents cannot use their parent's transaction
2216 let sub_doc = Doc::new();
2217 let sub_text = sub_doc.get_or_insert_text("sub-text");
2218 let sub_doc = map.insert(&mut txn, "sub-doc", sub_doc);
2219 let mut sub_txn = sub_doc.transact_mut();
2220 sub_text.push(&mut sub_txn, "sample");
2221
2222 let actual = doc.to_json(&txn);
2223 let expected = any!({
2224 "text": "hello",
2225 "array": [1,2,3],
2226 "map": {
2227 "key1": "value1",
2228 "sub-doc": {
2229 "guid": sub_doc.guid().as_ref()
2230 }
2231 },
2232 "xml-fragment": "<div></div>world<xml-element><body></body></xml-element>",
2233 });
2234 assert_eq!(actual, expected);
2235 }
2236
2237 #[test]
2238 fn apply_snapshot_updates() {
2239 let update = {
2240 let doc = Doc::with_options(Options {
2241 client_id: 1,
2242 skip_gc: true,
2243 offset_kind: OffsetKind::Utf16,
2244 ..Options::default()
2245 });
2246 let txt = doc.get_or_insert_text("test");
2247 let mut txn = doc.transact_mut();
2248 txt.insert(&mut txn, 0, "hello");
2249
2250 let snap = txn.snapshot();
2251
2252 txt.insert(&mut txn, 5, " world");
2253
2254 let mut encoder = EncoderV1::new();
2255 txn.encode_state_from_snapshot(&snap, &mut encoder).unwrap();
2256 encoder.to_vec()
2257 };
2258
2259 let doc = Doc::with_client_id(1);
2260 let txt = doc.get_or_insert_text("test");
2261 let mut txn = doc.transact_mut();
2262 txn.apply_update(Update::decode_v1(&update).unwrap())
2263 .unwrap();
2264 let str = txt.get_string(&txn);
2265 assert_eq!(&str, "hello");
2266 }
2267
2268 #[test]
2269 fn out_of_order_updates() {
2270 let updates = Arc::new(Mutex::new(vec![]));
2271
2272 let d1 = Doc::new();
2273 let _sub = {
2274 let updates = updates.clone();
2275 d1.observe_update_v1(move |_, e| {
2276 let mut u = updates.lock().unwrap();
2277 u.push(Update::decode_v1(&e.update).unwrap());
2278 })
2279 .unwrap()
2280 };
2281
2282 let map = d1.get_or_insert_map("map");
2283 map.insert(&mut d1.transact_mut(), "a", 1);
2284 map.insert(&mut d1.transact_mut(), "a", 1.1);
2285 map.insert(&mut d1.transact_mut(), "b", 2);
2286
2287 assert_eq!(map.to_json(&d1.transact()), any!({"a": 1.1, "b": 2}));
2288
2289 let d2 = Doc::new();
2290
2291 {
2292 let mut updates = updates.lock().unwrap();
2293 let u3 = updates.pop().unwrap();
2294 let u2 = updates.pop().unwrap();
2295 let u1 = updates.pop().unwrap();
2296 let mut txn = d2.transact_mut();
2297 txn.apply_update(u1).unwrap();
2298 assert!(txn.store.pending.is_none()); // applied
2299 txn.apply_update(u3).unwrap();
2300 assert!(txn.store.pending.is_some()); // pending update waiting for u2
2301 txn.apply_update(u2).unwrap();
2302 assert!(txn.store.pending.is_none()); // applied after fixing the missing update
2303 }
2304
2305 let map = d2.get_or_insert_map("map");
2306 assert_eq!(map.to_json(&d2.transact()), any!({"a": 1.1, "b": 2}));
2307 }
2308
2309 #[test]
2310 fn encoding_buffer_overflow_errors() {
2311 assert_matches!(
2312 Update::decode_v1(&vec![
2313 0xe4, 0x9c, 0x10, 0x00, 0x05, 0xff, 0xff, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
2314 0x01, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xfe, 0xb8, 0xc2,
2315 0xe9, 0xad, 0x87, 0xd9, 0x12, 0x00, 0x00, 0x01, 0x01, 0xff, 0xed, 0xf6,
2316 ]),
2317 Err(crate::encoding::read::Error::EndOfBuffer(_))
2318 );
2319
2320 assert_matches!(
2321 Update::decode_v2(&vec![
2322 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00,
2323 0x16, 0x02, 0x00, 0x00, 0x01, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,
2324 ]),
2325 Err(crate::encoding::read::Error::EndOfBuffer(_))
2326 );
2327 assert_matches!(
2328 Update::decode_v2(&vec![
2329 0xe4, 0x95, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
2330 0x00, 0x00, 0xed, 0x01, 0xbe, 0x82, 0xe3, 0xc3, 0x1c, 0x01, 0x02, 0xe4, 0x95, 0x00,
2331 0x00, 0x01, 0x18, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x01, 0x00, 0x01, 0xed, 0x00,
2332 ]),
2333 Err(crate::encoding::read::Error::InvalidVarInt)
2334 );
2335 assert_matches!(
2336 Update::decode_v2(&vec![
2337 0x8f, 0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0xaa, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00,
2338 0x16, 0x02, 0x00, 0xe5, 0xc4, 0x43, 0x14, 0xe7, 0xa6, 0x8b, 0x93, 0xae, 0xb5, 0xfd,
2339 0x5d, 0xe8, 0x26, 0x9a, 0x8a, 0x59, 0x00, 0x31, 0xd5, 0x0f, 0x12, 0x01, 0x30, 0x00,
2340 0x00, 0x00,
2341 ]),
2342 Err(crate::encoding::read::Error::EndOfBuffer(_))
2343 );
2344 assert_matches!(
2345 Update::decode_v2(&vec![
2346 0x00, 0x01, 0x23, 0x00, 0x00, 0x00, 0x01, 0x02, 0x81, 0x00, 0x00, 0x10, 0x00, 0xc7,
2347 0xdc, 0x00, 0xc4, 0x7a, 0x80, 0x00, 0x41, 0xab, 0xea, 0xd6, 0x00, 0x01, 0x00, 0x00,
2348 0x01, 0x00, 0x00, 0x84, 0x00, 0x00, 0x10, 0xff, 0xc7, 0xdc, 0xff, 0x00, 0x00, 0x00,
2349 ]),
2350 Err(crate::encoding::read::Error::EndOfBuffer(_))
2351 );
2352 }
2353
2354 #[test]
2355 fn observe_after_transaction() {
2356 let d1 = Doc::with_client_id(1);
2357 let txt1 = d1.get_or_insert_text("text");
2358
2359 let e = Arc::new(ArcSwapOption::default());
2360 let e_copy = e.clone();
2361 d1.observe_after_transaction_with("key", move |txn| {
2362 e_copy.swap(Some(Arc::new((
2363 txn.before_state.clone(),
2364 txn.after_state.clone(),
2365 txn.delete_set.clone(),
2366 ))));
2367 })
2368 .unwrap();
2369
2370 txt1.insert(&mut d1.transact_mut(), 0, "hello world");
2371 let actual = e.swap(None);
2372 assert_eq!(
2373 actual,
2374 Some(Arc::new((
2375 StateVector::default(),
2376 StateVector::from_iter([(1, 11)]),
2377 DeleteSet::default()
2378 )))
2379 );
2380
2381 txt1.remove_range(&mut d1.transact_mut(), 2, 7);
2382 let actual = e.swap(None);
2383 assert_eq!(
2384 actual,
2385 Some(Arc::new((
2386 StateVector::from_iter([(1, 11)]),
2387 StateVector::from_iter([(1, 11)]),
2388 {
2389 let mut ds = DeleteSet::new();
2390 ds.insert(ID::new(1, 2), 7);
2391 ds
2392 }
2393 )))
2394 );
2395
2396 d1.unobserve_after_transaction("key").unwrap();
2397
2398 txt1.insert(&mut d1.transact_mut(), 4, " the door");
2399 let actual = e.swap(None);
2400 assert!(actual.is_none());
2401 }
2402
2403 #[test]
2404 fn force_gc() {
2405 let doc = Doc::with_options(Options {
2406 client_id: 1,
2407 skip_gc: true,
2408 ..Default::default()
2409 });
2410 let map = doc.get_or_insert_map("map");
2411
2412 {
2413 // create some initial data
2414 let mut txn = doc.transact_mut();
2415 let txt = map.insert(&mut txn, "text", TextPrelim::default()); // <1#0>
2416 txt.insert(&mut txn, 0, "c"); // <1#1>
2417 txt.insert(&mut txn, 0, "b"); // <1#2>
2418 txt.insert(&mut txn, 0, "a"); // <1#3>
2419
2420 // drop nested type
2421 map.remove(&mut txn, "text");
2422 }
2423
2424 // verify that skip_gc works and we have access to an original text content
2425 {
2426 let txn = doc.transact();
2427 let mut i = 1;
2428 for c in ["c", "b", "a"] {
2429 let block = txn
2430 .store()
2431 .blocks
2432 .get_block(&ID::new(1, i))
2433 .unwrap()
2434 .as_item()
2435 .unwrap();
2436 assert!(block.is_deleted(), "`abc` should be marked as deleted");
2437 assert_eq!(&block.content, &ItemContent::String(c.into()));
2438 i += 1;
2439 }
2440 }
2441
2442 // force GC and check if original content is hard deleted
2443 doc.transact_mut().force_gc();
2444
2445 let txn = doc.transact();
2446 let block = txn.store().blocks.get_block(&ID::new(1, 1)).unwrap();
2447 assert_eq!(block.len(), 3, "GCed blocks should be squashed");
2448 assert!(block.is_deleted(), "`abc` should be deleted");
2449 assert_matches!(&block, &BlockCell::GC(_));
2450 }
2451
2452 #[test]
2453 fn uuid_generation() {
2454 let guid = uuid_v4();
2455 let uuid = uuid::Uuid::parse_str(&guid).unwrap();
2456 assert_eq!(&*uuid.to_string(), &*guid);
2457 }
2458}
2459