1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
#![doc(
    html_logo_url = "https://raw.githubusercontent.com/y-crdt/y-crdt/main/logo-yrs.svg",
    html_favicon_url = "https://raw.githubusercontent.com/y-crdt/y-crdt/main/logo-yrs.svg"
)]

//! Yrs (read: "wires") is a high performance CRDT implementation based on the idea of **Shared Types**.
//! It is a compatible port of the [Yjs](https://github.com/yjs/yjs) CRDT.
//!
//! **Shared Types** work just like normal data types, but they automatically sync with other peers.
//!
//! A **Document** is the access point to create shared types, and to listen to update events.
//!
//! # Quick start
//!
//! Let's discuss basic features of Yrs. We'll introduce these concepts starting from
//! the following code snippet:
//!
//! ```rust
//! use yrs::{Doc, GetString, ReadTxn, StateVector, Text, Transact, Update};
//! use yrs::updates::decoder::Decode;
//! use yrs::updates::encoder::Encode;
//!
//! let doc = Doc::new();
//! let text = doc.get_or_insert_text("article");
//!
//! {
//!   let mut txn = doc.transact_mut();
//!   text.insert(&mut txn, 0, "hello");
//!   text.insert(&mut txn, 5, " world");
//!   // other rich text operations include formatting or inserting embedded elements
//! } // transaction is automatically committed when dropped
//!
//! assert_eq!(text.get_string(&doc.transact()), "hello world".to_owned());
//!
//! // synchronize state with remote replica
//! let remote_doc = Doc::new();
//! let remote_text = remote_doc.get_or_insert_text("article");
//! let remote_timestamp = remote_doc.transact().state_vector().encode_v1();
//!
//! // get update with contents not observed by remote_doc
//! let update = doc.transact().encode_diff_v1(&StateVector::decode_v1(&remote_timestamp).unwrap());
//! // apply update on remote doc
//! remote_doc.transact_mut().apply_update(Update::decode_v1(&update).unwrap());
//!
//! assert_eq!(text.get_string(&doc.transact()), remote_text.get_string(&remote_doc.transact()));
//! ```
//!
//! [Doc] is a core structure of Yrs. All other structures and operations are performed in
//! context of their document. All documents gets randomly generated [Doc::client_id] (which can be
//! also defined explicitly), which must be unique per active peer. It's crucial, as potential
//! concurrent changes made by different peers sharing the same [ClientID] will cause a document
//! state corruption.
//!
//! Next line defines [TextRef] - a shared collection specialized in providing collaborative rich text
//! operations. In snippet above it has been defined by calling [Doc::get_or_insert_text] method.
//! Shared types defined at the document level are so called root types. Root level types sharing
//! the same name across different peers are considered to be replicas of the same logical entity,
//! regardless of their type. It's highly recommended for all collaborating clients to define all
//! root level types they are going to use up front, during document creation. A list of supported
//! shared types include: [TextRef], [ArrayRef], [MapRef], [XmlTextRef], [XmlFragmentRef] and [XmlElementRef].
//!
//! Next section of code performs an update over the defined text replica. In Yrs all operations
//! must be executed in a scope of transaction created by the document they were defined in. We
//! can differentiate two transaction types:
//!
//! 1. [Read-only transactions](Transaction), created via [Transact::transact]/[Transact::try_transact].
//!    They are used only to access the contents of an underlying document store but they never
//!    alter it. They are useful for methods like reading the structure state or for serialization.
//!    It's allowed to have multiple active read-only transactions as long as no read-write
//!    transaction is in progress.
//! 2. [Read-write transactions](TransactionMut), create via [Transact::transact_mut]/[Transact::try_transact_mut].
//!    These can be used to modify the internal document state. These transactions work as
//!    intelligent batches. They are automatically committed when dropped, performing tasks like
//!    state cleaning, metadata compression and triggering event callbacks. Read-write transactions
//!    require exclusive access to an underlying document store - no other transaction (neither
//!    read-write nor read-only one) can be active while read-write transaction is to be created.
//!
//! In order to synchronize state between the document replicas living on a different peer processes,
//! there are two possible cases:
//!
//! 1. Peer who wishes to receive an update first encodes its document's [state vector](ReadTxn::state_vector).
//!    It's a logical timestamp describing which updates that has been observed by this document instance
//!    so far. This [StateVector] can be later serialized and passed to the remote collaborator. This
//!    collaborator can then deserialize it back and [generate an update](ReadTxn::encode_diff) which
//!    will contain all new changes performed since provided state vector. Finally this update can
//!    be passed back to the requester, [deserialized](Update::decode) and integrated into a document
//!    store via [TransactionMut::apply_update].
//! 2. Another propagation mechanism relies on subscribing to [Doc::observe_update_v1] or
//!    [Doc::observe_update_v2] events, which will be fired whenever an referenced document will
//!    detect new changes.
//!
//! While the 2nd option can produce smaller binary payload than 1st one at times and doesn't require
//! request-response cycles, it cannot pass the document state prior the observer callback
//! registration and expects that all changes will surely be delivered to other peer. A practical
//! approach (used i.e. by [y-sync protocol](https://crates.io/crates/y-sync)) is usually a combination
//! of both variants: use 1st one on connection initialization between two peers followed by
//! 2nd approach to deliver subsequent changes.
//!
//! # Formatting and embedding
//!
//! While the quick start example covered only a simple text insertions, structures such as
//! [TextRef]/[XmlTextRef] are capable of including more advanced operators, such as adding
//! [formatting attributes](Text::format), [inserting embedded content](Text::insert_embed)
//! (eg. image binaries or [ArrayRef]s that we could interpret in example as nested tables).
//!
//! ```rust
//! use yrs::{Any, Array, ArrayPrelim, Doc, GetString, Text, Transact, WriteTxn, XmlFragment, XmlTextPrelim};
//! use yrs::types::Attrs;
//!
//! let doc = Doc::new();
//! let mut txn = doc.transact_mut();
//! let f = txn.get_or_insert_xml_fragment("article");
//! let xml = f.insert(&mut txn, 0, XmlTextPrelim::new(""));
//!
//! let bold = Attrs::from([("b".into(), true.into())]);
//! let italic = Attrs::from([("i".into(), true.into())]);
//!
//! xml.insert(&mut txn, 0, "hello ");
//! xml.insert_with_attributes(&mut txn, 6, "world", italic);
//! xml.format(&mut txn, 0, 5, bold);
//!
//! assert_eq!(xml.get_string(&txn), "<b>hello</b> <i>world</i>");
//!
//! // remove formatting
//! let remove_italic = Attrs::from([("i".into(), Any::Null)]);
//! xml.format(&mut txn, 6, 5, remove_italic);
//!
//! assert_eq!(xml.get_string(&txn), "<b>hello</b> world");
//!
//! // insert binary payload eg. images
//! let image = b"deadbeaf".to_vec();
//! xml.insert_embed(&mut txn, 1, image);
//!
//! // insert nested shared type eg. table as ArrayRef of ArrayRefs
//! let table = xml.insert_embed(&mut txn, 5, ArrayPrelim::default());
//! let header = table.insert(&mut txn, 0, ArrayPrelim::from(["Book title", "Author"]));
//! let row = table.insert(&mut txn, 1, ArrayPrelim::from(["\"Moby-Dick\"", "Herman Melville"]));
//! ```
//!
//! Keep in mind that this kind of special content may not be displayed using standard methods
//! ([TextRef::get_string] returns only inserted text and ignores other content, while
//! [XmlTextRef::get_string] renders formatting attributes as XML nodes, but still ignores embedded
//! values). Reason behind this behavior is that as generic collaboration library, Yrs cannot make
//! opinionated decisions in this regard - whenever a full collection of text chunks, formatting
//! attributes or embedded items is required, use [Text::diff] instead.
//!
//! # Cursor positioning
//!
//! Another common problem of collaborative text editors is a requirement of keeping track of cursor
//! position in the face of concurrent updates incoming from remote peers. Let's present the problem
//! on following example:
//!
//! ```rust
//! use yrs::{Doc, GetString, ReadTxn, StateVector, Text, Transact, Update};
//! use yrs::updates::decoder::Decode;
//!
//! let doc1 = Doc::with_client_id(1);
//! let text1 = doc1.get_or_insert_text("article");
//! let mut txn1 = doc1.transact_mut();
//! text1.insert(&mut txn1, 0, "hello");
//!
//! let doc2 = Doc::with_client_id(2);
//! let text2 = doc2.get_or_insert_text("article");
//! let mut txn2 = doc2.transact_mut();
//! text2.insert(&mut txn2, 0, "world");
//!
//! const INDEX: usize = 1;
//!
//! // Doc 2: cursor at index 1 points to character 'o'
//! let str = text2.get_string(&txn2);
//! assert_eq!(str.chars().nth(INDEX), Some('o'));
//!
//! // synchronize full state of doc1 -> doc2
//! txn2.apply_update(Update::decode_v1(&txn1.encode_diff_v1(&StateVector::default())).unwrap());
//!
//! // Doc 2: cursor at index 1 no longer points to the same character
//! let str = text2.get_string(&txn2);
//! assert_ne!(str.chars().nth(INDEX), Some('o'));
//! ```
//!
//! Since [TransactionMut::apply_update] merges updates performed by remote peer, some of these
//! them may shift the cursor position. However in such case the old index that we used (`1` in the
//! example above) is no longer valid.
//!
//! To address these issues, we can make use of [StickyIndex] struct to save the permanent
//! location, that will persist between concurrent updates being made:
//!
//! ```rust
//! use yrs::{Assoc, Doc, GetString, ReadTxn, IndexedSequence, StateVector, Text, Transact, Update};
//! use yrs::updates::decoder::Decode;
//!
//! let doc1 = Doc::with_client_id(1);
//! let text1 = doc1.get_or_insert_text("article");
//! let mut txn1 = doc1.transact_mut();
//! text1.insert(&mut txn1, 0, "hello");
//!
//! let doc2 = Doc::with_client_id(2);
//! let text2 = doc2.get_or_insert_text("article");
//! let mut txn2 = doc2.transact_mut();
//! text2.insert(&mut txn2, 0, "world");
//!
//! const INDEX: usize = 1;
//!
//! // Doc 2: cursor at index 1 points to character 'o'
//! let str = text2.get_string(&txn2);
//! assert_eq!(str.chars().nth(INDEX), Some('o'));
//!
//! // get a permanent index for cursor at index 1
//! let pos = text2.sticky_index(&mut txn2, INDEX as u32, Assoc::After).unwrap();
//!
//! // synchronize full state of doc1 -> doc2
//! txn2.apply_update(Update::decode_v1(&txn1.encode_diff_v1(&StateVector::default())).unwrap());
//!
//! // restore the index from position saved previously
//! let idx = pos.get_offset(&txn2).unwrap();
//! let str = text2.get_string(&txn2);
//! assert_eq!(str.chars().nth(idx.index as usize), Some('o'));
//! ```
//!
//! [StickyIndex] structure is serializable and can be persisted or passed over the network as
//! well, which may help with tracking and displaying the cursor location of other peers.
//!
//! # Weak links and quotations
//!
//! This functionality requires a "weak" feature flag to be turned on:
//! ```toml
//! yrs = { version = "0.17", features = ["weak"] }
//! ```
//!
//! Yrs document structure can be represented as a tree of elements. That means that usually a node
//! can have only one parent and cannot be referenced by any other node. This can be changed by
//! usage of weak links - they offer you a way to reference to values existing in other parts of
//! the document (also other collections):
//!
//! - [Map] elements can be references via [Map::link] method.
//! - Other collections like text and arrays, can quote entire ranges of values via [Quotable::quote]
//!   method.
//!
//! Both of these methods return a [WeakPrelim] struct can be integrated as an input value in other
//! collections and convert into [WeakRef] shared type.
//!
//! ```rust
//! use yrs::{Doc, Text, Transact, GetString, Quotable, Map};
//!
//! let doc = Doc::new();
//! let text = doc.get_or_insert_text("text");
//! let map = doc.get_or_insert_map("map");
//! let mut txn = doc.transact_mut();
//! text.insert(&mut txn, 0, "hello!");
//! let quote = text.quote(&txn, 0..5).unwrap();
//! let quote = map.insert(&mut txn, "title", quote);
//!
//! // retrieve quoted text fragment
//! assert_eq!(quote.get_string(&txn), "hello".to_string());
//!
//! // quotations are actively reacting to changes happening at source within quoted range
//! text.insert(&mut txn, 5, " world");
//! // since quoted range 0..5 was right-side exclusive, index 5 itself is not included in range,
//! // but inserts between position 4 and 5 are
//! assert_eq!(quote.get_string(&txn), "hello world".to_string());
//! ```
//!
//! Weak refs also expose observer API that allows to subscribe to changes happening in source
//! collections within quoted range.
//!
//! Keep in mind that weak refs don't maintain ownership over quoted elements. If a source
//! collection removes a quoted element, it will no longer be accessible from weak ref:
//!
//! ```rust
//! use yrs::{Doc, Transact, Quotable, Map};
//!
//! let doc = Doc::new();
//! let map = doc.get_or_insert_map("map");
//! let mut txn = doc.transact_mut();
//! map.insert(&mut txn, "origin", "value");
//! // establish a link 'origin' entry
//! let link = map.link(&txn, "origin").unwrap();
//! let link = map.insert(&mut txn, "link", link);
//! let linked_value: String = link.try_deref(&txn).unwrap();
//! assert_eq!(linked_value, "value".to_string());
//!
//! // remove original value
//! map.remove(&mut txn, "origin");
//! let linked_value = link.try_deref_value(&txn);
//! assert_eq!(linked_value, None); // linked value is no longer accessible
//! ```
//!
//! # Undo/redo
//!
//! Among very popular features of many user-facing applications is an ability to revert/reapply
//! operations performed by user. This becomes even more complicated, once we consider multiple peers
//! collaborating on the same document, as we may need to skip over the changes synchronized from
//! remote peers - even thou they could have happened later - in order to only undo our own actions.
//! [UndoManager] is a Yrs response for these needs, supporting wide variety of options:
//!
//! ```rust
//! use yrs::{Doc, GetString, ReadTxn, Text, Transact, UndoManager, Update};
//! use yrs::undo::Options;
//! use yrs::updates::decoder::Decode;
//!
//! let local = Doc::with_client_id(123);
//! let text1 = local.get_or_insert_text("article");
//! let mut mgr = UndoManager::with_options(&local, &text1, Options::default());
//! mgr.include_origin(local.client_id()); // only track changes originating from local peer
//!
//! let remote = Doc::with_client_id(321);
//! let text2 = remote.get_or_insert_text("article");
//!
//! // perform changes locally
//! text1.push(&mut local.transact_mut_with(local.client_id()), "hello ");
//! mgr.reset(); // prevent previous and next operation to be treated by Undo manager as one batch
//! text1.push(&mut local.transact_mut_with(local.client_id()), "world");
//! assert_eq!(text1.get_string(&local.transact()), "hello world");
//!
//! // perform remote changes - these are not being tracked by mgr
//! {
//!     let mut remote_txn = remote.transact_mut_with(remote.client_id());
//!     text2.push(&mut remote_txn, "everyone");
//!     assert_eq!(text2.get_string(&remote_txn), "everyone");
//! }
//!
//! // sync changes from remote to local
//! let update = remote.transact().encode_state_as_update_v1(&local.transact().state_vector());
//! local.transact_mut().apply_update(Update::decode_v1(&update).unwrap());
//! assert_eq!(text1.get_string(&local.transact()), "hello worldeveryone"); // remote changes synced
//!
//! // undo last performed change on local
//! mgr.undo().unwrap();
//! assert_eq!(text1.get_string(&local.transact()), "hello everyone");
//!
//! // redo change we undone
//! mgr.redo().unwrap();
//! assert_eq!(text1.get_string(&local.transact()), "hello worldeveryone");
//! ```
//!
//! > Keep in mind, that in order to serve its purpose, undo manager may need to implicitly create
//! transactions over underlying [Doc] - for that reason make sure that no other transaction is
//! active while calling methods like [UndoManager::undo] or [UndoManager::redo].
//!
//! It's important to understand a context, in which [UndoManager] operates:
//!
//! - **origins** can be specific classifiers attached to read-write transactions upon creation (see:
//!   [Transact::transact_mut_with]). Undo manager can [include](UndoManager::include_origin) any
//!   number of origins to its track scope. By default no origin is specified: in such case undo
//!   manager will track all changes without looking at transaction origin.
//! - **scope** refers to shared collection references such as [TextRef], [MapRef] etc. Undo manager
//!   will only track operations performed on tracked scope refs. By default at least one such
//!   reference must be specified, but they can be [expanded](UndoManager::expand_scope) to include
//!   multiple collections at once if necessary.
//!
//! Notice, that undo/redo changes are **not** mapped 1-1 on the update batches committed by
//! transactions. As an example: a frequent case includes establishing a new transaction for every
//! user key stroke. Meanwhile we may decide to use different granularity of undo/redo actions.
//! These are grouped together on time-based ranges (configurable in [undo::Options], which is
//! 500ms by default). You can also set them explicitly by calling [UndoManager::reset] method.
//!
//! # Showing past revisions of the document
//!
//! Another feature of Yrs is an ability to snapshot and recover versions of the document,
//! as well as show the differences between them:
//!
//! ```rust
//! use yrs::{Doc, GetString, Options, ReadTxn, Text, Transact, Update, WriteTxn, XmlFragment, XmlTextPrelim};
//! use yrs::types::Attrs;
//! use yrs::types::text::{Diff, YChange};
//! use yrs::updates::decoder::Decode;
//! use yrs::updates::encoder::{Encoder, EncoderV1};
//!
//! let doc = Doc::with_options(Options {
//!     skip_gc: true,  // in order to support revisions we cannot garbage collect deleted blocks
//!     ..Options::default()
//! });
//! let mut txn = doc.transact_mut();
//! let f = txn.get_or_insert_xml_fragment("article");
//! let text = f.insert(&mut txn, 0, XmlTextPrelim::new(""));
//!
//! const INIT: &str = "hello world";
//! text.push(&mut txn, INIT);
//!
//! // save current state of the document: "hello world"
//! let rev = txn.snapshot();
//!
//! // change document state
//! let italic = Attrs::from([("i".into(), true.into())]);
//! text.format(&mut txn, 6, 5, italic.clone());
//! text.remove_range(&mut txn, 2, 3);
//! assert_eq!(text.get_string(&txn), "he <i>world</i>");
//!
//! // encode past version of the document
//! let mut encoder = EncoderV1::new();
//! txn.encode_state_from_snapshot(&rev, &mut encoder).unwrap();
//! let update = encoder.to_vec();
//!
//! // restore the past state
//! let doc = Doc::new();
//! let mut txn = doc.transact_mut();
//! let f = txn.get_or_insert_xml_fragment("article");
//! txn.apply_update(Update::decode_v1(&update).unwrap());
//! let text = f.get(&mut txn, 0).unwrap().into_xml_text().unwrap();
//!
//! assert_eq!(text.get_string(&txn), INIT);
//! ```
//!
//! Keep in mind that an update created from past snapshot via [TransactionMut::encode_state_from_snapshot]
//! doesn't contain updates that happened after that snapshot. What does that mean? While you can
//! continue making new updates on top of that revision, they will be no longer compatible with any
//! changes made on the original document since the snapshot has been made, therefore [TransactionMut::apply_update]
//! on updates generated between two document revisions that branched their state is no longer possible.
//!
//! For the reason above main use case of this feature is rendering read-only state of the [Doc]
//! or restoring document from its past state ie. when current state has been irrecoverably corrupted.
//!
//! # Other shared types
//!
//! So far we only discussed rich text oriented capabilities of Yrs. However, it's possible to make
//! use of Yrs to represent any tree-like object:
//!
//! - [ArrayRef] can be used to represent any indexable sequence of values. If there are multiple
//!   peers inserting values at the same position, a [ClientID] will be used to determine a final
//!   deterministic order once all peers get in sync.
//! - [MapRef] is a map object (with keys limited to be strings), where values can be of any given
//!   type. If there are multiple peers updating the same entry concurrently - creating an update
//!   conflict in the result - Yrs will prioritize update belonging to a peer with higher [ClientID]
//!   to make conflict resolution algorithm deterministic.
//! - Yrs also provides support fo XML nodes in form of [XmlElementRef], [XmlTextRef] and [XmlFragmentRef].
//!
//! Underneath all of these types are represented by the same abstract [types::Branch] type. Each
//! branch is always capable of working as both indexed sequence of elements and a map. In practice
//! specialized shared types are actually projections over branch type and can be used interchangeably
//! if needed, i.e.: [XmlElementRef] can be also interpreted as [MapRef], in which case the collection
//! of that XML node attributes become key-value entries of reinterpreted map's.
//!
//! # Preliminary vs Integrated types
//!
//! In Yrs core library, every shared type has 2 representations:
//!
//! - **Integrated type** (eg. [TextRef], [ArrayRef], [MapRef]) represents a reference that has already
//!   been attached to its parent [Doc]. As such, its state is tracked as part of that document, it
//!   can be modified concurrently by multiple peers and any conflicts that occurred due to such
//!   actions will be automatically resolved accordingly to [YATA conflict resolution algorithm](https://www.researchgate.net/publication/310212186_Near_Real-Time_Peer-to-Peer_Shared_Editing_on_Extensible_Data_Types).
//! - **Preliminary type** (eg. [TextPrelim], [ArrayPrelim], [MapPrelim]) represents a content that
//!   we want to eventually turn into an integrated reference, but it has not been integrated yet.
//!
//! Whenever we want to nest shared types one into another - using methods such as [Array::insert],
//! [Map::insert] or [Text::insert_embed] - we always must do so using preliminary types. These
//! methods will return an integrated representation of the preliminary content we wished to integrate.
//!
//! Keep in mind that we cannot integrate references that have been already integrated - neither in
//! the same document nor in any other one. Yjs/Yrs doesn't allow to have the same object to be linked
//! in multiple places. Same rule concerns primitive types (they will eventually be serialized and
//! deserialized as unique independent objects), integrated types or sub-documents.
//!
//! # Shared collection hooks
//!
//! While type like [TextRef], [MapRef] etc. refer to addresses of objects living in memory,
//! sometime you'd like to be able to uniquely identify the same collection across its different
//! replicas living on other peers. This is possible via hooks:
//!
//! ```rust
//! use yrs::{Array, ArrayRef, Doc, Hook, MapPrelim, ReadTxn, RootRef, SharedRef, Transact, Update};
//! use yrs::types::ToJson;
//! use yrs::updates::decoder::Decode;
//!
//! // create a logical identifier to a root type
//! let root = ArrayRef::root("root");
//!
//! let local = Doc::with_client_id(1);
//! let local_array = root.get_or_create(&mut local.transact_mut());
//! assert_eq!(local_array.hook(), Hook::from(root.clone())); // another way to get hook for existing type
//!
//! let local_map = local_array.push_back(&mut local.transact_mut(), MapPrelim::from([("key", "old")]));
//! let nested = local_map.hook(); // logical identifier to a nested shared type
//!
//! let remote = Doc::with_client_id(2);
//! let remote_array = root.get_or_create(&mut local.transact_mut());
//! // we haven't synchronized yet, so nested element doesn't exist on remote
//! assert!(nested.get(&remote.transact()).is_none());
//!
//! // synchronize the changes
//! {
//!     let mut txn = remote.transact_mut();
//!     let update = local.transact().encode_state_as_update_v1(&txn.state_vector());
//!     txn.apply_update(Update::decode_v1(&update).unwrap());
//! }
//!
//! // after synchronizing, we can now instantiate instance of the same logical type
//! let remote_map = nested.get(&remote.transact()).unwrap();
//! assert_eq!(local_map.hook(), remote_map.hook());
//! assert_eq!(local_map.to_json(&local.transact()), remote_map.to_json(&remote.transact()));
//! ```
//!
//! Logical references are serializable. They also can help to avoid segfaults in cases when we hold
//! an unsafe reference to a nested collection that has been already deleted by concurrent operation.
//!
//! # Transaction event lifecycle
//!
//! Yrs provides a variety of lifecycle events, which enable users to react on various situations
//! and changes performed. Some of these events are used by Yrs own features (e.g. [UndoManager]).
//! They are always triggered once performed update is committed by dropping or
//! [committing](TransactionMut::commit) a read-write transaction.
//!
//! An order in which these updates are fired is as follows:
//!
//! 1. Observers on updated shared types: [TextRef::observe], [ArrayRef::observe], [MapRef::observe],
//!    [XmlTextRef::observe], [XmlFragmentRef::observe] and [XmlElementRef::observe].
//! 2. [Deep observers](DeepObservable::observe_deep) (special kind of observers that are bubbled up
//!    from nested shared types through their parent collections hierarchy).
//! 3. After transaction callbacks: [Doc::observe_after_transaction].
//! 4. After transaction cleanup callbacks (moment after all changes performed by transaction have
//!    been compressed an integrated into document store): [Doc::observe_transaction_cleanup].
//! 5. Update callbacks: [Doc::observe_update_v1] and [Doc::observe_update_v2]. Useful when we want
//!    to encode and propagate incremental changes made by transaction to other peers.
//! 6. Sub-document change callbacks: [Doc::observe_subdocs].
//!
//! # Update encoding v1 vs. v2
//!
//! Yrs ships with so called lib0 encoding, which offers two different variants, both of which are
//! compatible with [Yjs](https://docs.yjs.dev/) and can be used to bridge between applications
//! written in different languages using Yrs underneath. They offer a highly compact format,
//! that aims to produce small binary payload size and high encoding/decoding speed.
//!
//! V1 encoding is the default one and should be preferred most of the time. V2 encoding aims to
//! perform payload size optimizations whenever multiple updates are being encoded and passed
//! together (e.g. when you want to serialize an entire document state), however for small updates
//! (e.g. sending individual user keystrokes) V2 may turn out to be less optimal than its V1
//! equivalent.
//!
//! # Awareness and y-sync protocol
//!
//! Sometimes it's not always feasible to keep all state changes related to a document within a
//! document update history - especially if they are notifications bound to a single user or session.
//! For this reason most of the editor bindings using Yjs supplement the document state with
//! [sync::Awareness] - it's a separate entity that keeps user related data such as username
//! or cursor position, but without the overhead of keeping metadata necessary for conflict
//! resolution.
//!
//! [sync::Awareness] together with [Doc] updates combined create basis of y-sync [sync::Protocol].
//! It's used by most of the network providers in Yjs/Yrs ecosystem and enables universal way of
//! communicating between different systems.
//!
//! In its core y-sync protocol can operate as a simple state machine that serves exchanging and
//! responding to different message types described by the protocol. The [sync::DefaultProtocol]
//! provides all the message handlers necessary to make basic communication possible.
//!
//! y-sync protocol is extensible leaves a space for the users to define their own messages if
//! necessary:
//!
//! ```rust
//! use yrs::sync::{Awareness, Message, Protocol, Error};
//!
//! struct MyProtocol;
//! impl Protocol for MyProtocol {
//!     fn missing_handle(&self, awareness: &mut Awareness, tag: u8, data: Vec<u8>) -> Result<Option<Message>, Error> {
//!         // you can not only override existing message handlers but also define your own
//!         Ok(Some(Message::Custom(tag, data))) // echo
//!     }
//! }
//! ```
//!
//! # External learning materials
//!
//! - [A short walkthrough over YATA](https://bartoszsypytkowski.com/yata/) - a conflict resolution
//!   algorithm used by Yrs/Yjs.
//! - [Deep dive into internal architecture of Yrs](https://bartoszsypytkowski.com/yrs-architecture/).
//! - [Detailed explanation of conflict-free reordering algorithm](https://bartoszsypytkowski.com/yata-move/) used by Yrs.

mod alt;
pub mod block;
mod block_store;
pub mod doc;
mod event;
mod id_set;
mod store;
mod transaction;
pub mod types;
mod update;
pub mod updates;
mod utils;

pub mod any;
pub mod atomic;
mod block_iter;
pub mod branch;
pub mod encoding;
mod error;
mod gc;
pub mod iter;
mod moving;
pub mod observer;
mod slice;
mod state_vector;
pub mod sync;
#[cfg(test)]
mod test_utils;
#[cfg(test)]
mod tests;
pub mod undo;

pub use crate::alt::{
    diff_updates_v1, diff_updates_v2, encode_state_vector_from_update_v1,
    encode_state_vector_from_update_v2, merge_updates_v1, merge_updates_v2,
};
pub use crate::any::Any;
pub use crate::block::ID;
pub use crate::branch::BranchID;
pub use crate::branch::Hook;
pub use crate::branch::Nested;
pub use crate::branch::Root;
pub use crate::doc::Doc;
pub use crate::doc::OffsetKind;
pub use crate::doc::Options;
pub use crate::doc::Transact;
pub use crate::event::{SubdocsEvent, SubdocsEventIter, TransactionCleanupEvent, UpdateEvent};
pub use crate::id_set::DeleteSet;
pub use crate::moving::Assoc;
pub use crate::moving::IndexScope;
pub use crate::moving::IndexedSequence;
pub use crate::moving::Offset;
pub use crate::moving::StickyIndex;
pub use crate::observer::{Observer, ObserverMut, Subscription};
pub use crate::state_vector::Snapshot;
pub use crate::state_vector::StateVector;
pub use crate::store::Store;
pub use crate::transaction::Origin;
pub use crate::transaction::ReadTxn;
pub use crate::transaction::RootRefs;
pub use crate::transaction::Transaction;
pub use crate::transaction::TransactionMut;
pub use crate::transaction::WriteTxn;
pub use crate::types::array::Array;
pub use crate::types::array::ArrayPrelim;
pub use crate::types::array::ArrayRef;
pub use crate::types::map::Map;
pub use crate::types::map::MapPrelim;
pub use crate::types::map::MapRef;
pub use crate::types::text::Text;
pub use crate::types::text::TextPrelim;
pub use crate::types::text::TextRef;
#[cfg(feature = "weak")]
pub use crate::types::weak::{Quotable, WeakPrelim, WeakRef};
pub use crate::types::xml::Xml;
pub use crate::types::xml::XmlElementPrelim;
pub use crate::types::xml::XmlElementRef;
pub use crate::types::xml::XmlFragment;
pub use crate::types::xml::XmlFragmentPrelim;
pub use crate::types::xml::XmlFragmentRef;
pub use crate::types::xml::XmlNode;
pub use crate::types::xml::XmlTextPrelim;
pub use crate::types::xml::XmlTextRef;
pub use crate::types::DeepObservable;
pub use crate::types::GetString;
pub use crate::types::Observable;
pub use crate::types::RootRef;
pub use crate::types::SharedRef;
pub use crate::types::Value;
pub use crate::update::Update;

pub type UndoManager = crate::undo::UndoManager<()>;
pub type Uuid = std::sync::Arc<str>;

/// Generate random v4 UUID.
/// (See: https://www.rfc-editor.org/rfc/rfc4122#section-4.4)
pub fn uuid_v4() -> Uuid {
    uuid_v4_from(&mut fastrand::Rng::new())
}

/// Generate random v4 UUID.
/// (See: https://www.rfc-editor.org/rfc/rfc4122#section-4.4)
pub fn uuid_v4_from(rng: &mut fastrand::Rng) -> Uuid {
    let mut b = [0u8; 16];
    rng.fill(&mut b);

    // According to RFC 4122 - Section 4.4, UUID v4 requires setting up following:
    b[6] = b[6] & 0x0f | 0x40; // time_hi_and_version (bits 4-7 of 7th octet)
    b[8] = b[8] & 0x3f | 0x80; // clock_seq_hi_and_reserved (bit 6 & 7 of 9th octet)

    let uuid = format!(
        "{:x}{:x}{:x}{:x}-{:x}{:x}-{:x}{:x}-{:x}{:x}-{:x}{:x}{:x}{:x}{:x}{:x}",
        b[0],
        b[1],
        b[2],
        b[3],
        b[4],
        b[5],
        b[6],
        b[7],
        b[8],
        b[9],
        b[10],
        b[11],
        b[12],
        b[13],
        b[14],
        b[15]
    );
    uuid.into()
}