Skip to main content

yrs/
lib.rs

1use std::collections::{Bound, HashMap};
2use std::ffi::{c_char, c_void, CStr, CString};
3use std::mem::{forget, ManuallyDrop, MaybeUninit};
4use std::ops::{Deref, RangeBounds};
5use std::ptr::{null, null_mut};
6use std::sync::atomic::{AtomicPtr, Ordering};
7use std::sync::Arc;
8use yrs::block::{ClientID, EmbedPrelim, ItemContent, Prelim, Unused};
9use yrs::branch::BranchPtr;
10use yrs::encoding::read::Error;
11use yrs::error::UpdateError;
12use yrs::json_path::JsonPathIter as NativeJsonPathIter;
13use yrs::types::array::ArrayEvent;
14use yrs::types::array::ArrayIter as NativeArrayIter;
15use yrs::types::map::MapEvent;
16use yrs::types::map::MapIter as NativeMapIter;
17use yrs::types::text::{Diff, TextEvent, YChange};
18use yrs::types::weak::{LinkSource, Unquote as NativeUnquote, WeakEvent, WeakRef};
19use yrs::types::xml::{Attributes as NativeAttributes, XmlOut};
20use yrs::types::xml::{TreeWalker as NativeTreeWalker, XmlFragment};
21use yrs::types::xml::{XmlEvent, XmlTextEvent};
22use yrs::types::{Attrs, Change, Delta, EntryChange, Event, PathSegment, ToJson, TypeRef};
23use yrs::undo::EventKind;
24use yrs::updates::decoder::{Decode, DecoderV1};
25use yrs::updates::encoder::{Encode, Encoder, EncoderV1, EncoderV2};
26use yrs::{
27    uuid_v4, Any, Array, ArrayRef, Assoc, BranchID, GetString, IdSet, JsonPath, JsonPathEval, Map,
28    MapRef, Observable, OffsetKind, Options, Origin, Out, Quotable, ReadTxn, Snapshot, StateVector,
29    StickyIndex, Store, SubdocsEvent, SubdocsEventIter, Text, TextRef, Transact,
30    TransactionCleanupEvent, Update, Xml, XmlElementPrelim, XmlElementRef, XmlFragmentRef,
31    XmlTextPrelim, XmlTextRef, ID,
32};
33
34/// Flag used by `YInput` to pass JSON string for an object that should be deserialized and
35/// stored internally as fully fledged scalar type.
36pub const Y_JSON: i8 = -9;
37
38/// Flag used by `YInput` and `YOutput` to tag boolean values.
39pub const Y_JSON_BOOL: i8 = -8;
40
41/// Flag used by `YInput` and `YOutput` to tag floating point numbers.
42pub const Y_JSON_NUM: i8 = -7;
43
44/// Flag used by `YInput` and `YOutput` to tag 64-bit integer numbers.
45pub const Y_JSON_INT: i8 = -6;
46
47/// Flag used by `YInput` and `YOutput` to tag strings.
48pub const Y_JSON_STR: i8 = -5;
49
50/// Flag used by `YInput` and `YOutput` to tag binary content.
51pub const Y_JSON_BUF: i8 = -4;
52
53/// Flag used by `YInput` and `YOutput` to tag embedded JSON-like arrays of values,
54/// which themselves are `YInput` and `YOutput` instances respectively.
55pub const Y_JSON_ARR: i8 = -3;
56
57/// Flag used by `YInput` and `YOutput` to tag embedded JSON-like maps of key-value pairs,
58/// where keys are strings and v
59pub const Y_JSON_MAP: i8 = -2;
60
61/// Flag used by `YInput` and `YOutput` to tag JSON-like null values.
62pub const Y_JSON_NULL: i8 = -1;
63
64/// Flag used by `YInput` and `YOutput` to tag JSON-like undefined values.
65pub const Y_JSON_UNDEF: i8 = 0;
66
67/// Flag used by `YInput` and `YOutput` to tag content, which is an `YArray` shared type.
68pub const Y_ARRAY: i8 = 1;
69
70/// Flag used by `YInput` and `YOutput` to tag content, which is an `YMap` shared type.
71pub const Y_MAP: i8 = 2;
72
73/// Flag used by `YInput` and `YOutput` to tag content, which is an `YText` shared type.
74pub const Y_TEXT: i8 = 3;
75
76/// Flag used by `YInput` and `YOutput` to tag content, which is an `YXmlElement` shared type.
77pub const Y_XML_ELEM: i8 = 4;
78
79/// Flag used by `YInput` and `YOutput` to tag content, which is an `YXmlText` shared type.
80pub const Y_XML_TEXT: i8 = 5;
81
82/// Flag used by `YInput` and `YOutput` to tag content, which is an `YXmlFragment` shared type.
83pub const Y_XML_FRAG: i8 = 6;
84
85/// Flag used by `YInput` and `YOutput` to tag content, which is an `YDoc` shared type.
86pub const Y_DOC: i8 = 7;
87
88/// Flag used by `YInput` and `YOutput` to tag content, which is an `YWeakLink` shared type.
89pub const Y_WEAK_LINK: i8 = 8;
90
91/// Flag used by `YOutput` to tag content, which is an undefined shared type. This usually happens
92/// when it's referencing a root type that has not been initalized localy.
93pub const Y_UNDEFINED: i8 = 9;
94
95/// Flag used to mark a truthy boolean numbers.
96pub const Y_TRUE: u8 = 1;
97
98/// Flag used to mark a falsy boolean numbers.
99pub const Y_FALSE: u8 = 0;
100
101/* pub types below are used by cbindgen for c header generation */
102
103/// A Yrs document type. Documents are the most important units of collaborative resources management.
104/// All shared collections live within a scope of their corresponding documents. All updates are
105/// generated on per-document basis (rather than individual shared type). All operations on shared
106/// collections happen via `YTransaction`, which lifetime is also bound to a document.
107///
108/// Document manages so-called root types, which are top-level shared types definitions (as opposed
109/// to recursively nested types).
110pub type Doc = yrs::Doc;
111
112/// A common shared data type. All Yrs instances can be refered to using this data type (use
113/// `ytype_kind` function if a specific type needs to be determined). Branch pointers are passed
114/// over type-specific functions like `ytext_insert`, `yarray_insert` or `ymap_insert` to perform
115/// a specific shared type operations.
116///
117/// Using write methods of different shared types (eg. `ytext_insert` and `yarray_insert`) over
118/// the same branch may result in undefined behavior.
119pub type Branch = yrs::branch::Branch;
120
121/// Subscription to any kind of observable events, like `ymap_observe`, `ydoc_observe_updates_v1` etc.
122/// This subscription can be destroyed by calling `yunobserve` function, which will cause to unsubscribe
123/// correlated callback.
124pub type Subscription = yrs::Subscription;
125
126/// Iterator structure used by shared array data type.
127#[repr(transparent)]
128pub struct ArrayIter(NativeArrayIter<&'static Transaction, Transaction>);
129
130/// Iterator structure used by `yweak_iter` function call.
131#[repr(transparent)]
132pub struct WeakIter(NativeUnquote<'static, Transaction>);
133
134/// Iterator structure used by shared map data type. Map iterators are unordered - there's no
135/// specific order in which map entries will be returned during consecutive iterator calls.
136#[repr(transparent)]
137pub struct MapIter(NativeMapIter<'static, &'static Transaction, Transaction>);
138
139/// Iterator structure used by XML nodes (elements and text) to iterate over node's attributes.
140/// Attribute iterators are unordered - there's no specific order in which map entries will be
141/// returned during consecutive iterator calls.
142#[repr(transparent)]
143pub struct Attributes(NativeAttributes<'static, &'static Transaction, Transaction>);
144
145/// Iterator used to traverse over the complex nested tree structure of a XML node. XML node
146/// iterator walks only over `YXmlElement` and `YXmlText` nodes. It does so in ordered manner (using
147/// the order in which children are ordered within their parent nodes) and using **depth-first**
148/// traverse.
149#[repr(transparent)]
150pub struct TreeWalker(NativeTreeWalker<'static, &'static Transaction, Transaction>);
151
152/// Transaction is one of the core types in Yrs. All operations that need to touch or
153/// modify a document's contents (a.k.a. block store), need to be executed in scope of a
154/// transaction.
155#[repr(transparent)]
156pub struct Transaction(TransactionInner);
157
158/// Iterator structure used by json path queries to traverse over the results of a query.
159#[repr(C)]
160pub struct JsonPathIter {
161    query: String,
162    json_path: Box<JsonPath<'static>>,
163    inner: NativeJsonPathIter<'static, Transaction>,
164}
165
166enum TransactionInner {
167    ReadOnly(yrs::Transaction<'static>),
168    ReadWrite(yrs::TransactionMut<'static>),
169}
170
171impl Transaction {
172    fn read_only(txn: yrs::Transaction) -> Self {
173        Transaction(TransactionInner::ReadOnly(unsafe {
174            std::mem::transmute(txn)
175        }))
176    }
177
178    fn read_write(txn: yrs::TransactionMut) -> Self {
179        Transaction(TransactionInner::ReadWrite(unsafe {
180            std::mem::transmute(txn)
181        }))
182    }
183
184    fn is_writeable(&self) -> bool {
185        match &self.0 {
186            TransactionInner::ReadOnly(_) => false,
187            TransactionInner::ReadWrite(_) => true,
188        }
189    }
190
191    fn as_mut(&mut self) -> Option<&mut yrs::TransactionMut<'static>> {
192        match &mut self.0 {
193            TransactionInner::ReadOnly(_) => None,
194            TransactionInner::ReadWrite(txn) => Some(txn),
195        }
196    }
197}
198
199impl ReadTxn for Transaction {
200    fn store(&self) -> &Store {
201        match &self.0 {
202            TransactionInner::ReadOnly(txn) => txn.store(),
203            TransactionInner::ReadWrite(txn) => txn.store(),
204        }
205    }
206}
207
208/// A structure representing single key-value entry of a map output (used by either
209/// embedded JSON-like maps or YMaps).
210#[repr(C)]
211pub struct YMapEntry {
212    /// Null-terminated string representing an entry's key component. Encoded as UTF-8.
213    pub key: *const c_char,
214    /// A `YOutput` value representing containing variadic content that can be stored withing map's
215    /// entry.
216    pub value: *const YOutput,
217}
218
219impl YMapEntry {
220    fn new(key: &str, value: Box<YOutput>) -> Self {
221        let key = CString::new(key).unwrap().into_raw();
222        let value = Box::into_raw(value) as *const YOutput;
223        YMapEntry { key, value }
224    }
225}
226
227impl Drop for YMapEntry {
228    fn drop(&mut self) {
229        unsafe {
230            drop(CString::from_raw(self.key as *mut c_char));
231            drop(Box::from_raw(self.value as *mut YOutput));
232        }
233    }
234}
235
236/// A structure representing single attribute of an either `YXmlElement` or `YXmlText` instance.
237/// It consists of attribute name and string, both of which are null-terminated UTF-8 strings.
238#[repr(C)]
239pub struct YXmlAttr {
240    pub name: *const c_char,
241    pub value: *const YOutput,
242}
243
244impl Drop for YXmlAttr {
245    fn drop(&mut self) {
246        unsafe {
247            drop(CString::from_raw(self.name as *mut _));
248            if (!self.value.is_null()) {
249                drop(Box::from_raw(self.value as *mut YOutput));
250            }
251        }
252    }
253}
254
255/// Configuration object used by `YDoc`.
256#[repr(C)]
257pub struct YOptions {
258    /// Globally unique 53-bit integer assigned to corresponding document replica as its identifier.
259    ///
260    /// If two clients share the same `id` and will perform any updates, it will result in
261    /// unrecoverable document state corruption. The same thing may happen if the client restored
262    /// document state from snapshot, that didn't contain all of that clients updates that were sent
263    /// to other peers.
264    pub id: u64,
265
266    /// A NULL-able globally unique Uuid v4 compatible null-terminated string identifier
267    /// of this document. If passed as NULL, a random Uuid will be generated instead.
268    pub guid: *const c_char,
269
270    /// A NULL-able, UTF-8 encoded, null-terminated string of a collection that this document
271    /// belongs to. It's used only by providers.
272    pub collection_id: *const c_char,
273
274    /// Boolean flags used to configure document options:
275    /// - `Y_OFFSET_BYTES`: use UTF-8 byte length for text indexes and offsets.
276    /// - `Y_OFFSET_UTF16`: use UTF-16 code points for text indexes and offsets.
277    /// - `Y_SKIP_GC`: skip automatic garbage collection at transaction commit (useful for snapshots and keeping historical traces).
278    /// - `Y_AUTO_LOAD`: all subdocuments should be loaded automatically.
279    /// - `Y_SHOULD_LOAD`: should current document be synced with its provider immediatelly?
280    /// - `Y_CLEANUP_TEXT_FMT`: automatically remove dangling formatting attributes.
281    pub flags: u8,
282}
283
284/// Flag used by `YOptions` to determine, that text operations offsets and length will be counted by
285/// the byte number of UTF8-encoded string.
286pub const Y_OFFSET_BYTES: u8 = 0;
287
288/// Flag used by `YOptions` to determine, that text operations offsets and length will be counted by
289/// UTF-16 chars of encoded string.
290pub const Y_OFFSET_UTF16: u8 = 1;
291
292/// Boolean flag used to determine if deleted blocks should be garbage collected or not
293/// during the transaction commits. Setting this value to 0 means GC will be performed.
294pub const Y_SKIP_GC: u8 = 1 << 1;
295
296/// Boolean flag used to determine if subdocument should be loaded automatically.
297/// If this is a subdocument, remote peers will load the document as well automatically.
298pub const Y_AUTO_LOAD: u8 = 1 << 2;
299
300/// Boolean flag used to determine whether the document should be synced by the provider now.
301pub const Y_SHOULD_LOAD: u8 = 1 << 3;
302
303/// Whenever we receive an update that might remove piece of text, it might turn out that it was
304/// surrounded by the formatting attributes, that now are effectively dead and unrenderable, but
305/// still are considered alive blocks.
306///
307/// This flag orders cleanup of dangling formatting attributes.
308pub const Y_CLEANUP_FMT: u8 = 1 << 4;
309
310impl Into<Options> for YOptions {
311    fn into(self) -> Options {
312        let mut offset_kind = OffsetKind::Bytes;
313        if self.flags & Y_OFFSET_UTF16 != 0 {
314            offset_kind = OffsetKind::Utf16;
315        }
316        let skip_gc = self.flags & Y_SKIP_GC != 0;
317        let auto_load = self.flags & Y_AUTO_LOAD != 0;
318        let should_load = self.flags & Y_SHOULD_LOAD != 0;
319        let cleanup_formatting = self.flags & Y_CLEANUP_FMT != 0;
320        let guid = if self.guid.is_null() {
321            uuid_v4()
322        } else {
323            let c_str = unsafe { CStr::from_ptr(self.guid) };
324            let str = c_str.to_str().unwrap();
325            str.into()
326        };
327        let collection_id = if self.collection_id.is_null() {
328            None
329        } else {
330            let c_str = unsafe { CStr::from_ptr(self.collection_id) };
331            let str = Arc::from(c_str.to_str().unwrap());
332            Some(str)
333        };
334        Options {
335            client_id: ClientID::new(self.id),
336            guid,
337            collection_id,
338            skip_gc,
339            auto_load,
340            should_load,
341            offset_kind,
342            cleanup_formatting,
343        }
344    }
345}
346
347impl From<Options> for YOptions {
348    fn from(o: Options) -> Self {
349        let mut flags = 0;
350        if o.offset_kind == OffsetKind::Utf16 {
351            flags |= Y_OFFSET_UTF16;
352        }
353        if o.skip_gc {
354            flags |= Y_SKIP_GC;
355        }
356        if o.auto_load {
357            flags |= Y_AUTO_LOAD;
358        }
359        if o.should_load {
360            flags |= Y_SHOULD_LOAD;
361        }
362        if o.cleanup_formatting {
363            flags |= Y_CLEANUP_FMT;
364        }
365
366        YOptions {
367            id: o.client_id.get(),
368            guid: CString::new(o.guid.as_ref()).unwrap().into_raw(),
369            collection_id: if let Some(collection_id) = o.collection_id {
370                CString::new(collection_id.to_string()).unwrap().into_raw()
371            } else {
372                null_mut()
373            },
374            flags,
375        }
376    }
377}
378
379/// Returns default ceonfiguration for `YOptions`.
380#[no_mangle]
381pub unsafe extern "C" fn yoptions() -> YOptions {
382    Options::default().into()
383}
384
385/// Releases all memory-allocated resources bound to given document.
386#[no_mangle]
387pub unsafe extern "C" fn ydoc_destroy(value: *mut Doc) {
388    if !value.is_null() {
389        drop(Box::from_raw(value));
390    }
391}
392
393/// Frees all memory-allocated resources bound to a given [YMapEntry].
394#[no_mangle]
395pub unsafe extern "C" fn ymap_entry_destroy(value: *mut YMapEntry) {
396    if !value.is_null() {
397        drop(Box::from_raw(value));
398    }
399}
400
401/// Frees all memory-allocated resources bound to a given [YXmlAttr].
402#[no_mangle]
403pub unsafe extern "C" fn yxmlattr_destroy(attr: *mut YXmlAttr) {
404    if !attr.is_null() {
405        drop(Box::from_raw(attr));
406    }
407}
408
409/// Frees all memory-allocated resources bound to a given UTF-8 null-terminated string returned from
410/// Yrs document API. Yrs strings don't use libc malloc, so calling `free()` on them will fault.
411#[no_mangle]
412pub unsafe extern "C" fn ystring_destroy(str: *mut c_char) {
413    if !str.is_null() {
414        drop(CString::from_raw(str));
415    }
416}
417
418/// Frees all memory-allocated resources bound to a given binary returned from Yrs document API.
419/// Unlike strings binaries are not null-terminated and can contain null characters inside,
420/// therefore a size of memory to be released must be explicitly provided.
421/// Yrs binaries don't use libc malloc, so calling `free()` on them will fault.
422#[no_mangle]
423pub unsafe extern "C" fn ybinary_destroy(ptr: *mut c_char, len: u32) {
424    if !ptr.is_null() {
425        drop(Vec::from_raw_parts(ptr, len as usize, len as usize));
426    }
427}
428
429/// Creates a new [Doc] instance with a randomized unique client identifier.
430///
431/// Use [ydoc_destroy] in order to release created [Doc] resources.
432#[no_mangle]
433pub extern "C" fn ydoc_new() -> *mut Doc {
434    Box::into_raw(Box::new(Doc::new()))
435}
436
437/// Creates a shallow clone of a provided `doc` - it's realized by increasing the ref-count
438/// value of the document. In result both input and output documents point to the same instance.
439///
440/// Documents created this way can be destroyed via [ydoc_destroy] - keep in mind, that the memory
441/// will still be persisted until all strong references are dropped.
442#[no_mangle]
443pub unsafe extern "C" fn ydoc_clone(doc: *mut Doc) -> *mut Doc {
444    let doc = doc.as_mut().unwrap();
445    Box::into_raw(Box::new(doc.clone()))
446}
447
448/// Creates a new [Doc] instance with a specified `options`.
449///
450/// Use [ydoc_destroy] in order to release created [Doc] resources.
451#[no_mangle]
452pub extern "C" fn ydoc_new_with_options(options: YOptions) -> *mut Doc {
453    Box::into_raw(Box::new(Doc::with_options(options.into())))
454}
455
456/// Returns a unique client identifier of this [Doc] instance.
457#[no_mangle]
458pub unsafe extern "C" fn ydoc_id(doc: *mut Doc) -> u64 {
459    let doc = doc.as_ref().unwrap();
460    doc.client_id().get()
461}
462
463/// Returns a unique document identifier of this [Doc] instance.
464///
465/// Generated string resources should be released using [ystring_destroy] function.
466#[no_mangle]
467pub unsafe extern "C" fn ydoc_guid(doc: *mut Doc) -> *mut c_char {
468    let doc = doc.as_ref().unwrap();
469    let uid = doc.guid();
470    CString::new(uid.as_ref()).unwrap().into_raw()
471}
472
473/// Returns a collection identifier of this [Doc] instance.
474/// If none was defined, a `NULL` will be returned.
475///
476/// Generated string resources should be released using [ystring_destroy] function.
477#[no_mangle]
478pub unsafe extern "C" fn ydoc_collection_id(doc: *mut Doc) -> *mut c_char {
479    let doc = doc.as_ref().unwrap();
480    if let Some(cid) = doc.collection_id() {
481        CString::new(cid.as_ref()).unwrap().into_raw()
482    } else {
483        null_mut()
484    }
485}
486
487/// Returns status of should_load flag of this [Doc] instance, informing parent [Doc] if this
488/// document instance requested a data load.
489#[no_mangle]
490pub unsafe extern "C" fn ydoc_should_load(doc: *mut Doc) -> u8 {
491    let doc = doc.as_ref().unwrap();
492    doc.should_load() as u8
493}
494
495/// Returns status of auto_load flag of this [Doc] instance. Auto loaded sub-documents automatically
496/// send a load request to their parent documents.
497#[no_mangle]
498pub unsafe extern "C" fn ydoc_auto_load(doc: *mut Doc) -> u8 {
499    let doc = doc.as_ref().unwrap();
500    doc.auto_load() as u8
501}
502
503#[repr(transparent)]
504struct CallbackState(*mut c_void);
505
506unsafe impl Send for CallbackState {}
507unsafe impl Sync for CallbackState {}
508
509impl CallbackState {
510    #[inline]
511    fn new(state: *mut c_void) -> Self {
512        CallbackState(state)
513    }
514}
515
516#[no_mangle]
517pub unsafe extern "C" fn ydoc_observe_updates_v1(
518    doc: *mut Doc,
519    state: *mut c_void,
520    cb: extern "C" fn(*mut c_void, u32, *const c_char),
521) -> *mut Subscription {
522    let state = CallbackState::new(state);
523    let doc = doc.as_ref().unwrap();
524    let subscription = doc
525        .observe_update_v1(move |_, e| {
526            let bytes = &e.update;
527            let len = bytes.len() as u32;
528            cb(state.0, len, bytes.as_ptr() as *const c_char)
529        })
530        .unwrap();
531    Box::into_raw(Box::new(subscription))
532}
533
534#[no_mangle]
535pub unsafe extern "C" fn ydoc_observe_updates_v2(
536    doc: *mut Doc,
537    state: *mut c_void,
538    cb: extern "C" fn(*mut c_void, u32, *const c_char),
539) -> *mut Subscription {
540    let state = CallbackState::new(state);
541    let doc = doc.as_ref().unwrap();
542    let subscription = doc
543        .observe_update_v2(move |_, e| {
544            let bytes = &e.update;
545            let len = bytes.len() as u32;
546            cb(state.0, len, bytes.as_ptr() as *const c_char)
547        })
548        .unwrap();
549    Box::into_raw(Box::new(subscription))
550}
551
552#[no_mangle]
553pub unsafe extern "C" fn ydoc_observe_after_transaction(
554    doc: *mut Doc,
555    state: *mut c_void,
556    cb: extern "C" fn(*mut c_void, *mut YAfterTransactionEvent),
557) -> *mut Subscription {
558    let state = CallbackState::new(state);
559    let doc = doc.as_ref().unwrap();
560    let subscription = doc
561        .observe_transaction_cleanup(move |_, e| {
562            let mut event = YAfterTransactionEvent::new(e);
563            cb(state.0, (&mut event) as *mut _);
564        })
565        .unwrap();
566    Box::into_raw(Box::new(subscription))
567}
568
569#[no_mangle]
570pub unsafe extern "C" fn ydoc_observe_subdocs(
571    doc: *mut Doc,
572    state: *mut c_void,
573    cb: extern "C" fn(*mut c_void, *mut YSubdocsEvent),
574) -> *mut Subscription {
575    let state = CallbackState::new(state);
576    let doc = doc.as_mut().unwrap();
577    let subscription = doc
578        .observe_subdocs(move |_, e| {
579            let mut event = YSubdocsEvent::new(e);
580            cb(state.0, (&mut event) as *mut _);
581        })
582        .unwrap();
583    Box::into_raw(Box::new(subscription))
584}
585
586#[no_mangle]
587pub unsafe extern "C" fn ydoc_observe_clear(
588    doc: *mut Doc,
589    state: *mut c_void,
590    cb: extern "C" fn(*mut c_void, *mut Doc),
591) -> *mut Subscription {
592    let state = CallbackState::new(state);
593    let doc = doc.as_mut().unwrap();
594    let subscription = doc
595        .observe_destroy(move |_, e| cb(state.0, e as *const Doc as *mut _))
596        .unwrap();
597    Box::into_raw(Box::new(subscription))
598}
599
600/// Manually send a load request to a parent document of this subdoc.
601#[no_mangle]
602pub unsafe extern "C" fn ydoc_load(doc: *mut Doc, parent_txn: *mut Transaction) {
603    let doc = doc.as_ref().unwrap();
604    let txn = parent_txn.as_mut().unwrap();
605    if let Some(txn) = txn.as_mut() {
606        doc.load(txn)
607    } else {
608        panic!("ydoc_load: passed read-only parent transaction, where read-write one was expected")
609    }
610}
611
612/// Destroys current document, sending a 'destroy' event and clearing up all the event callbacks
613/// registered.
614#[no_mangle]
615pub unsafe extern "C" fn ydoc_clear(doc: *mut Doc, parent_txn: *mut Transaction) {
616    let doc = doc.as_mut().unwrap();
617    let txn = parent_txn.as_mut();
618    let txn = txn.and_then(|tx| tx.as_mut());
619    doc.destroy(txn);
620}
621
622/// Starts a new read-only transaction on a given document. All other operations happen in context
623/// of a transaction. Yrs transactions do not follow ACID rules. Once a set of operations is
624/// complete, a transaction can be finished using `ytransaction_commit` function.
625///
626/// Returns `NULL` if read-only transaction couldn't be created, i.e. when another read-write
627/// transaction is already opened.
628#[no_mangle]
629pub unsafe extern "C" fn ydoc_read_transaction(doc: *mut Doc) -> *mut Transaction {
630    assert!(!doc.is_null());
631
632    let doc = doc.as_mut().unwrap();
633    if let Ok(txn) = doc.try_transact() {
634        Box::into_raw(Box::new(Transaction::read_only(txn)))
635    } else {
636        null_mut()
637    }
638}
639
640/// Starts a new read-write transaction on a given document. All other operations happen in context
641/// of a transaction. Yrs transactions do not follow ACID rules. Once a set of operations is
642/// complete, a transaction can be finished using `ytransaction_commit` function.
643///
644/// `origin_len` and `origin` are optional parameters to specify a byte sequence used to mark
645/// the origin of this transaction (eg. you may decide to give different origins for transaction
646/// applying remote updates). These can be used by event handlers or `YUndoManager` to perform
647/// specific actions. If origin should not be set, call `ydoc_write_transaction(doc, 0, NULL)`.
648///
649/// Returns `NULL` if read-write transaction couldn't be created, i.e. when another transaction is
650/// already opened.
651#[no_mangle]
652pub unsafe extern "C" fn ydoc_write_transaction(
653    doc: *mut Doc,
654    origin_len: u32,
655    origin: *const c_char,
656) -> *mut Transaction {
657    assert!(!doc.is_null());
658
659    let doc = doc.as_mut().unwrap();
660    if origin_len == 0 {
661        if let Ok(txn) = doc.try_transact_mut() {
662            Box::into_raw(Box::new(Transaction::read_write(txn)))
663        } else {
664            null_mut()
665        }
666    } else {
667        let origin = std::slice::from_raw_parts(origin as *const u8, origin_len as usize);
668        if let Ok(txn) = doc.try_transact_mut_with(origin) {
669            Box::into_raw(Box::new(Transaction::read_write(txn)))
670        } else {
671            null_mut()
672        }
673    }
674}
675
676/// Returns a list of subdocs existing within current document.
677#[no_mangle]
678pub unsafe extern "C" fn ytransaction_subdocs(
679    txn: *mut Transaction,
680    len: *mut u32,
681) -> *mut *mut Doc {
682    let txn = txn.as_ref().unwrap();
683    let subdocs: Vec<_> = txn
684        .subdocs()
685        .map(|doc| doc as *const Doc as *mut Doc)
686        .collect();
687    let out = subdocs.into_boxed_slice();
688    *len = out.len() as u32;
689    Box::into_raw(out) as *mut _
690}
691
692/// Commit and dispose provided read-write transaction. This operation releases allocated resources,
693/// triggers update events and performs a storage compression over all operations executed in scope
694/// of a current transaction.
695#[no_mangle]
696pub unsafe extern "C" fn ytransaction_commit(txn: *mut Transaction) {
697    assert!(!txn.is_null());
698    drop(Box::from_raw(txn)); // transaction is auto-committed when dropped
699}
700
701/// Perform garbage collection of deleted blocks, even if a document was created with `skip_gc`
702/// option. This operation will scan over ALL deleted elements, NOT ONLY the ones that have been
703/// changed as part of this transaction scope.
704#[no_mangle]
705pub unsafe extern "C" fn ytransaction_force_gc(txn: *mut Transaction) {
706    assert!(!txn.is_null());
707    let txn = txn.as_mut().unwrap();
708    let txn = txn.as_mut().unwrap();
709    txn.gc(None);
710}
711
712/// Returns `1` if current transaction is of read-write type.
713/// Returns `0` if transaction is read-only.
714#[no_mangle]
715pub unsafe extern "C" fn ytransaction_writeable(txn: *mut Transaction) -> u8 {
716    assert!(!txn.is_null());
717    if txn.as_ref().unwrap().is_writeable() {
718        1
719    } else {
720        0
721    }
722}
723
724/// Evaluates a JSON path expression (see: https://en.wikipedia.org/wiki/JSONPath) on
725/// the transaction's document and returns an iterator over values matching that query.
726///
727/// Currently, this method supports the following syntax:
728/// - `$` - root object
729/// - `@` - current object
730/// - `.field` or `['field']` - member accessor
731/// - `[1]` - array index (also supports negative indices)
732/// - `.*` or `[*]` - wildcard (matches all members of an object or array)
733/// - `..` - recursive descent (matches all descendants not only direct children)
734/// - `[start:end:step]` - array slice operator (requires positive integer arguments)
735/// - `['a', 'b', 'c']` - union operator (returns an array of values for each query)
736/// - `[1, -1, 3]` - multiple indices operator (returns an array of values for each index)
737///
738/// At the moment, JSON Path does not support filter predicates.
739///
740/// Returns `NULL` if the json_path expression is invalid and couldn't be parsed.
741///
742/// Use ``yjson_path_iter_next` function in order to retrieve a consecutive array elements.
743/// Use ``yjson_path_iter_destroy` function in order to close the iterator and release its resources.
744#[no_mangle]
745pub unsafe extern "C" fn ytransaction_json_path(
746    txn: *mut Transaction,
747    json_path: *const c_char,
748) -> *mut JsonPathIter {
749    assert!(!txn.is_null());
750    let txn = txn.as_ref().unwrap();
751
752    // copy JSONPath string to have its ownership
753    let query: String = CStr::from_ptr(json_path).to_str().unwrap().into();
754    // since string is not reallocated/deallocated, we can safely pass it to the parser
755    let json_path: &'static str = unsafe { std::mem::transmute(query.as_str()) };
756    let json_path = match JsonPath::parse(json_path) {
757        Ok(query) => Box::new(query),
758        Err(_) => return null_mut(),
759    };
760    // again, we wraped parsed JSONPath in a Box to ensure that it's owned and not moving
761    let json_path_ref: &'static JsonPath = unsafe { std::mem::transmute(json_path.as_ref()) };
762    let inner = txn.json_path(json_path_ref);
763    let iter = Box::new(JsonPathIter {
764        query,
765        json_path,
766        inner,
767    });
768    Box::into_raw(iter)
769}
770
771/// Returns the next element of a JSON path iterator. If there are no more elements, `NULL` is returned.
772#[no_mangle]
773pub unsafe extern "C" fn yjson_path_iter_next(iter: *mut JsonPathIter) -> *mut YOutput {
774    assert!(!iter.is_null());
775    let iter = iter.as_mut().unwrap();
776    if let Some(value) = iter.inner.next() {
777        let youtput = YOutput::from(value);
778        Box::into_raw(Box::new(youtput))
779    } else {
780        null_mut()
781    }
782}
783
784/// Closes the JSON path iterator created via `ytransaction_json_path` and releases its resources.
785#[no_mangle]
786pub unsafe extern "C" fn yjson_path_iter_destroy(iter: *mut JsonPathIter) {
787    if !iter.is_null() {
788        drop(Box::from_raw(iter));
789    }
790}
791
792/// Gets a reference to shared data type instance at the document root-level,
793/// identified by its `name`, which must be a null-terminated UTF-8 compatible string.
794///
795/// Returns `NULL` if no such structure was defined in the document before.
796// TODO [LSViana] Rename this to `ytransaction_get_ytype()` (or similar) to match the signature.
797#[no_mangle]
798pub unsafe extern "C" fn ytype_get(txn: *mut Transaction, name: *const c_char) -> *mut Branch {
799    assert!(!txn.is_null());
800    assert!(!name.is_null());
801
802    let name = CStr::from_ptr(name).to_str().unwrap();
803    //NOTE: we're retrieving this as a text, but ultimatelly it doesn't matter as we don't define
804    // nor redefine the underlying branch type
805    if let Some(txt) = txn.as_mut().unwrap().get_text(name) {
806        txt.into_raw_branch()
807    } else {
808        null_mut()
809    }
810}
811
812/// Gets or creates a new shared `YText` data type instance as a root-level type of a given document.
813/// This structure can later be accessed using its `name`, which must be a null-terminated UTF-8
814/// compatible string.
815#[no_mangle]
816pub unsafe extern "C" fn ytext(doc: *mut Doc, name: *const c_char) -> *mut Branch {
817    assert!(!doc.is_null());
818    assert!(!name.is_null());
819
820    let name = CStr::from_ptr(name).to_str().unwrap();
821    let txt = doc.as_mut().unwrap().get_or_insert_text(name);
822    txt.into_raw_branch()
823}
824
825/// Gets or creates a new shared `YArray` data type instance as a root-level type of a given document.
826/// This structure can later be accessed using its `name`, which must be a null-terminated UTF-8
827/// compatible string.
828///
829/// Once created, a `YArray` instance will last for the entire lifecycle of a document.
830#[no_mangle]
831pub unsafe extern "C" fn yarray(doc: *mut Doc, name: *const c_char) -> *mut Branch {
832    assert!(!doc.is_null());
833    assert!(!name.is_null());
834
835    let name = CStr::from_ptr(name).to_str().unwrap();
836    doc.as_mut()
837        .unwrap()
838        .get_or_insert_array(name)
839        .into_raw_branch()
840}
841
842/// Gets or creates a new shared `YMap` data type instance as a root-level type of a given document.
843/// This structure can later be accessed using its `name`, which must be a null-terminated UTF-8
844/// compatible string.
845///
846/// Once created, a `YMap` instance will last for the entire lifecycle of a document.
847#[no_mangle]
848pub unsafe extern "C" fn ymap(doc: *mut Doc, name: *const c_char) -> *mut Branch {
849    assert!(!doc.is_null());
850    assert!(!name.is_null());
851
852    let name = CStr::from_ptr(name).to_str().unwrap();
853    doc.as_mut()
854        .unwrap()
855        .get_or_insert_map(name)
856        .into_raw_branch()
857}
858
859/// Gets or creates a new shared `YXmlElement` data type instance as a root-level type of a given
860/// document. This structure can later be accessed using its `name`, which must be a null-terminated
861/// UTF-8 compatible string.
862#[no_mangle]
863pub unsafe extern "C" fn yxmlfragment(doc: *mut Doc, name: *const c_char) -> *mut Branch {
864    assert!(!doc.is_null());
865    assert!(!name.is_null());
866
867    let name = CStr::from_ptr(name).to_str().unwrap();
868    doc.as_mut()
869        .unwrap()
870        .get_or_insert_xml_fragment(name)
871        .into_raw_branch()
872}
873
874/// Returns a state vector of a current transaction's document, serialized using lib0 version 1
875/// encoding. Payload created by this function can then be send over the network to a remote peer,
876/// where it can be used as a parameter of [ytransaction_state_diff_v1] in order to produce a delta
877/// update payload, that can be send back and applied locally in order to efficiently propagate
878/// updates from one peer to another.
879///
880/// The length of a generated binary will be passed within a `len` out parameter.
881///
882/// Once no longer needed, a returned binary can be disposed using [ybinary_destroy] function.
883#[no_mangle]
884pub unsafe extern "C" fn ytransaction_state_vector_v1(
885    txn: *const Transaction,
886    len: *mut u32,
887) -> *mut c_char {
888    assert!(!txn.is_null());
889
890    let txn = txn.as_ref().unwrap();
891    let state_vector = txn.state_vector();
892    let binary = state_vector.encode_v1().into_boxed_slice();
893
894    *len = binary.len() as u32;
895    Box::into_raw(binary) as *mut c_char
896}
897
898/// Returns a delta difference between current state of a transaction's document and a state vector
899/// `sv` encoded as a binary payload using lib0 version 1 encoding (which could be generated using
900/// [ytransaction_state_vector_v1]). Such delta can be send back to the state vector's sender in
901/// order to propagate and apply (using [ytransaction_apply]) all updates known to a current
902/// document, which remote peer was not aware of.
903///
904/// If passed `sv` pointer is null, the generated diff will be a snapshot containing entire state of
905/// the document.
906///
907/// A length of an encoded state vector payload must be passed as `sv_len` parameter.
908///
909/// A length of generated delta diff binary will be passed within a `len` out parameter.
910///
911/// Once no longer needed, a returned binary can be disposed using [ybinary_destroy] function.
912#[no_mangle]
913pub unsafe extern "C" fn ytransaction_state_diff_v1(
914    txn: *const Transaction,
915    sv: *const c_char,
916    sv_len: u32,
917    len: *mut u32,
918) -> *mut c_char {
919    assert!(!txn.is_null());
920
921    let txn = txn.as_ref().unwrap();
922    let sv = {
923        if sv.is_null() {
924            StateVector::default()
925        } else {
926            let sv_slice = std::slice::from_raw_parts(sv as *const u8, sv_len as usize);
927            if let Ok(sv) = StateVector::decode_v1(sv_slice) {
928                sv
929            } else {
930                return null_mut();
931            }
932        }
933    };
934
935    let mut encoder = EncoderV1::new();
936    txn.encode_diff(&sv, &mut encoder);
937    let binary = encoder.to_vec().into_boxed_slice();
938    *len = binary.len() as u32;
939    Box::into_raw(binary) as *mut c_char
940}
941
942/// Returns a delta difference between current state of a transaction's document and a state vector
943/// `sv` encoded as a binary payload using lib0 version 1 encoding (which could be generated using
944/// [ytransaction_state_vector_v1]). Such delta can be send back to the state vector's sender in
945/// order to propagate and apply (using [ytransaction_apply_v2]) all updates known to a current
946/// document, which remote peer was not aware of.
947///
948/// If passed `sv` pointer is null, the generated diff will be a snapshot containing entire state of
949/// the document.
950///
951/// A length of an encoded state vector payload must be passed as `sv_len` parameter.
952///
953/// A length of generated delta diff binary will be passed within a `len` out parameter.
954///
955/// Once no longer needed, a returned binary can be disposed using [ybinary_destroy] function.
956#[no_mangle]
957pub unsafe extern "C" fn ytransaction_state_diff_v2(
958    txn: *const Transaction,
959    sv: *const c_char,
960    sv_len: u32,
961    len: *mut u32,
962) -> *mut c_char {
963    assert!(!txn.is_null());
964
965    let txn = txn.as_ref().unwrap();
966    let sv = {
967        if sv.is_null() {
968            StateVector::default()
969        } else {
970            let sv_slice = std::slice::from_raw_parts(sv as *const u8, sv_len as usize);
971            if let Ok(sv) = StateVector::decode_v1(sv_slice) {
972                sv
973            } else {
974                return null_mut();
975            }
976        }
977    };
978
979    let mut encoder = EncoderV2::new();
980    txn.encode_diff(&sv, &mut encoder);
981    let binary = encoder.to_vec().into_boxed_slice();
982    *len = binary.len() as u32;
983    Box::into_raw(binary) as *mut c_char
984}
985
986/// Returns a snapshot descriptor of a current state of the document. This snapshot information
987/// can be then used to encode document data at a particular point in time
988/// (see: `ytransaction_encode_state_from_snapshot`).
989#[no_mangle]
990pub unsafe extern "C" fn ytransaction_snapshot(
991    txn: *const Transaction,
992    len: *mut u32,
993) -> *mut c_char {
994    assert!(!txn.is_null());
995    let txn = txn.as_ref().unwrap();
996    let binary = txn.snapshot().encode_v1().into_boxed_slice();
997
998    *len = binary.len() as u32;
999    Box::into_raw(binary) as *mut c_char
1000}
1001
1002/// Encodes a state of the document at a point in time specified by the provided `snapshot`
1003/// (generated by: `ytransaction_snapshot`). This is useful to generate a past view of the document.
1004///
1005/// The returned update is binary compatible with Yrs update lib0 v1 encoding, and can be processed
1006/// with functions dedicated to work on it, like `ytransaction_apply`.
1007///
1008/// This function requires document with a GC option flag turned off (otherwise "time travel" would
1009/// not be a safe operation). If this is not a case, the NULL pointer will be returned.
1010#[no_mangle]
1011pub unsafe extern "C" fn ytransaction_encode_state_from_snapshot_v1(
1012    txn: *const Transaction,
1013    snapshot: *const c_char,
1014    snapshot_len: u32,
1015    len: *mut u32,
1016) -> *mut c_char {
1017    assert!(!txn.is_null());
1018    let txn = txn.as_ref().unwrap();
1019    let snapshot = {
1020        let len = snapshot_len as usize;
1021        let data = std::slice::from_raw_parts(snapshot as *mut u8, len);
1022        Snapshot::decode_v1(&data).unwrap()
1023    };
1024    let mut encoder = EncoderV1::new();
1025    match txn.encode_state_from_snapshot(&snapshot, &mut encoder) {
1026        Err(_) => null_mut(),
1027        Ok(_) => {
1028            let binary = encoder.to_vec().into_boxed_slice();
1029            *len = binary.len() as u32;
1030            Box::into_raw(binary) as *mut c_char
1031        }
1032    }
1033}
1034
1035/// Encodes a state of the document at a point in time specified by the provided `snapshot`
1036/// (generated by: `ytransaction_snapshot`). This is useful to generate a past view of the document.
1037///
1038/// The returned update is binary compatible with Yrs update lib0 v2 encoding, and can be processed
1039/// with functions dedicated to work on it, like `ytransaction_apply_v2`.
1040///
1041/// This function requires document with a GC option flag turned off (otherwise "time travel" would
1042/// not be a safe operation). If this is not a case, the NULL pointer will be returned.
1043#[no_mangle]
1044pub unsafe extern "C" fn ytransaction_encode_state_from_snapshot_v2(
1045    txn: *const Transaction,
1046    snapshot: *const c_char,
1047    snapshot_len: u32,
1048    len: *mut u32,
1049) -> *mut c_char {
1050    assert!(!txn.is_null());
1051    let txn = txn.as_ref().unwrap();
1052    let snapshot = {
1053        let len = snapshot_len as usize;
1054        let data = std::slice::from_raw_parts(snapshot as *mut u8, len);
1055        Snapshot::decode_v1(&data).unwrap()
1056    };
1057    let mut encoder = EncoderV2::new();
1058    match txn.encode_state_from_snapshot(&snapshot, &mut encoder) {
1059        Err(_) => null_mut(),
1060        Ok(_) => {
1061            let binary = encoder.to_vec().into_boxed_slice();
1062            *len = binary.len() as u32;
1063            Box::into_raw(binary) as *mut c_char
1064        }
1065    }
1066}
1067
1068/// Returns an unapplied Delete Set for the current document, waiting for missing updates in order
1069/// to be integrated into document store.
1070///
1071/// Return `NULL` if there's no missing delete set and all deletions have been applied.
1072/// See also: `ytransaction_pending_update`
1073#[no_mangle]
1074pub unsafe extern "C" fn ytransaction_pending_ds(txn: *const Transaction) -> *mut YIdSet {
1075    let txn = txn.as_ref().unwrap();
1076    match txn.store().pending_ds() {
1077        None => null_mut(),
1078        Some(ds) => Box::into_raw(Box::new(YIdSet::new(ds))),
1079    }
1080}
1081
1082#[no_mangle]
1083pub unsafe extern "C" fn ydelete_set_destroy(ds: *mut YIdSet) {
1084    if ds.is_null() {
1085        return;
1086    }
1087    drop(Box::from_raw(ds))
1088}
1089
1090/// Returns a pending update associated with an underlying `YDoc`. Pending update contains update
1091/// data waiting for being integrated into main document store. Usually reason for that is that
1092/// there were missing updates required for integration. In such cases they need to arrive and be
1093/// integrated first.
1094///
1095/// Returns `NULL` if there is not update pending. Returned value can be released by calling
1096/// `ypending_update_destroy`.
1097/// See also: `ytransaction_pending_ds`
1098#[no_mangle]
1099pub unsafe extern "C" fn ytransaction_pending_update(
1100    txn: *const Transaction,
1101) -> *mut YPendingUpdate {
1102    let txn = txn.as_ref().unwrap();
1103    match txn.store().pending_update() {
1104        None => null_mut(),
1105        Some(u) => {
1106            let binary = u.update.encode_v1().into_boxed_slice();
1107            let update_len = binary.len() as u32;
1108            let missing = YStateVector::new(&u.missing);
1109            let update = YPendingUpdate {
1110                missing,
1111                update_len,
1112                update_v1: Box::into_raw(binary) as *mut c_char,
1113            };
1114            Box::into_raw(Box::new(update))
1115        }
1116    }
1117}
1118
1119/// Structure containing unapplied update data.
1120/// Created via `ytransaction_pending_update`.
1121/// Released via `ypending_update_destroy`.
1122#[repr(C)]
1123pub struct YPendingUpdate {
1124    /// A state vector that informs about minimal client clock values that need to be satisfied
1125    /// in order to successfully apply current update.
1126    pub missing: YStateVector,
1127    /// Update data stored in lib0 v1 format.
1128    pub update_v1: *mut c_char,
1129    /// Length of `update_v1` payload.
1130    pub update_len: u32,
1131}
1132
1133#[no_mangle]
1134pub unsafe extern "C" fn ypending_update_destroy(update: *mut YPendingUpdate) {
1135    if update.is_null() {
1136        return;
1137    }
1138    let update = Box::from_raw(update);
1139    drop(update.missing);
1140    ybinary_destroy(update.update_v1, update.update_len);
1141}
1142
1143/// Returns a null-terminated UTF-8 encoded string representation of an `update` binary payload,
1144/// encoded using lib0 v1 encoding.
1145/// Returns null if update couldn't be parsed into a lib0 v1 formatting.
1146#[no_mangle]
1147pub unsafe extern "C" fn yupdate_debug_v1(update: *const c_char, update_len: u32) -> *mut c_char {
1148    assert!(!update.is_null());
1149
1150    let data = std::slice::from_raw_parts(update as *const u8, update_len as usize);
1151    if let Ok(u) = Update::decode_v1(data) {
1152        let str = format!("{:#?}", u);
1153        CString::new(str).unwrap().into_raw()
1154    } else {
1155        null_mut()
1156    }
1157}
1158
1159/// Returns a null-terminated UTF-8 encoded string representation of an `update` binary payload,
1160/// encoded using lib0 v2 encoding.
1161/// Returns null if update couldn't be parsed into a lib0 v2 formatting.
1162#[no_mangle]
1163pub unsafe extern "C" fn yupdate_debug_v2(update: *const c_char, update_len: u32) -> *mut c_char {
1164    assert!(!update.is_null());
1165
1166    let data = std::slice::from_raw_parts(update as *const u8, update_len as usize);
1167    if let Ok(u) = Update::decode_v2(data) {
1168        let str = format!("{:#?}", u);
1169        CString::new(str).unwrap().into_raw()
1170    } else {
1171        null_mut()
1172    }
1173}
1174
1175/// Applies an diff update (generated by `ytransaction_state_diff_v1`) to a local transaction's
1176/// document.
1177///
1178/// A length of generated `diff` binary must be passed within a `diff_len` out parameter.
1179///
1180/// Returns an error code in case if transaction succeeded failed:
1181/// - **0**: success
1182/// - `ERR_CODE_IO` (**1**): couldn't read data from input stream.
1183/// - `ERR_CODE_VAR_INT` (**2**): decoded variable integer outside of the expected integer size bounds.
1184/// - `ERR_CODE_EOS` (**3**): end of stream found when more data was expected.
1185/// - `ERR_CODE_UNEXPECTED_VALUE` (**4**): decoded enum tag value was not among known cases.
1186/// - `ERR_CODE_INVALID_JSON` (**5**): failure when trying to decode JSON content.
1187/// - `ERR_CODE_OTHER` (**6**): other error type than the one specified.
1188#[no_mangle]
1189pub unsafe extern "C" fn ytransaction_apply(
1190    txn: *mut Transaction,
1191    diff: *const c_char,
1192    diff_len: u32,
1193) -> u8 {
1194    assert!(!txn.is_null());
1195    assert!(!diff.is_null());
1196
1197    let update = std::slice::from_raw_parts(diff as *const u8, diff_len as usize);
1198    let mut decoder = DecoderV1::from(update);
1199    match Update::decode(&mut decoder) {
1200        Ok(update) => {
1201            let txn = txn.as_mut().unwrap();
1202            let txn = txn
1203                .as_mut()
1204                .expect("provided transaction was not writeable");
1205            match txn.apply_update(update) {
1206                Ok(_) => 0,
1207                Err(e) => update_err_code(e),
1208            }
1209        }
1210        Err(e) => err_code(e),
1211    }
1212}
1213
1214/// Applies an diff update (generated by [ytransaction_state_diff_v2]) to a local transaction's
1215/// document.
1216///
1217/// A length of generated `diff` binary must be passed within a `diff_len` out parameter.
1218///
1219/// Returns an error code in case if transaction succeeded failed:
1220/// - **0**: success
1221/// - `ERR_CODE_IO` (**1**): couldn't read data from input stream.
1222/// - `ERR_CODE_VAR_INT` (**2**): decoded variable integer outside of the expected integer size bounds.
1223/// - `ERR_CODE_EOS` (**3**): end of stream found when more data was expected.
1224/// - `ERR_CODE_UNEXPECTED_VALUE` (**4**): decoded enum tag value was not among known cases.
1225/// - `ERR_CODE_INVALID_JSON` (**5**): failure when trying to decode JSON content.
1226/// - `ERR_CODE_OTHER` (**6**): other error type than the one specified.
1227#[no_mangle]
1228pub unsafe extern "C" fn ytransaction_apply_v2(
1229    txn: *mut Transaction,
1230    diff: *const c_char,
1231    diff_len: u32,
1232) -> u8 {
1233    assert!(!txn.is_null());
1234    assert!(!diff.is_null());
1235
1236    let mut update = std::slice::from_raw_parts(diff as *const u8, diff_len as usize);
1237    match Update::decode_v2(&mut update) {
1238        Ok(update) => {
1239            let txn = txn.as_mut().unwrap();
1240            let txn = txn
1241                .as_mut()
1242                .expect("provided transaction was not writeable");
1243            match txn.apply_update(update) {
1244                Ok(_) => 0,
1245                Err(e) => update_err_code(e),
1246            }
1247        }
1248        Err(e) => err_code(e),
1249    }
1250}
1251
1252/// Error code: couldn't read data from input stream.
1253pub const ERR_CODE_IO: u8 = 1;
1254
1255/// Error code: decoded variable integer outside of the expected integer size bounds.
1256pub const ERR_CODE_VAR_INT: u8 = 2;
1257
1258/// Error code: end of stream found when more data was expected.
1259pub const ERR_CODE_EOS: u8 = 3;
1260
1261/// Error code: decoded enum tag value was not among known cases.
1262pub const ERR_CODE_UNEXPECTED_VALUE: u8 = 4;
1263
1264/// Error code: failure when trying to decode JSON content.
1265pub const ERR_CODE_INVALID_JSON: u8 = 5;
1266
1267/// Error code: other error type than the one specified.
1268pub const ERR_CODE_OTHER: u8 = 6;
1269
1270/// Error code: not enough memory to perform an operation.
1271pub const ERR_NOT_ENOUGH_MEMORY: u8 = 7;
1272
1273/// Error code: conversion attempt to specific Rust type was not possible.
1274pub const ERR_TYPE_MISMATCH: u8 = 8;
1275
1276/// Error code: miscellaneous error coming from serde, not covered by other error codes.
1277pub const ERR_CUSTOM: u8 = 9;
1278
1279/// Error code: update block assigned to parent that is not a valid shared ref of deleted block.
1280pub const ERR_INVALID_PARENT: u8 = 9;
1281
1282fn err_code(e: Error) -> u8 {
1283    match e {
1284        Error::InvalidVarInt => ERR_CODE_VAR_INT,
1285        Error::EndOfBuffer(_) => ERR_CODE_EOS,
1286        Error::UnexpectedValue => ERR_CODE_UNEXPECTED_VALUE,
1287        Error::InvalidJSON(_) => ERR_CODE_INVALID_JSON,
1288        Error::NotEnoughMemory(_) => ERR_NOT_ENOUGH_MEMORY,
1289        Error::TypeMismatch(_) => ERR_TYPE_MISMATCH,
1290        Error::Custom(_) => ERR_CUSTOM,
1291    }
1292}
1293fn update_err_code(e: UpdateError) -> u8 {
1294    match e {
1295        UpdateError::InvalidParent(_, _) => ERR_INVALID_PARENT,
1296    }
1297}
1298
1299/// Returns the length of the `YText` string content in bytes (without the null terminator character)
1300#[no_mangle]
1301pub unsafe extern "C" fn ytext_len(txt: *const Branch, txn: *const Transaction) -> u32 {
1302    assert!(!txt.is_null());
1303    let txn = txn.as_ref().unwrap();
1304    let txt = TextRef::from_raw_branch(txt);
1305    txt.len(txn)
1306}
1307
1308/// Returns a null-terminated UTF-8 encoded string content of a current `YText` shared data type.
1309///
1310/// Generated string resources should be released using [ystring_destroy] function.
1311#[no_mangle]
1312pub unsafe extern "C" fn ytext_string(txt: *const Branch, txn: *const Transaction) -> *mut c_char {
1313    assert!(!txt.is_null());
1314
1315    let txn = txn.as_ref().unwrap();
1316    let txt = TextRef::from_raw_branch(txt);
1317    let str = txt.get_string(txn);
1318    CString::new(str).unwrap().into_raw()
1319}
1320
1321/// Inserts a null-terminated UTF-8 encoded string a given `index`. `index` value must be between
1322/// 0 and a length of a `YText` (inclusive, accordingly to [ytext_len] return value), otherwise this
1323/// function will panic.
1324///
1325/// A `str` parameter must be a null-terminated UTF-8 encoded string. This function doesn't take
1326/// ownership over a passed value - it will be copied and therefore a string parameter must be
1327/// released by the caller.
1328///
1329/// A nullable pointer with defined `attrs` will be used to wrap provided text with
1330/// a formatting blocks. `attrs` must be a map-like type.
1331#[no_mangle]
1332pub unsafe extern "C" fn ytext_insert(
1333    txt: *const Branch,
1334    txn: *mut Transaction,
1335    index: u32,
1336    value: *const c_char,
1337    attrs: *const YInput,
1338) {
1339    assert!(!txt.is_null());
1340    assert!(!txn.is_null());
1341    assert!(!value.is_null());
1342
1343    let chunk = CStr::from_ptr(value).to_str().unwrap();
1344    let txn = txn.as_mut().unwrap();
1345    let txn = txn
1346        .as_mut()
1347        .expect("provided transaction was not writeable");
1348    let txt = TextRef::from_raw_branch(txt);
1349    let index = index as u32;
1350    if attrs.is_null() {
1351        txt.insert(txn, index, chunk)
1352    } else {
1353        if let Some(attrs) = map_attrs(attrs.read().into()) {
1354            txt.insert_with_attributes(txn, index, chunk, attrs)
1355        } else {
1356            panic!("ytext_insert: passed attributes are not of map type")
1357        }
1358    }
1359}
1360
1361/// Wraps an existing piece of text within a range described by `index`-`len` parameters with
1362/// formatting blocks containing provided `attrs` metadata. `attrs` must be a map-like type.
1363#[no_mangle]
1364pub unsafe extern "C" fn ytext_format(
1365    txt: *const Branch,
1366    txn: *mut Transaction,
1367    index: u32,
1368    len: u32,
1369    attrs: *const YInput,
1370) {
1371    assert!(!txt.is_null());
1372    assert!(!txn.is_null());
1373    assert!(!attrs.is_null());
1374
1375    if let Some(attrs) = map_attrs(attrs.read().into()) {
1376        let txt = TextRef::from_raw_branch(txt);
1377        let txn = txn.as_mut().unwrap();
1378        let txn = txn
1379            .as_mut()
1380            .expect("provided transaction was not writeable");
1381        let index = index as u32;
1382        let len = len as u32;
1383        txt.format(txn, index, len, attrs);
1384    } else {
1385        panic!("ytext_format: passed attributes are not of map type")
1386    }
1387}
1388
1389/// Inserts an embed content given `index`. `index` value must be between 0 and a length of a
1390/// `YText` (inclusive, accordingly to [ytext_len] return value), otherwise this
1391/// function will panic.
1392///
1393/// A `str` parameter must be a null-terminated UTF-8 encoded string. This function doesn't take
1394/// ownership over a passed value - it will be copied and therefore a string parameter must be
1395/// released by the caller.
1396///
1397/// A nullable pointer with defined `attrs` will be used to wrap provided text with
1398/// a formatting blocks. `attrs` must be a map-like type.
1399#[no_mangle]
1400pub unsafe extern "C" fn ytext_insert_embed(
1401    txt: *const Branch,
1402    txn: *mut Transaction,
1403    index: u32,
1404    content: *const YInput,
1405    attrs: *const YInput,
1406) {
1407    assert!(!txt.is_null());
1408    assert!(!txn.is_null());
1409    assert!(!content.is_null());
1410
1411    let txn = txn.as_mut().unwrap();
1412    let txn = txn
1413        .as_mut()
1414        .expect("provided transaction was not writeable");
1415    let txt = TextRef::from_raw_branch(txt);
1416    let index = index as u32;
1417    let content = content.read();
1418    if attrs.is_null() {
1419        txt.insert_embed(txn, index, content);
1420    } else {
1421        if let Some(attrs) = map_attrs(attrs.read().into()) {
1422            txt.insert_embed_with_attributes(txn, index, content, attrs);
1423        } else {
1424            panic!("ytext_insert_embed: passed attributes are not of map type")
1425        }
1426    }
1427}
1428
1429/// Performs a series of changes over the given `YText` shared ref type, described by the `delta`
1430/// parameter:
1431///
1432/// - Deltas constructed with `ydelta_input_retain` will move cursor position by the given number
1433///   of elements. If formatting attributes were defined, all elements skipped over this way will be
1434///   wrapped by given formatting attributes.
1435/// - Deltas constructed with `ydelta_input_delete` will tell cursor to remove a corresponding
1436///   number of elements.
1437/// - Deltas constructed with `ydelta_input_insert` will tell cursor to insert given elements into
1438///   current cursor position. While these elements can be of any type (used for embedding ie.
1439///   shared types or binary payload like images), for the text insertion a `yinput_string`
1440///   is expected. If formatting attributes were specified, inserted elements will be wrapped by
1441///   given formatting attributes.
1442#[no_mangle]
1443pub unsafe extern "C" fn ytext_insert_delta(
1444    txt: *const Branch,
1445    txn: *mut Transaction,
1446    delta: *mut YDeltaIn,
1447    delta_len: u32,
1448) {
1449    let txt = TextRef::from_raw_branch(txt);
1450    let txn = txn.as_mut().unwrap();
1451    let txn = txn
1452        .as_mut()
1453        .expect("provided transaction was not writeable");
1454    let delta = std::slice::from_raw_parts(delta, delta_len as usize);
1455    let mut insert = Vec::with_capacity(delta.len());
1456    for chunk in delta {
1457        let d = chunk.as_input();
1458        insert.push(d);
1459    }
1460    txt.apply_delta(txn, insert);
1461}
1462
1463/// Creates a parameter for `ytext_insert_delta` function. This parameter will move cursor position
1464/// by the `len` of elements. If formatting `attrs` were defined, all elements skipped over this
1465/// way will be wrapped by given formatting attributes.
1466#[no_mangle]
1467pub unsafe extern "C" fn ydelta_input_retain(len: u32, attrs: *const YInput) -> YDeltaIn {
1468    YDeltaIn {
1469        tag: Y_EVENT_CHANGE_RETAIN,
1470        len,
1471        attributes: attrs,
1472        insert: null(),
1473    }
1474}
1475
1476/// Creates a parameter for `ytext_insert_delta` function. This parameter will tell cursor to remove
1477/// a corresponding number of elements, starting from current cursor position.
1478#[no_mangle]
1479pub unsafe extern "C" fn ydelta_input_delete(len: u32) -> YDeltaIn {
1480    YDeltaIn {
1481        tag: Y_EVENT_CHANGE_DELETE,
1482        len,
1483        attributes: null(),
1484        insert: null(),
1485    }
1486}
1487
1488/// Creates a parameter for `ytext_insert_delta` function. This parameter will tell cursor to insert
1489/// given elements into current cursor position. While these elements can be of any type (used for
1490/// embedding ie. shared types or binary payload like images), for the text insertion a `yinput_string`
1491/// is expected. If formatting attributes were specified, inserted elements will be wrapped by
1492/// given formatting attributes.
1493#[no_mangle]
1494pub unsafe extern "C" fn ydelta_input_insert(
1495    data: *const YInput,
1496    attrs: *const YInput,
1497) -> YDeltaIn {
1498    YDeltaIn {
1499        tag: Y_EVENT_CHANGE_ADD,
1500        len: 1,
1501        attributes: attrs,
1502        insert: data,
1503    }
1504}
1505
1506fn map_attrs(attrs: Any) -> Option<Attrs> {
1507    if let Any::Map(attrs) = attrs {
1508        let attrs = attrs
1509            .iter()
1510            .map(|(k, v)| (k.as_str().into(), v.clone()))
1511            .collect();
1512        Some(attrs)
1513    } else {
1514        None
1515    }
1516}
1517
1518/// Removes a range of characters, starting a a given `index`. This range must fit within the bounds
1519/// of a current `YText`, otherwise this function call will fail.
1520///
1521/// An `index` value must be between 0 and the length of a `YText` (exclusive, accordingly to
1522/// [ytext_len] return value).
1523///
1524/// A `length` must be lower or equal number of characters (counted as UTF chars depending on the
1525/// encoding configured by `YDoc`) from `index` position to the end of of the string.
1526#[no_mangle]
1527pub unsafe extern "C" fn ytext_remove_range(
1528    txt: *const Branch,
1529    txn: *mut Transaction,
1530    index: u32,
1531    length: u32,
1532) {
1533    assert!(!txt.is_null());
1534    assert!(!txn.is_null());
1535
1536    let txn = txn.as_mut().unwrap();
1537    let txn = txn
1538        .as_mut()
1539        .expect("provided transaction was not writeable");
1540    let txt = TextRef::from_raw_branch(txt);
1541    txt.remove_range(txn, index as u32, length as u32)
1542}
1543
1544/// Returns a number of elements stored within current instance of `YArray`.
1545#[no_mangle]
1546pub unsafe extern "C" fn yarray_len(array: *const Branch) -> u32 {
1547    assert!(!array.is_null());
1548
1549    let array = array.as_ref().unwrap();
1550    array.len() as u32
1551}
1552
1553/// Returns a pointer to a `YOutput` value stored at a given `index` of a current `YArray`.
1554/// If `index` is outside the bounds of an array, a null pointer will be returned.
1555///
1556/// A value returned should be eventually released using [youtput_destroy] function.
1557#[no_mangle]
1558pub unsafe extern "C" fn yarray_get(
1559    array: *const Branch,
1560    txn: *const Transaction,
1561    index: u32,
1562) -> *mut YOutput {
1563    assert!(!array.is_null());
1564
1565    let array = ArrayRef::from_raw_branch(array);
1566    let txn = txn.as_ref().unwrap();
1567
1568    if let Some(val) = array.get(txn, index as u32) {
1569        Box::into_raw(Box::new(YOutput::from(val)))
1570    } else {
1571        std::ptr::null_mut()
1572    }
1573}
1574
1575/// Returns a UTF-8 encoded, NULL-terminated JSON string representing a value stored in a current
1576/// YArray under a given index.
1577///
1578/// This method will return `NULL` pointer if value was outside the bound of an array or couldn't be
1579/// serialized into JSON string.
1580///
1581/// This method will also try to serialize complex types that don't have native JSON representation
1582/// like YMap, YArray, YText etc. in such cases their contents will be materialized into JSON values.
1583///
1584/// A string returned should be eventually released using [ystring_destroy] function.
1585#[no_mangle]
1586pub unsafe extern "C" fn yarray_get_json(
1587    array: *const Branch,
1588    txn: *const Transaction,
1589    index: u32,
1590) -> *mut c_char {
1591    assert!(!array.is_null());
1592
1593    let array = ArrayRef::from_raw_branch(array);
1594    let txn = txn.as_ref().unwrap();
1595
1596    if let Some(val) = array.get(txn, index as u32) {
1597        let any = val.to_json(txn);
1598        let json = match serde_json::to_string(&any) {
1599            Ok(json) => json,
1600            Err(_) => return std::ptr::null_mut(),
1601        };
1602        CString::new(json).unwrap().into_raw()
1603    } else {
1604        std::ptr::null_mut()
1605    }
1606}
1607
1608/// Inserts a range of `items` into current `YArray`, starting at given `index`. An `items_len`
1609/// parameter is used to determine the size of `items` array - it can also be used to insert
1610/// a single element given its pointer.
1611///
1612/// An `index` value must be between 0 and (inclusive) length of a current array (use [yarray_len]
1613/// to determine its length), otherwise it will panic at runtime.
1614///
1615/// `YArray` doesn't take ownership over the inserted `items` data - their contents are being copied
1616/// into array structure - therefore caller is responsible for freeing all memory associated with
1617/// input params.
1618#[no_mangle]
1619pub unsafe extern "C" fn yarray_insert_range(
1620    array: *const Branch,
1621    txn: *mut Transaction,
1622    index: u32,
1623    items: *const YInput,
1624    items_len: u32,
1625) {
1626    assert!(!array.is_null());
1627    assert!(!txn.is_null());
1628    assert!(!items.is_null());
1629
1630    let array = ArrayRef::from_raw_branch(array);
1631    let txn = txn.as_mut().unwrap();
1632    let txn = txn
1633        .as_mut()
1634        .expect("provided transaction was not writeable");
1635
1636    let ptr = items;
1637    let mut i = 0;
1638    let mut j = index as u32;
1639    let len = items_len as isize;
1640    while i < len {
1641        let mut vec: Vec<Any> = Vec::default();
1642
1643        // try read as many values a JSON-like primitives and insert them at once
1644        while i < len {
1645            let val = ptr.offset(i).read();
1646            if val.tag <= 0 {
1647                let any = val.into();
1648                vec.push(any);
1649            } else {
1650                break;
1651            }
1652            i += 1;
1653        }
1654
1655        if !vec.is_empty() {
1656            let len = vec.len() as u32;
1657            array.insert_range(txn, j, vec);
1658            j += len;
1659        } else {
1660            let val = ptr.offset(i).read();
1661            array.insert(txn, j, val);
1662            i += 1;
1663            j += 1;
1664        }
1665    }
1666}
1667
1668/// Removes a `len` of consecutive range of elements from current `array` instance, starting at
1669/// a given `index`. Range determined by `index` and `len` must fit into boundaries of an array,
1670/// otherwise it will panic at runtime.
1671#[no_mangle]
1672pub unsafe extern "C" fn yarray_remove_range(
1673    array: *const Branch,
1674    txn: *mut Transaction,
1675    index: u32,
1676    len: u32,
1677) {
1678    assert!(!array.is_null());
1679    assert!(!txn.is_null());
1680
1681    let array = ArrayRef::from_raw_branch(array);
1682    let txn = txn.as_mut().unwrap();
1683    let txn = txn
1684        .as_mut()
1685        .expect("provided transaction was not writeable");
1686
1687    array.remove_range(txn, index as u32, len as u32)
1688}
1689
1690/// Returns an iterator, which can be used to traverse over all elements of an `array` (`array`'s
1691/// length can be determined using [yarray_len] function).
1692///
1693/// Use [yarray_iter_next] function in order to retrieve a consecutive array elements.
1694/// Use [yarray_iter_destroy] function in order to close the iterator and release its resources.
1695#[no_mangle]
1696pub unsafe extern "C" fn yarray_iter(
1697    array: *const Branch,
1698    txn: *mut Transaction,
1699) -> *mut ArrayIter {
1700    assert!(!array.is_null());
1701    assert!(!txn.is_null());
1702
1703    let txn = txn.as_ref().unwrap();
1704    let array = &ArrayRef::from_raw_branch(array) as *const ArrayRef;
1705    Box::into_raw(Box::new(ArrayIter(array.as_ref().unwrap().iter(txn))))
1706}
1707
1708/// Releases all of an `YArray` iterator resources created by calling [yarray_iter].
1709#[no_mangle]
1710pub unsafe extern "C" fn yarray_iter_destroy(iter: *mut ArrayIter) {
1711    if !iter.is_null() {
1712        drop(Box::from_raw(iter))
1713    }
1714}
1715
1716/// Moves current `YArray` iterator over to a next element, returning a pointer to it. If an iterator
1717/// comes to an end of an array, a null pointer will be returned.
1718///
1719/// Returned values should be eventually released using [youtput_destroy] function.
1720#[no_mangle]
1721pub unsafe extern "C" fn yarray_iter_next(iterator: *mut ArrayIter) -> *mut YOutput {
1722    assert!(!iterator.is_null());
1723
1724    let iter = iterator.as_mut().unwrap();
1725    if let Some(v) = iter.0.next() {
1726        let out = YOutput::from(v);
1727        Box::into_raw(Box::new(out))
1728    } else {
1729        std::ptr::null_mut()
1730    }
1731}
1732
1733/// Returns an iterator, which can be used to traverse over all key-value pairs of a `map`.
1734///
1735/// Use [ymap_iter_next] function in order to retrieve a consecutive (**unordered**) map entries.
1736/// Use [ymap_iter_destroy] function in order to close the iterator and release its resources.
1737#[no_mangle]
1738pub unsafe extern "C" fn ymap_iter(map: *const Branch, txn: *const Transaction) -> *mut MapIter {
1739    assert!(!map.is_null());
1740
1741    let txn = txn.as_ref().unwrap();
1742    let map = &MapRef::from_raw_branch(map) as *const MapRef;
1743    Box::into_raw(Box::new(MapIter(map.as_ref().unwrap().iter(txn))))
1744}
1745
1746/// Releases all of an `YMap` iterator resources created by calling [ymap_iter].
1747#[no_mangle]
1748pub unsafe extern "C" fn ymap_iter_destroy(iter: *mut MapIter) {
1749    if !iter.is_null() {
1750        drop(Box::from_raw(iter))
1751    }
1752}
1753
1754/// Moves current `YMap` iterator over to a next entry, returning a pointer to it. If an iterator
1755/// comes to an end of a map, a null pointer will be returned. Yrs maps are unordered and so are
1756/// their iterators.
1757///
1758/// Returned values should be eventually released using [ymap_entry_destroy] function.
1759#[no_mangle]
1760pub unsafe extern "C" fn ymap_iter_next(iter: *mut MapIter) -> *mut YMapEntry {
1761    assert!(!iter.is_null());
1762
1763    let iter = iter.as_mut().unwrap();
1764    if let Some((key, value)) = iter.0.next() {
1765        let output = YOutput::from(value);
1766        Box::into_raw(Box::new(YMapEntry::new(key, Box::new(output))))
1767    } else {
1768        std::ptr::null_mut()
1769    }
1770}
1771
1772/// Returns a number of entries stored within a `map`.
1773#[no_mangle]
1774pub unsafe extern "C" fn ymap_len(map: *const Branch, txn: *const Transaction) -> u32 {
1775    assert!(!map.is_null());
1776
1777    let txn = txn.as_ref().unwrap();
1778    let map = MapRef::from_raw_branch(map);
1779
1780    map.len(txn)
1781}
1782
1783/// Inserts a new entry (specified as `key`-`value` pair) into a current `map`. If entry under such
1784/// given `key` already existed, its corresponding value will be replaced.
1785///
1786/// A `key` must be a null-terminated UTF-8 encoded string, which contents will be copied into
1787/// a `map` (therefore it must be freed by the function caller).
1788///
1789/// A `value` content is being copied into a `map`, therefore any of its content must be freed by
1790/// the function caller.
1791#[no_mangle]
1792pub unsafe extern "C" fn ymap_insert(
1793    map: *const Branch,
1794    txn: *mut Transaction,
1795    key: *const c_char,
1796    value: *const YInput,
1797) {
1798    assert!(!map.is_null());
1799    assert!(!txn.is_null());
1800    assert!(!key.is_null());
1801    assert!(!value.is_null());
1802
1803    let cstr = CStr::from_ptr(key);
1804    let key = cstr.to_str().unwrap().to_string();
1805
1806    let map = MapRef::from_raw_branch(map);
1807    let txn = txn.as_mut().unwrap();
1808    let txn = txn
1809        .as_mut()
1810        .expect("provided transaction was not writeable");
1811
1812    map.insert(txn, key, value.read());
1813}
1814
1815/// Removes a `map` entry, given its `key`. Returns `1` if the corresponding entry was successfully
1816/// removed or `0` if no entry with a provided `key` has been found inside of a `map`.
1817///
1818/// A `key` must be a null-terminated UTF-8 encoded string.
1819#[no_mangle]
1820pub unsafe extern "C" fn ymap_remove(
1821    map: *const Branch,
1822    txn: *mut Transaction,
1823    key: *const c_char,
1824) -> u8 {
1825    assert!(!map.is_null());
1826    assert!(!txn.is_null());
1827    assert!(!key.is_null());
1828
1829    let key = CStr::from_ptr(key).to_str().unwrap();
1830
1831    let map = MapRef::from_raw_branch(map);
1832    let txn = txn.as_mut().unwrap();
1833    let txn = txn
1834        .as_mut()
1835        .expect("provided transaction was not writeable");
1836
1837    if let Some(_) = map.remove(txn, key) {
1838        Y_TRUE
1839    } else {
1840        Y_FALSE
1841    }
1842}
1843
1844/// Returns a value stored under the provided `key`, or a null pointer if no entry with such `key`
1845/// has been found in a current `map`. A returned value is allocated by this function and therefore
1846/// should be eventually released using [youtput_destroy] function.
1847///
1848/// A `key` must be a null-terminated UTF-8 encoded string.
1849#[no_mangle]
1850pub unsafe extern "C" fn ymap_get(
1851    map: *const Branch,
1852    txn: *const Transaction,
1853    key: *const c_char,
1854) -> *mut YOutput {
1855    assert!(!map.is_null());
1856    assert!(!key.is_null());
1857    assert!(!txn.is_null());
1858
1859    let txn = txn.as_ref().unwrap();
1860    let key = CStr::from_ptr(key).to_str().unwrap();
1861
1862    let map = MapRef::from_raw_branch(map);
1863
1864    if let Some(value) = map.get(txn, key) {
1865        let output = YOutput::from(value);
1866        Box::into_raw(Box::new(output))
1867    } else {
1868        std::ptr::null_mut()
1869    }
1870}
1871
1872/// Returns a value stored under the provided `key` as UTF-8 encoded, NULL-terminated JSON string.
1873/// Once not needed that string should be deallocated using `ystring_destroy`.
1874///
1875/// This method will return `NULL` pointer if value was not found or value couldn't be serialized
1876/// into JSON string.
1877///
1878/// This method will also try to serialize complex types that don't have native JSON representation
1879/// like YMap, YArray, YText etc. in such cases their contents will be materialized into JSON values.
1880#[no_mangle]
1881pub unsafe extern "C" fn ymap_get_json(
1882    map: *const Branch,
1883    txn: *const Transaction,
1884    key: *const c_char,
1885) -> *mut c_char {
1886    assert!(!map.is_null());
1887    assert!(!key.is_null());
1888    assert!(!txn.is_null());
1889
1890    let txn = txn.as_ref().unwrap();
1891    let key = CStr::from_ptr(key).to_str().unwrap();
1892
1893    let map = MapRef::from_raw_branch(map);
1894
1895    if let Some(value) = map.get(txn, key) {
1896        let any = value.to_json(txn);
1897        match serde_json::to_string(&any) {
1898            Ok(json) => CString::new(json).unwrap().into_raw(),
1899            Err(_) => std::ptr::null_mut(),
1900        }
1901    } else {
1902        std::ptr::null_mut()
1903    }
1904}
1905
1906/// Removes all entries from a current `map`.
1907#[no_mangle]
1908pub unsafe extern "C" fn ymap_remove_all(map: *const Branch, txn: *mut Transaction) {
1909    assert!(!map.is_null());
1910    assert!(!txn.is_null());
1911
1912    let map = MapRef::from_raw_branch(map);
1913    let txn = txn.as_mut().unwrap();
1914    let txn = txn
1915        .as_mut()
1916        .expect("provided transaction was not writeable");
1917
1918    map.clear(txn);
1919}
1920
1921/// Return a name (or an XML tag) of a current `YXmlElement`. Root-level XML nodes use "UNDEFINED" as
1922/// their tag names.
1923///
1924/// Returned value is a null-terminated UTF-8 string, which must be released using [ystring_destroy]
1925/// function.
1926#[no_mangle]
1927pub unsafe extern "C" fn yxmlelem_tag(xml: *const Branch) -> *mut c_char {
1928    assert!(!xml.is_null());
1929    let xml = XmlElementRef::from_raw_branch(xml);
1930    if let Some(tag) = xml.try_tag() {
1931        CString::new(tag.deref()).unwrap().into_raw()
1932    } else {
1933        null_mut()
1934    }
1935}
1936
1937/// Converts current `YXmlElement` together with its children and attributes into a flat string
1938/// representation (no padding) eg. `<UNDEFINED><title key="value">sample text</title></UNDEFINED>`.
1939///
1940/// Returned value is a null-terminated UTF-8 string, which must be released using [ystring_destroy]
1941/// function.
1942#[no_mangle]
1943pub unsafe extern "C" fn yxmlelem_string(
1944    xml: *const Branch,
1945    txn: *const Transaction,
1946) -> *mut c_char {
1947    assert!(!xml.is_null());
1948    assert!(!txn.is_null());
1949
1950    let txn = txn.as_ref().unwrap();
1951    let xml = XmlElementRef::from_raw_branch(xml);
1952
1953    let str = xml.get_string(txn);
1954    CString::new(str).unwrap().into_raw()
1955}
1956
1957/// Inserts an XML attribute described using `attr_name` and `attr_value`. If another attribute with
1958/// the same name already existed, its value will be replaced with a provided one.
1959///
1960/// Both `attr_name` and `attr_value` must be a null-terminated UTF-8 encoded strings. Their
1961/// contents are being copied, therefore it's up to a function caller to properly release them.
1962#[no_mangle]
1963pub unsafe extern "C" fn yxmlelem_insert_attr(
1964    xml: *const Branch,
1965    txn: *mut Transaction,
1966    attr_name: *const c_char,
1967    attr_value: *const YInput,
1968) {
1969    assert!(!xml.is_null());
1970    assert!(!txn.is_null());
1971    assert!(!attr_name.is_null());
1972    assert!(!attr_value.is_null());
1973
1974    let xml = XmlElementRef::from_raw_branch(xml);
1975    let txn = txn.as_mut().unwrap();
1976    let txn = txn
1977        .as_mut()
1978        .expect("provided transaction was not writeable");
1979
1980    let key = CStr::from_ptr(attr_name).to_str().unwrap();
1981
1982    xml.insert_attribute(txn, key, attr_value.read());
1983}
1984
1985/// Removes an attribute from a current `YXmlElement`, given its name.
1986///
1987/// An `attr_name`must be a null-terminated UTF-8 encoded string.
1988#[no_mangle]
1989pub unsafe extern "C" fn yxmlelem_remove_attr(
1990    xml: *const Branch,
1991    txn: *mut Transaction,
1992    attr_name: *const c_char,
1993) {
1994    assert!(!xml.is_null());
1995    assert!(!txn.is_null());
1996    assert!(!attr_name.is_null());
1997
1998    let xml = XmlElementRef::from_raw_branch(xml);
1999    let txn = txn.as_mut().unwrap();
2000    let txn = txn
2001        .as_mut()
2002        .expect("provided transaction was not writeable");
2003
2004    let key = CStr::from_ptr(attr_name).to_str().unwrap();
2005    xml.remove_attribute(txn, &key);
2006}
2007
2008/// Returns the value of a current `YXmlElement`, given its name, or a null pointer if not attribute
2009/// with such name has been found. Returned pointer is a null-terminated UTF-8 encoded string, which
2010/// should be released using [ystring_destroy] function.
2011///
2012/// An `attr_name` must be a null-terminated UTF-8 encoded string.
2013#[no_mangle]
2014pub unsafe extern "C" fn yxmlelem_get_attr(
2015    xml: *const Branch,
2016    txn: *const Transaction,
2017    attr_name: *const c_char,
2018) -> *mut YOutput {
2019    assert!(!xml.is_null());
2020    assert!(!attr_name.is_null());
2021    assert!(!txn.is_null());
2022
2023    let xml = XmlElementRef::from_raw_branch(xml);
2024
2025    let key = CStr::from_ptr(attr_name).to_str().unwrap();
2026    let txn = txn.as_ref().unwrap();
2027    if let Some(value) = xml.get_attribute(txn, key) {
2028        let output = YOutput::from(value);
2029        Box::into_raw(Box::new(output))
2030    } else {
2031        std::ptr::null_mut()
2032    }
2033}
2034
2035/// Returns an iterator over the `YXmlElement` attributes.
2036///
2037/// Use [yxmlattr_iter_next] function in order to retrieve a consecutive (**unordered**) attributes.
2038/// Use [yxmlattr_iter_destroy] function in order to close the iterator and release its resources.
2039#[no_mangle]
2040pub unsafe extern "C" fn yxmlelem_attr_iter(
2041    xml: *const Branch,
2042    txn: *const Transaction,
2043) -> *mut Attributes {
2044    assert!(!xml.is_null());
2045    assert!(!txn.is_null());
2046
2047    let xml = &XmlElementRef::from_raw_branch(xml) as *const XmlElementRef;
2048    let txn = txn.as_ref().unwrap();
2049    Box::into_raw(Box::new(Attributes(xml.as_ref().unwrap().attributes(txn))))
2050}
2051
2052/// Returns an iterator over the `YXmlText` attributes.
2053///
2054/// Use [yxmlattr_iter_next] function in order to retrieve a consecutive (**unordered**) attributes.
2055/// Use [yxmlattr_iter_destroy] function in order to close the iterator and release its resources.
2056#[no_mangle]
2057pub unsafe extern "C" fn yxmltext_attr_iter(
2058    xml: *const Branch,
2059    txn: *const Transaction,
2060) -> *mut Attributes {
2061    assert!(!xml.is_null());
2062    assert!(!txn.is_null());
2063
2064    let xml = &XmlTextRef::from_raw_branch(xml) as *const XmlTextRef;
2065    let txn = txn.as_ref().unwrap();
2066    Box::into_raw(Box::new(Attributes(xml.as_ref().unwrap().attributes(txn))))
2067}
2068
2069/// Releases all of attributes iterator resources created by calling [yxmlelem_attr_iter]
2070/// or [yxmltext_attr_iter].
2071#[no_mangle]
2072pub unsafe extern "C" fn yxmlattr_iter_destroy(iterator: *mut Attributes) {
2073    if !iterator.is_null() {
2074        drop(Box::from_raw(iterator))
2075    }
2076}
2077
2078/// Returns a next XML attribute from an `iterator`. Attributes are returned in an unordered
2079/// manner. Once `iterator` reaches the end of attributes collection, a null pointer will be
2080/// returned.
2081///
2082/// Returned value should be eventually released using [yxmlattr_destroy].
2083#[no_mangle]
2084pub unsafe extern "C" fn yxmlattr_iter_next(iterator: *mut Attributes) -> *mut YXmlAttr {
2085    assert!(!iterator.is_null());
2086
2087    let iter = iterator.as_mut().unwrap();
2088
2089    if let Some((name, value)) = iter.0.next() {
2090        Box::into_raw(Box::new(YXmlAttr {
2091            name: CString::new(name).unwrap().into_raw(),
2092            value: Box::into_raw(Box::new(YOutput::from(value))),
2093        }))
2094    } else {
2095        std::ptr::null_mut()
2096    }
2097}
2098
2099/// Returns a next sibling of a current XML node, which can be either another `YXmlElement`
2100/// or a `YXmlText`. Together with [yxmlelem_first_child] it may be used to iterate over the direct
2101/// children of an XML node (in order to iterate over the nested XML structure use
2102/// [yxmlelem_tree_walker]).
2103///
2104/// If current `YXmlElement` is the last child, this function returns a null pointer.
2105/// A returned value should be eventually released using [youtput_destroy] function.
2106#[no_mangle]
2107pub unsafe extern "C" fn yxml_next_sibling(
2108    xml: *const Branch,
2109    txn: *const Transaction,
2110) -> *mut YOutput {
2111    assert!(!xml.is_null());
2112    assert!(!txn.is_null());
2113
2114    let xml = XmlElementRef::from_raw_branch(xml);
2115    let txn = txn.as_ref().unwrap();
2116
2117    let mut siblings = xml.siblings(txn);
2118    if let Some(next) = siblings.next() {
2119        match next {
2120            XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
2121            XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
2122            XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
2123        }
2124    } else {
2125        null_mut()
2126    }
2127}
2128
2129/// Returns a previous sibling of a current XML node, which can be either another `YXmlElement`
2130/// or a `YXmlText`.
2131///
2132/// If current `YXmlElement` is the first child, this function returns a null pointer.
2133/// A returned value should be eventually released using [youtput_destroy] function.
2134#[no_mangle]
2135pub unsafe extern "C" fn yxml_prev_sibling(
2136    xml: *const Branch,
2137    txn: *const Transaction,
2138) -> *mut YOutput {
2139    assert!(!xml.is_null());
2140    assert!(!txn.is_null());
2141
2142    let xml = XmlElementRef::from_raw_branch(xml);
2143    let txn = txn.as_ref().unwrap();
2144
2145    let mut siblings = xml.siblings(txn);
2146    if let Some(next) = siblings.next_back() {
2147        match next {
2148            XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
2149            XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
2150            XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
2151        }
2152    } else {
2153        null_mut()
2154    }
2155}
2156
2157/// Returns a parent `YXmlElement` of a current node, or null pointer when current `YXmlElement` is
2158/// a root-level shared data type.
2159#[no_mangle]
2160pub unsafe extern "C" fn yxmlelem_parent(xml: *const Branch) -> *mut Branch {
2161    assert!(!xml.is_null());
2162
2163    let xml = XmlElementRef::from_raw_branch(xml);
2164
2165    if let Some(parent) = xml.parent() {
2166        let branch = parent.as_ptr();
2167        branch.deref() as *const Branch as *mut Branch
2168    } else {
2169        std::ptr::null_mut()
2170    }
2171}
2172
2173/// Returns a number of child nodes (both `YXmlElement` and `YXmlText`) living under a current XML
2174/// element. This function doesn't count a recursive nodes, only direct children of a current node.
2175#[no_mangle]
2176pub unsafe extern "C" fn yxmlelem_child_len(xml: *const Branch, txn: *const Transaction) -> u32 {
2177    assert!(!xml.is_null());
2178    assert!(!txn.is_null());
2179
2180    let txn = txn.as_ref().unwrap();
2181    let xml = XmlElementRef::from_raw_branch(xml);
2182
2183    xml.len(txn) as u32
2184}
2185
2186/// Returns a first child node of a current `YXmlElement`, or null pointer if current XML node is
2187/// empty. Returned value could be either another `YXmlElement` or `YXmlText`.
2188///
2189/// A returned value should be eventually released using [youtput_destroy] function.
2190#[no_mangle]
2191pub unsafe extern "C" fn yxmlelem_first_child(xml: *const Branch) -> *mut YOutput {
2192    assert!(!xml.is_null());
2193
2194    let xml = XmlElementRef::from_raw_branch(xml);
2195
2196    if let Some(value) = xml.first_child() {
2197        match value {
2198            XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
2199            XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
2200            XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
2201        }
2202    } else {
2203        std::ptr::null_mut()
2204    }
2205}
2206
2207/// Returns an iterator over a nested recursive structure of a current `YXmlElement`, starting from
2208/// first of its children. Returned values can be either `YXmlElement` or `YXmlText` nodes.
2209///
2210/// Use [yxmlelem_tree_walker_next] function in order to iterate over to a next node.
2211/// Use [yxmlelem_tree_walker_destroy] function to release resources used by the iterator.
2212#[no_mangle]
2213pub unsafe extern "C" fn yxmlelem_tree_walker(
2214    xml: *const Branch,
2215    txn: *const Transaction,
2216) -> *mut TreeWalker {
2217    assert!(!xml.is_null());
2218    assert!(!txn.is_null());
2219
2220    let txn = txn.as_ref().unwrap();
2221    let xml = &XmlElementRef::from_raw_branch(xml) as *const XmlElementRef;
2222    Box::into_raw(Box::new(TreeWalker(xml.as_ref().unwrap().successors(txn))))
2223}
2224
2225/// Releases resources associated with a current XML tree walker iterator.
2226#[no_mangle]
2227pub unsafe extern "C" fn yxmlelem_tree_walker_destroy(iter: *mut TreeWalker) {
2228    if !iter.is_null() {
2229        drop(Box::from_raw(iter))
2230    }
2231}
2232
2233/// Moves current `iterator` to a next value (either `YXmlElement` or `YXmlText`), returning its
2234/// pointer or a null, if an `iterator` already reached the last successor node.
2235///
2236/// Values returned by this function should be eventually released using [youtput_destroy].
2237#[no_mangle]
2238pub unsafe extern "C" fn yxmlelem_tree_walker_next(iterator: *mut TreeWalker) -> *mut YOutput {
2239    assert!(!iterator.is_null());
2240
2241    let iter = iterator.as_mut().unwrap();
2242
2243    if let Some(next) = iter.0.next() {
2244        match next {
2245            XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
2246            XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
2247            XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
2248        }
2249    } else {
2250        std::ptr::null_mut()
2251    }
2252}
2253
2254/// Inserts an `YXmlElement` as a child of a current node at the given `index` and returns its
2255/// pointer. Node created this way will have a given `name` as its tag (eg. `p` for `<p></p>` node).
2256///
2257/// An `index` value must be between 0 and (inclusive) length of a current XML element (use
2258/// [yxmlelem_child_len] function to determine its length).
2259///
2260/// A `name` must be a null-terminated UTF-8 encoded string, which will be copied into current
2261/// document. Therefore `name` should be freed by the function caller.
2262#[no_mangle]
2263pub unsafe extern "C" fn yxmlelem_insert_elem(
2264    xml: *const Branch,
2265    txn: *mut Transaction,
2266    index: u32,
2267    name: *const c_char,
2268) -> *mut Branch {
2269    assert!(!xml.is_null());
2270    assert!(!txn.is_null());
2271    assert!(!name.is_null());
2272
2273    let xml = XmlElementRef::from_raw_branch(xml);
2274    let txn = txn.as_mut().unwrap();
2275    let txn = txn
2276        .as_mut()
2277        .expect("provided transaction was not writeable");
2278
2279    let name = CStr::from_ptr(name).to_str().unwrap();
2280    xml.insert(txn, index as u32, XmlElementPrelim::empty(name))
2281        .into_raw_branch()
2282}
2283
2284/// Inserts an `YXmlText` as a child of a current node at the given `index` and returns its
2285/// pointer.
2286///
2287/// An `index` value must be between 0 and (inclusive) length of a current XML element (use
2288/// [yxmlelem_child_len] function to determine its length).
2289#[no_mangle]
2290pub unsafe extern "C" fn yxmlelem_insert_text(
2291    xml: *const Branch,
2292    txn: *mut Transaction,
2293    index: u32,
2294) -> *mut Branch {
2295    assert!(!xml.is_null());
2296    assert!(!txn.is_null());
2297
2298    let xml = XmlElementRef::from_raw_branch(xml);
2299    let txn = txn.as_mut().unwrap();
2300    let txn = txn
2301        .as_mut()
2302        .expect("provided transaction was not writeable");
2303    xml.insert(txn, index as u32, XmlTextPrelim::new(""))
2304        .into_raw_branch()
2305}
2306
2307/// Removes a consecutive range of child elements (of specified length) from the current
2308/// `YXmlElement`, starting at the given `index`. Specified range must fit into boundaries of current
2309/// XML node children, otherwise this function will panic at runtime.
2310#[no_mangle]
2311pub unsafe extern "C" fn yxmlelem_remove_range(
2312    xml: *const Branch,
2313    txn: *mut Transaction,
2314    index: u32,
2315    len: u32,
2316) {
2317    assert!(!xml.is_null());
2318    assert!(!txn.is_null());
2319
2320    let xml = XmlElementRef::from_raw_branch(xml);
2321    let txn = txn.as_mut().unwrap();
2322    let txn = txn
2323        .as_mut()
2324        .expect("provided transaction was not writeable");
2325
2326    xml.remove_range(txn, index as u32, len as u32)
2327}
2328
2329/// Returns an XML child node (either a `YXmlElement` or `YXmlText`) stored at a given `index` of
2330/// a current `YXmlElement`. Returns null pointer if `index` was outside of the bound of current XML
2331/// node children.
2332///
2333/// Returned value should be eventually released using [youtput_destroy].
2334#[no_mangle]
2335pub unsafe extern "C" fn yxmlelem_get(
2336    xml: *const Branch,
2337    txn: *const Transaction,
2338    index: u32,
2339) -> *const YOutput {
2340    assert!(!xml.is_null());
2341    assert!(!txn.is_null());
2342
2343    let xml = XmlElementRef::from_raw_branch(xml);
2344    let txn = txn.as_ref().unwrap();
2345
2346    if let Some(child) = xml.get(txn, index as u32) {
2347        match child {
2348            XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
2349            XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
2350            XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
2351        }
2352    } else {
2353        std::ptr::null()
2354    }
2355}
2356
2357/// Returns the length of the `YXmlText` string content in bytes (without the null terminator
2358/// character)
2359#[no_mangle]
2360pub unsafe extern "C" fn yxmltext_len(txt: *const Branch, txn: *const Transaction) -> u32 {
2361    assert!(!txt.is_null());
2362    assert!(!txn.is_null());
2363
2364    let txn = txn.as_ref().unwrap();
2365    let txt = XmlTextRef::from_raw_branch(txt);
2366
2367    txt.len(txn) as u32
2368}
2369
2370/// Returns a null-terminated UTF-8 encoded string content of a current `YXmlText` shared data type.
2371///
2372/// Generated string resources should be released using [ystring_destroy] function.
2373#[no_mangle]
2374pub unsafe extern "C" fn yxmltext_string(
2375    txt: *const Branch,
2376    txn: *const Transaction,
2377) -> *mut c_char {
2378    assert!(!txt.is_null());
2379    assert!(!txn.is_null());
2380
2381    let txn = txn.as_ref().unwrap();
2382    let txt = XmlTextRef::from_raw_branch(txt);
2383
2384    let str = txt.get_string(txn);
2385    CString::new(str).unwrap().into_raw()
2386}
2387
2388/// Inserts a null-terminated UTF-8 encoded string a a given `index`. `index` value must be between
2389/// 0 and a length of a `YXmlText` (inclusive, accordingly to [yxmltext_len] return value), otherwise
2390/// this function will panic.
2391///
2392/// A `str` parameter must be a null-terminated UTF-8 encoded string. This function doesn't take
2393/// ownership over a passed value - it will be copied and therefore a string parameter must be
2394/// released by the caller.
2395///
2396/// A nullable pointer with defined `attrs` will be used to wrap provided text with
2397/// a formatting blocks. `attrs` must be a map-like type.
2398#[no_mangle]
2399pub unsafe extern "C" fn yxmltext_insert(
2400    txt: *const Branch,
2401    txn: *mut Transaction,
2402    index: u32,
2403    str: *const c_char,
2404    attrs: *const YInput,
2405) {
2406    assert!(!txt.is_null());
2407    assert!(!txn.is_null());
2408    assert!(!str.is_null());
2409
2410    let txt = XmlTextRef::from_raw_branch(txt);
2411    let txn = txn.as_mut().unwrap();
2412    let txn = txn
2413        .as_mut()
2414        .expect("provided transaction was not writeable");
2415    let chunk = CStr::from_ptr(str).to_str().unwrap();
2416
2417    if attrs.is_null() {
2418        txt.insert(txn, index as u32, chunk)
2419    } else {
2420        if let Some(attrs) = map_attrs(attrs.read().into()) {
2421            txt.insert_with_attributes(txn, index as u32, chunk, attrs)
2422        } else {
2423            panic!("yxmltext_insert: passed attributes are not of map type")
2424        }
2425    }
2426}
2427
2428/// Inserts an embed content given `index`. `index` value must be between 0 and a length of a
2429/// `YXmlText` (inclusive, accordingly to [ytext_len] return value), otherwise this
2430/// function will panic.
2431///
2432/// A `str` parameter must be a null-terminated UTF-8 encoded string. This function doesn't take
2433/// ownership over a passed value - it will be copied and therefore a string parameter must be
2434/// released by the caller.
2435///
2436/// A nullable pointer with defined `attrs` will be used to wrap provided text with
2437/// a formatting blocks. `attrs` must be a map-like type.
2438#[no_mangle]
2439pub unsafe extern "C" fn yxmltext_insert_embed(
2440    txt: *const Branch,
2441    txn: *mut Transaction,
2442    index: u32,
2443    content: *const YInput,
2444    attrs: *const YInput,
2445) {
2446    assert!(!txt.is_null());
2447    assert!(!txn.is_null());
2448    assert!(!content.is_null());
2449
2450    let txn = txn.as_mut().unwrap();
2451    let txn = txn
2452        .as_mut()
2453        .expect("provided transaction was not writeable");
2454    let txt = XmlTextRef::from_raw_branch(txt);
2455    let index = index as u32;
2456    let content = content.read();
2457    if attrs.is_null() {
2458        txt.insert_embed(txn, index, content);
2459    } else {
2460        if let Some(attrs) = map_attrs(attrs.read().into()) {
2461            txt.insert_embed_with_attributes(txn, index, content, attrs);
2462        } else {
2463            panic!("yxmltext_insert_embed: passed attributes are not of map type")
2464        }
2465    }
2466}
2467
2468/// Wraps an existing piece of text within a range described by `index`-`len` parameters with
2469/// formatting blocks containing provided `attrs` metadata. `attrs` must be a map-like type.
2470#[no_mangle]
2471pub unsafe extern "C" fn yxmltext_format(
2472    txt: *const Branch,
2473    txn: *mut Transaction,
2474    index: u32,
2475    len: u32,
2476    attrs: *const YInput,
2477) {
2478    assert!(!txt.is_null());
2479    assert!(!txn.is_null());
2480    assert!(!attrs.is_null());
2481
2482    if let Some(attrs) = map_attrs(attrs.read().into()) {
2483        let txt = XmlTextRef::from_raw_branch(txt);
2484        let txn = txn.as_mut().unwrap();
2485        let txn = txn
2486            .as_mut()
2487            .expect("provided transaction was not writeable");
2488        let index = index as u32;
2489        let len = len as u32;
2490        txt.format(txn, index, len, attrs);
2491    } else {
2492        panic!("yxmltext_format: passed attributes are not of map type")
2493    }
2494}
2495
2496/// Removes a range of characters, starting a a given `index`. This range must fit within the bounds
2497/// of a current `YXmlText`, otherwise this function call will fail.
2498///
2499/// An `index` value must be between 0 and the length of a `YXmlText` (exclusive, accordingly to
2500/// [yxmltext_len] return value).
2501///
2502/// A `length` must be lower or equal number of characters (counted as UTF chars depending on the
2503/// encoding configured by `YDoc`) from `index` position to the end of of the string.
2504#[no_mangle]
2505pub unsafe extern "C" fn yxmltext_remove_range(
2506    txt: *const Branch,
2507    txn: *mut Transaction,
2508    idx: u32,
2509    len: u32,
2510) {
2511    assert!(!txt.is_null());
2512    assert!(!txn.is_null());
2513
2514    let txt = XmlTextRef::from_raw_branch(txt);
2515    let txn = txn.as_mut().unwrap();
2516    let txn = txn
2517        .as_mut()
2518        .expect("provided transaction was not writeable");
2519    txt.remove_range(txn, idx as u32, len as u32)
2520}
2521
2522/// Inserts an XML attribute described using `attr_name` and `attr_value`. If another attribute with
2523/// the same name already existed, its value will be replaced with a provided one.
2524///
2525/// Both `attr_name` and `attr_value` must be a null-terminated UTF-8 encoded strings. Their
2526/// contents are being copied, therefore it's up to a function caller to properly release them.
2527#[no_mangle]
2528pub unsafe extern "C" fn yxmltext_insert_attr(
2529    txt: *const Branch,
2530    txn: *mut Transaction,
2531    attr_name: *const c_char,
2532    attr_value: *const YInput,
2533) {
2534    assert!(!txt.is_null());
2535    assert!(!txn.is_null());
2536    assert!(!attr_name.is_null());
2537    assert!(!attr_value.is_null());
2538
2539    let txt = XmlTextRef::from_raw_branch(txt);
2540    let txn = txn.as_mut().unwrap();
2541    let txn = txn
2542        .as_mut()
2543        .expect("provided transaction was not writeable");
2544
2545    let name = CStr::from_ptr(attr_name).to_str().unwrap();
2546
2547    txt.insert_attribute(txn, name, attr_value.read());
2548}
2549
2550/// Removes an attribute from a current `YXmlText`, given its name.
2551///
2552/// An `attr_name`must be a null-terminated UTF-8 encoded string.
2553#[no_mangle]
2554pub unsafe extern "C" fn yxmltext_remove_attr(
2555    txt: *const Branch,
2556    txn: *mut Transaction,
2557    attr_name: *const c_char,
2558) {
2559    assert!(!txt.is_null());
2560    assert!(!txn.is_null());
2561    assert!(!attr_name.is_null());
2562
2563    let txt = XmlTextRef::from_raw_branch(txt);
2564    let txn = txn.as_mut().unwrap();
2565    let txn = txn
2566        .as_mut()
2567        .expect("provided transaction was not writeable");
2568    let name = CStr::from_ptr(attr_name).to_str().unwrap();
2569
2570    txt.remove_attribute(txn, &name)
2571}
2572
2573/// Returns the value of a current `YXmlText`, given its name, or a null pointer if not attribute
2574/// with such name has been found. Returned pointer is a null-terminated UTF-8 encoded string, which
2575/// should be released using [ystring_destroy] function.
2576///
2577/// An `attr_name` must be a null-terminated UTF-8 encoded string.
2578#[no_mangle]
2579pub unsafe extern "C" fn yxmltext_get_attr(
2580    txt: *const Branch,
2581    txn: *const Transaction,
2582    attr_name: *const c_char,
2583) -> *mut YOutput {
2584    assert!(!txt.is_null());
2585    assert!(!attr_name.is_null());
2586    assert!(!txn.is_null());
2587
2588    let txn = txn.as_ref().unwrap();
2589    let txt = XmlTextRef::from_raw_branch(txt);
2590    let name = CStr::from_ptr(attr_name).to_str().unwrap();
2591
2592    if let Some(value) = txt.get_attribute(txn, name) {
2593        let output = YOutput::from(value);
2594        Box::into_raw(Box::new(output))
2595    } else {
2596        std::ptr::null_mut()
2597    }
2598}
2599
2600/// Returns a collection of chunks representing pieces of `YText` rich text string grouped together
2601/// by the same formatting rules and type. `chunks_len` is used to inform about a number of chunks
2602/// generated this way.
2603///
2604/// Returned array needs to be eventually deallocated using `ychunks_destroy`.
2605#[no_mangle]
2606pub unsafe extern "C" fn ytext_chunks(
2607    txt: *const Branch,
2608    txn: *const Transaction,
2609    chunks_len: *mut u32,
2610) -> *mut YChunk {
2611    assert!(!txt.is_null());
2612    assert!(!txn.is_null());
2613
2614    let txt = TextRef::from_raw_branch(txt);
2615    let txn = txn.as_ref().unwrap();
2616
2617    let diffs = txt.diff(txn, YChange::identity);
2618    let chunks: Vec<_> = diffs.into_iter().map(YChunk::from).collect();
2619    let out = chunks.into_boxed_slice();
2620    *chunks_len = out.len() as u32;
2621    Box::into_raw(out) as *mut _
2622}
2623
2624/// Deallocates result of `ytext_chunks` method.
2625#[no_mangle]
2626pub unsafe extern "C" fn ychunks_destroy(chunks: *mut YChunk, len: u32) {
2627    drop(Vec::from_raw_parts(chunks, len as usize, len as usize));
2628}
2629
2630pub const YCHANGE_ADD: i8 = 1;
2631pub const YCHANGE_RETAIN: i8 = 0;
2632pub const YCHANGE_REMOVE: i8 = -1;
2633
2634/// A chunk of text contents formatted with the same set of attributes.
2635#[repr(C)]
2636pub struct YChunk {
2637    /// Piece of YText formatted using the same `fmt` rules. It can be a string, embedded object
2638    /// or another y-type.
2639    pub data: YOutput,
2640    /// Number of formatting attributes attached to current chunk of text.
2641    pub fmt_len: u32,
2642    /// The formatting attributes attached to the current chunk of text.
2643    pub fmt: *mut YMapEntry,
2644}
2645
2646impl From<Diff<YChange>> for YChunk {
2647    fn from(diff: Diff<YChange>) -> Self {
2648        let data = YOutput::from(diff.insert);
2649        let mut fmt_len = 0;
2650        let fmt = if let Some(attrs) = diff.attributes {
2651            fmt_len = attrs.len() as u32;
2652            let mut fmt = Vec::with_capacity(attrs.len());
2653            for (k, v) in attrs.into_iter() {
2654                let output = YOutput::from(&v); //TODO: test if we don't drop memory here
2655                let e = YMapEntry::new(k.as_ref(), Box::new(output));
2656                fmt.push(e);
2657            }
2658            Box::into_raw(fmt.into_boxed_slice()) as *mut _
2659        } else {
2660            null_mut()
2661        };
2662        YChunk { data, fmt_len, fmt }
2663    }
2664}
2665
2666impl Drop for YChunk {
2667    fn drop(&mut self) {
2668        if !self.fmt.is_null() {
2669            drop(unsafe {
2670                Vec::from_raw_parts(self.fmt, self.fmt_len as usize, self.fmt_len as usize)
2671            });
2672        }
2673    }
2674}
2675
2676/// A data structure that is used to pass input values of various types supported by Yrs into a
2677/// shared document store.
2678///
2679/// `YInput` constructor function don't allocate any resources on their own, neither they take
2680/// ownership by pointers to memory blocks allocated by user - for this reason once an input cell
2681/// has been used, its content should be freed by the caller.
2682#[repr(C)]
2683pub struct YInput {
2684    /// Tag describing, which `value` type is being stored by this input cell. Can be one of:
2685    ///
2686    /// - [Y_JSON] for a UTF-8 encoded, NULL-terminated JSON string.
2687    /// - [Y_JSON_BOOL] for boolean flags.
2688    /// - [Y_JSON_NUM] for 64-bit floating point numbers.
2689    /// - [Y_JSON_INT] for 64-bit signed integers.
2690    /// - [Y_JSON_STR] for null-terminated UTF-8 encoded strings.
2691    /// - [Y_JSON_BUF] for embedded binary data.
2692    /// - [Y_JSON_ARR] for arrays of JSON-like values.
2693    /// - [Y_JSON_MAP] for JSON-like objects build from key-value pairs.
2694    /// - [Y_JSON_NULL] for JSON-like null values.
2695    /// - [Y_JSON_UNDEF] for JSON-like undefined values.
2696    /// - [Y_ARRAY] for cells which contents should be used to initialize a `YArray` shared type.
2697    /// - [Y_MAP] for cells which contents should be used to initialize a `YMap` shared type.
2698    /// - [Y_DOC] for cells which contents should be used to nest a `YDoc` sub-document.
2699    /// - [Y_WEAK_LINK] for cells which contents should be used to nest a `YWeakLink` sub-document.
2700    pub tag: i8,
2701
2702    /// Length of the contents stored by current `YInput` cell.
2703    ///
2704    /// For [Y_JSON_NULL] and [Y_JSON_UNDEF] its equal to `0`.
2705    ///
2706    /// For [Y_JSON_ARR], [Y_JSON_MAP], [Y_ARRAY] and [Y_MAP] it describes a number of passed
2707    /// elements.
2708    ///
2709    /// For other types it's always equal to `1`.
2710    pub len: u32,
2711
2712    /// Union struct which contains a content corresponding to a provided `tag` field.
2713    value: YInputContent,
2714}
2715
2716impl YInput {
2717    fn into(self) -> Any {
2718        let tag = self.tag;
2719        unsafe {
2720            match tag {
2721                Y_JSON_STR => {
2722                    let str = CStr::from_ptr(self.value.str).to_str().unwrap().into();
2723                    Any::String(str)
2724                }
2725                Y_JSON => {
2726                    let json_str = CStr::from_ptr(self.value.str).to_str().unwrap();
2727                    serde_json::from_str(json_str).unwrap()
2728                }
2729                Y_JSON_NULL => Any::Null,
2730                Y_JSON_UNDEF => Any::Undefined,
2731                Y_JSON_INT => Any::BigInt(self.value.integer),
2732                Y_JSON_NUM => Any::Number(self.value.num),
2733                Y_JSON_BOOL => Any::Bool(if self.value.flag == 0 { false } else { true }),
2734                Y_JSON_BUF => Any::from(std::slice::from_raw_parts(
2735                    self.value.buf as *mut u8,
2736                    self.len as usize,
2737                )),
2738                Y_JSON_ARR => {
2739                    let ptr = self.value.values;
2740                    let mut dst: Vec<Any> = Vec::with_capacity(self.len as usize);
2741                    let mut i = 0;
2742                    while i < self.len as isize {
2743                        let value = ptr.offset(i).read();
2744                        let any = value.into();
2745                        dst.push(any);
2746                        i += 1;
2747                    }
2748                    Any::from(dst)
2749                }
2750                Y_JSON_MAP => {
2751                    let mut dst = HashMap::with_capacity(self.len as usize);
2752                    let keys = self.value.map.keys;
2753                    let values = self.value.map.values;
2754                    let mut i = 0;
2755                    while i < self.len as isize {
2756                        let key = CStr::from_ptr(keys.offset(i).read())
2757                            .to_str()
2758                            .unwrap()
2759                            .to_owned();
2760                        let value = values.offset(i).read().into();
2761                        dst.insert(key, value);
2762                        i += 1;
2763                    }
2764                    Any::from(dst)
2765                }
2766                Y_DOC => Any::Undefined,
2767                other => panic!("Cannot convert input - unknown tag: {}", other),
2768            }
2769        }
2770    }
2771}
2772
2773impl Into<EmbedPrelim<YInput>> for YInput {
2774    fn into(self) -> EmbedPrelim<YInput> {
2775        if self.tag <= 0 {
2776            EmbedPrelim::Primitive(self.into())
2777        } else {
2778            EmbedPrelim::Shared(self)
2779        }
2780    }
2781}
2782
2783#[repr(C)]
2784union YInputContent {
2785    flag: u8,
2786    num: f64,
2787    integer: i64,
2788    str: *mut c_char,
2789    buf: *mut c_char,
2790    values: *mut YInput,
2791    map: ManuallyDrop<YMapInputData>,
2792    doc: *mut Doc,
2793    weak: *const Weak,
2794}
2795
2796#[repr(C)]
2797struct YMapInputData {
2798    keys: *mut *mut c_char,
2799    values: *mut YInput,
2800}
2801
2802impl Drop for YInput {
2803    fn drop(&mut self) {}
2804}
2805
2806impl Prelim for YInput {
2807    type Return = Unused;
2808
2809    fn into_content<'doc>(self, _: &mut yrs::TransactionMut<'doc>) -> (ItemContent, Option<Self>) {
2810        unsafe {
2811            if self.tag <= 0 {
2812                (ItemContent::Any(vec![self.into()]), None)
2813            } else if self.tag == Y_DOC {
2814                let doc = self.value.doc.as_ref().unwrap();
2815                (ItemContent::Doc(None, doc.clone()), None)
2816            } else {
2817                let type_ref = match self.tag {
2818                    Y_MAP => TypeRef::Map,
2819                    Y_ARRAY => TypeRef::Array,
2820                    Y_TEXT => TypeRef::Text,
2821                    Y_XML_TEXT => TypeRef::XmlText,
2822                    Y_XML_ELEM => {
2823                        let name: Arc<str> =
2824                            CStr::from_ptr(self.value.str).to_str().unwrap().into();
2825                        TypeRef::XmlElement(name)
2826                    }
2827                    Y_WEAK_LINK => {
2828                        let source = Arc::from_raw(self.value.weak);
2829                        TypeRef::WeakLink(source)
2830                    }
2831                    Y_XML_FRAG => TypeRef::XmlFragment,
2832                    other => panic!("unrecognized YInput tag: {}", other),
2833                };
2834                let inner = Branch::new(type_ref);
2835                (ItemContent::Type(inner), Some(self))
2836            }
2837        }
2838    }
2839
2840    fn integrate(self, txn: &mut yrs::TransactionMut, inner_ref: BranchPtr) {
2841        unsafe {
2842            match self.tag {
2843                Y_MAP => {
2844                    let map = MapRef::from(inner_ref);
2845                    let keys = self.value.map.keys;
2846                    let values = self.value.map.values;
2847                    let mut i = 0;
2848                    while i < self.len as isize {
2849                        let key = CStr::from_ptr(keys.offset(i).read())
2850                            .to_str()
2851                            .unwrap()
2852                            .to_owned();
2853                        let value = values.offset(i).read();
2854                        map.insert(txn, key, value);
2855                        i += 1;
2856                    }
2857                }
2858                Y_ARRAY => {
2859                    let array = ArrayRef::from(inner_ref);
2860                    let ptr = self.value.values;
2861                    let len = self.len as isize;
2862                    let mut i = 0;
2863                    while i < len {
2864                        let value = ptr.offset(i).read();
2865                        array.push_back(txn, value);
2866                        i += 1;
2867                    }
2868                }
2869                Y_TEXT => {
2870                    let text = TextRef::from(inner_ref);
2871                    let init = CStr::from_ptr(self.value.str).to_str().unwrap();
2872                    text.push(txn, init);
2873                }
2874                Y_XML_TEXT => {
2875                    let text = XmlTextRef::from(inner_ref);
2876                    let init = CStr::from_ptr(self.value.str).to_str().unwrap();
2877                    text.push(txn, init);
2878                }
2879                _ => { /* do nothing */ }
2880            }
2881        }
2882    }
2883}
2884
2885/// An output value cell returned from yrs API methods. It describes a various types of data
2886/// supported by yrs shared data types.
2887///
2888/// Since `YOutput` instances are always created by calling the corresponding yrs API functions,
2889/// they eventually should be deallocated using [youtput_destroy] function.
2890#[repr(C)]
2891pub struct YOutput {
2892    /// Tag describing, which `value` type is being stored by this input cell. Can be one of:
2893    ///
2894    /// - [Y_JSON_BOOL] for boolean flags.
2895    /// - [Y_JSON_NUM] for 64-bit floating point numbers.
2896    /// - [Y_JSON_INT] for 64-bit signed integers.
2897    /// - [Y_JSON_STR] for null-terminated UTF-8 encoded strings.
2898    /// - [Y_JSON_BUF] for embedded binary data.
2899    /// - [Y_JSON_ARR] for arrays of JSON-like values.
2900    /// - [Y_JSON_MAP] for JSON-like objects build from key-value pairs.
2901    /// - [Y_JSON_NULL] for JSON-like null values.
2902    /// - [Y_JSON_UNDEF] for JSON-like undefined values.
2903    /// - [Y_TEXT] for pointers to `YText` data types.
2904    /// - [Y_ARRAY] for pointers to `YArray` data types.
2905    /// - [Y_MAP] for pointers to `YMap` data types.
2906    /// - [Y_XML_ELEM] for pointers to `YXmlElement` data types.
2907    /// - [Y_XML_TEXT] for pointers to `YXmlText` data types.
2908    /// - [Y_DOC] for pointers to nested `YDocRef` data types.
2909    pub tag: i8,
2910
2911    /// Length of the contents stored by a current `YOutput` cell.
2912    ///
2913    /// For [Y_JSON_NULL] and [Y_JSON_UNDEF] its equal to `0`.
2914    ///
2915    /// For [Y_JSON_ARR], [Y_JSON_MAP] it describes a number of passed elements.
2916    ///
2917    /// For other types it's always equal to `1`.
2918    pub len: u32,
2919
2920    /// Union struct which contains a content corresponding to a provided `tag` field.
2921    value: YOutputContent,
2922}
2923
2924impl YOutput {
2925    #[inline]
2926    unsafe fn null() -> YOutput {
2927        YOutput {
2928            tag: Y_JSON_NULL,
2929            len: 0,
2930            value: MaybeUninit::uninit().assume_init(),
2931        }
2932    }
2933
2934    #[inline]
2935    unsafe fn undefined() -> YOutput {
2936        YOutput {
2937            tag: Y_JSON_UNDEF,
2938            len: 0,
2939            value: MaybeUninit::uninit().assume_init(),
2940        }
2941    }
2942}
2943
2944impl std::fmt::Display for YOutput {
2945    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2946        let tag = self.tag;
2947        unsafe {
2948            if tag == Y_JSON_INT {
2949                write!(f, "{}", self.value.integer)
2950            } else if tag == Y_JSON_NUM {
2951                write!(f, "{}", self.value.num)
2952            } else if tag == Y_JSON_BOOL {
2953                write!(
2954                    f,
2955                    "{}",
2956                    if self.value.flag == 0 {
2957                        "false"
2958                    } else {
2959                        "true"
2960                    }
2961                )
2962            } else if tag == Y_JSON_UNDEF {
2963                write!(f, "undefined")
2964            } else if tag == Y_JSON_NULL {
2965                write!(f, "null")
2966            } else if tag == Y_JSON_STR {
2967                write!(f, "{}", CString::from_raw(self.value.str).to_str().unwrap())
2968            } else if tag == Y_MAP {
2969                write!(f, "YMap")
2970            } else if tag == Y_ARRAY {
2971                write!(f, "YArray")
2972            } else if tag == Y_JSON_ARR {
2973                write!(f, "[")?;
2974                let slice = std::slice::from_raw_parts(self.value.array, self.len as usize);
2975                for o in slice {
2976                    write!(f, ", {}", o)?;
2977                }
2978                write!(f, "]")
2979            } else if tag == Y_JSON_MAP {
2980                write!(f, "{{")?;
2981                let slice = std::slice::from_raw_parts(self.value.map, self.len as usize);
2982                for e in slice {
2983                    let key = CStr::from_ptr(e.key).to_str().unwrap();
2984                    let value = e.value.as_ref().unwrap();
2985                    write!(f, ", '{}' => {}", key, value)?;
2986                }
2987                write!(f, "}}")
2988            } else if tag == Y_TEXT {
2989                write!(f, "YText")
2990            } else if tag == Y_XML_TEXT {
2991                write!(f, "YXmlText")
2992            } else if tag == Y_XML_ELEM {
2993                write!(f, "YXmlElement",)
2994            } else if tag == Y_JSON_BUF {
2995                write!(f, "YBinary(len: {})", self.len)
2996            } else {
2997                Ok(())
2998            }
2999        }
3000    }
3001}
3002
3003impl Drop for YOutput {
3004    fn drop(&mut self) {
3005        let tag = self.tag;
3006        unsafe {
3007            match tag {
3008                Y_JSON_STR => drop(CString::from_raw(self.value.str)),
3009                Y_JSON_ARR => drop(Vec::from_raw_parts(
3010                    self.value.array,
3011                    self.len as usize,
3012                    self.len as usize,
3013                )),
3014                Y_JSON_MAP => drop(Vec::from_raw_parts(
3015                    self.value.map,
3016                    self.len as usize,
3017                    self.len as usize,
3018                )),
3019                Y_JSON_BUF => drop(Vec::from_raw_parts(
3020                    // while we were using Box<[u8]>, for deallocation this should work
3021                    self.value.buf as *mut u8,
3022                    self.len as usize,
3023                    self.len as usize,
3024                )),
3025                Y_DOC => drop(Box::from_raw(self.value.y_doc)),
3026                _ => { /* ignore */ }
3027            }
3028        }
3029    }
3030}
3031
3032impl From<Out> for YOutput {
3033    fn from(v: Out) -> Self {
3034        match v {
3035            Out::Any(v) => Self::from(v),
3036            Out::YText(v) => Self::from(v),
3037            Out::YArray(v) => Self::from(v),
3038            Out::YMap(v) => Self::from(v),
3039            Out::YXmlElement(v) => Self::from(v),
3040            Out::YXmlFragment(v) => Self::from(v),
3041            Out::YXmlText(v) => Self::from(v),
3042            Out::YDoc(v) => Self::from(v),
3043            Out::YWeakLink(v) => Self::from(v),
3044            Out::UndefinedRef(v) => Self::from(v),
3045        }
3046    }
3047}
3048
3049impl From<bool> for YOutput {
3050    #[inline]
3051    fn from(value: bool) -> Self {
3052        YOutput {
3053            tag: Y_JSON_BOOL,
3054            len: 1,
3055            value: YOutputContent {
3056                flag: if value { Y_TRUE } else { Y_FALSE },
3057            },
3058        }
3059    }
3060}
3061
3062impl From<f64> for YOutput {
3063    #[inline]
3064    fn from(value: f64) -> Self {
3065        YOutput {
3066            tag: Y_JSON_NUM,
3067            len: 1,
3068            value: YOutputContent { num: value },
3069        }
3070    }
3071}
3072
3073impl From<i64> for YOutput {
3074    #[inline]
3075    fn from(value: i64) -> Self {
3076        YOutput {
3077            tag: Y_JSON_INT,
3078            len: 1,
3079            value: YOutputContent { integer: value },
3080        }
3081    }
3082}
3083
3084impl<'a> From<&'a str> for YOutput {
3085    fn from(value: &'a str) -> Self {
3086        YOutput {
3087            tag: Y_JSON_STR,
3088            len: value.len() as u32,
3089            value: YOutputContent {
3090                str: CString::new(value).unwrap().into_raw(),
3091            },
3092        }
3093    }
3094}
3095
3096impl<'a> From<&'a [u8]> for YOutput {
3097    fn from(value: &'a [u8]) -> Self {
3098        let value: Box<[u8]> = value.into();
3099        YOutput {
3100            tag: Y_JSON_BUF,
3101            len: value.len() as u32,
3102            value: YOutputContent {
3103                buf: Box::into_raw(value) as *const u8 as *mut c_char,
3104            },
3105        }
3106    }
3107}
3108
3109impl<'a> From<&'a [Any]> for YOutput {
3110    fn from(values: &'a [Any]) -> Self {
3111        let len = values.len() as u32;
3112        let mut array = Vec::with_capacity(values.len());
3113        for v in values.iter() {
3114            let output = YOutput::from(v);
3115            array.push(output);
3116        }
3117        let ptr = array.as_mut_ptr();
3118        forget(array);
3119        YOutput {
3120            tag: Y_JSON_ARR,
3121            len,
3122            value: YOutputContent { array: ptr },
3123        }
3124    }
3125}
3126
3127impl<'a> From<&'a HashMap<String, Any>> for YOutput {
3128    fn from(value: &'a HashMap<String, Any>) -> Self {
3129        let len = value.len() as u32;
3130        let mut array = Vec::with_capacity(len as usize);
3131        for (k, v) in value.iter() {
3132            let entry = YMapEntry::new(k.as_str(), Box::new(YOutput::from(v)));
3133            array.push(entry);
3134        }
3135        let ptr = array.as_mut_ptr();
3136        forget(array);
3137        YOutput {
3138            tag: Y_JSON_MAP,
3139            len,
3140            value: YOutputContent { map: ptr },
3141        }
3142    }
3143}
3144
3145impl<'a> From<&'a Any> for YOutput {
3146    fn from(v: &'a Any) -> Self {
3147        unsafe {
3148            match v {
3149                Any::Null => YOutput::null(),
3150                Any::Undefined => YOutput::undefined(),
3151                Any::Bool(v) => YOutput::from(*v),
3152                Any::Number(v) => YOutput::from(*v),
3153                Any::BigInt(v) => YOutput::from(*v),
3154                Any::String(v) => YOutput::from(v.as_ref()),
3155                Any::Buffer(v) => YOutput::from(v.as_ref()),
3156                Any::Array(v) => YOutput::from(v.as_ref()),
3157                Any::Map(v) => YOutput::from(v.as_ref()),
3158            }
3159        }
3160    }
3161}
3162
3163impl From<Any> for YOutput {
3164    fn from(v: Any) -> Self {
3165        unsafe {
3166            match v {
3167                Any::Null => YOutput::null(),
3168                Any::Undefined => YOutput::undefined(),
3169                Any::Bool(v) => YOutput::from(v),
3170                Any::Number(v) => YOutput::from(v),
3171                Any::BigInt(v) => YOutput::from(v),
3172                Any::String(v) => YOutput::from(v.as_ref()),
3173                Any::Buffer(v) => YOutput::from(v.as_ref()),
3174                Any::Array(v) => YOutput::from(v.as_ref()),
3175                Any::Map(v) => YOutput::from(v.as_ref()),
3176            }
3177        }
3178    }
3179}
3180
3181impl From<TextRef> for YOutput {
3182    fn from(v: TextRef) -> Self {
3183        YOutput {
3184            tag: Y_TEXT,
3185            len: 1,
3186            value: YOutputContent {
3187                y_type: v.into_raw_branch(),
3188            },
3189        }
3190    }
3191}
3192
3193impl From<ArrayRef> for YOutput {
3194    fn from(v: ArrayRef) -> Self {
3195        YOutput {
3196            tag: Y_ARRAY,
3197            len: 1,
3198            value: YOutputContent {
3199                y_type: v.into_raw_branch(),
3200            },
3201        }
3202    }
3203}
3204
3205impl From<WeakRef<BranchPtr>> for YOutput {
3206    fn from(v: WeakRef<BranchPtr>) -> Self {
3207        YOutput {
3208            tag: Y_WEAK_LINK,
3209            len: 1,
3210            value: YOutputContent {
3211                y_type: v.into_raw_branch(),
3212            },
3213        }
3214    }
3215}
3216
3217impl From<MapRef> for YOutput {
3218    fn from(v: MapRef) -> Self {
3219        YOutput {
3220            tag: Y_MAP,
3221            len: 1,
3222            value: YOutputContent {
3223                y_type: v.into_raw_branch(),
3224            },
3225        }
3226    }
3227}
3228
3229impl From<BranchPtr> for YOutput {
3230    fn from(v: BranchPtr) -> Self {
3231        let branch_ref = v.as_ref();
3232        YOutput {
3233            tag: Y_UNDEFINED,
3234            len: 1,
3235            value: YOutputContent {
3236                y_type: branch_ref as *const Branch as *mut Branch,
3237            },
3238        }
3239    }
3240}
3241
3242impl From<XmlElementRef> for YOutput {
3243    fn from(v: XmlElementRef) -> Self {
3244        YOutput {
3245            tag: Y_XML_ELEM,
3246            len: 1,
3247            value: YOutputContent {
3248                y_type: v.into_raw_branch(),
3249            },
3250        }
3251    }
3252}
3253
3254impl From<XmlTextRef> for YOutput {
3255    fn from(v: XmlTextRef) -> Self {
3256        YOutput {
3257            tag: Y_XML_TEXT,
3258            len: 1,
3259            value: YOutputContent {
3260                y_type: v.into_raw_branch(),
3261            },
3262        }
3263    }
3264}
3265
3266impl From<XmlFragmentRef> for YOutput {
3267    fn from(v: XmlFragmentRef) -> Self {
3268        YOutput {
3269            tag: Y_XML_FRAG,
3270            len: 1,
3271            value: YOutputContent {
3272                y_type: v.into_raw_branch(),
3273            },
3274        }
3275    }
3276}
3277
3278impl From<Doc> for YOutput {
3279    fn from(v: Doc) -> Self {
3280        YOutput {
3281            tag: Y_DOC,
3282            len: 1,
3283            value: YOutputContent {
3284                y_doc: Box::into_raw(Box::new(v.clone())),
3285            },
3286        }
3287    }
3288}
3289
3290#[repr(C)]
3291union YOutputContent {
3292    flag: u8,
3293    num: f64,
3294    integer: i64,
3295    str: *mut c_char,
3296    buf: *const c_char,
3297    array: *mut YOutput,
3298    map: *mut YMapEntry,
3299    y_type: *mut Branch,
3300    y_doc: *mut Doc,
3301}
3302
3303/// Releases all resources related to a corresponding `YOutput` cell.
3304#[no_mangle]
3305pub unsafe extern "C" fn youtput_destroy(val: *mut YOutput) {
3306    if !val.is_null() {
3307        drop(Box::from_raw(val))
3308    }
3309}
3310
3311/// Function constructor used to create JSON-like NULL `YInput` cell.
3312/// This function doesn't allocate any heap resources.
3313#[no_mangle]
3314pub unsafe extern "C" fn yinput_null() -> YInput {
3315    YInput {
3316        tag: Y_JSON_NULL,
3317        len: 0,
3318        value: MaybeUninit::uninit().assume_init(),
3319    }
3320}
3321
3322/// Function constructor used to create JSON-like undefined `YInput` cell.
3323/// This function doesn't allocate any heap resources.
3324#[no_mangle]
3325pub unsafe extern "C" fn yinput_undefined() -> YInput {
3326    YInput {
3327        tag: Y_JSON_UNDEF,
3328        len: 0,
3329        value: MaybeUninit::uninit().assume_init(),
3330    }
3331}
3332
3333/// Function constructor used to create JSON-like boolean `YInput` cell.
3334/// This function doesn't allocate any heap resources.
3335#[no_mangle]
3336pub unsafe extern "C" fn yinput_bool(flag: u8) -> YInput {
3337    YInput {
3338        tag: Y_JSON_BOOL,
3339        len: 1,
3340        value: YInputContent { flag },
3341    }
3342}
3343
3344/// Function constructor used to create JSON-like 64-bit floating point number `YInput` cell.
3345/// This function doesn't allocate any heap resources.
3346#[no_mangle]
3347pub unsafe extern "C" fn yinput_float(num: f64) -> YInput {
3348    YInput {
3349        tag: Y_JSON_NUM,
3350        len: 1,
3351        value: YInputContent { num },
3352    }
3353}
3354
3355/// Function constructor used to create JSON-like 64-bit signed integer `YInput` cell.
3356/// This function doesn't allocate any heap resources.
3357#[no_mangle]
3358pub unsafe extern "C" fn yinput_long(integer: i64) -> YInput {
3359    YInput {
3360        tag: Y_JSON_INT,
3361        len: 1,
3362        value: YInputContent { integer },
3363    }
3364}
3365
3366/// Function constructor used to create a string `YInput` cell. Provided parameter must be
3367/// a null-terminated UTF-8 encoded string. This function doesn't allocate any heap resources,
3368/// and doesn't release any on its own, therefore its up to a caller to free resources once
3369/// a structure is no longer needed.
3370#[no_mangle]
3371pub unsafe extern "C" fn yinput_string(str: *const c_char) -> YInput {
3372    YInput {
3373        tag: Y_JSON_STR,
3374        len: 1,
3375        value: YInputContent {
3376            str: str as *mut c_char,
3377        },
3378    }
3379}
3380
3381/// Function constructor used to create aa `YInput` cell representing any JSON-like object.
3382/// Provided parameter must be a null-terminated UTF-8 encoded JSON string.
3383///
3384/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3385/// its up to a caller to free resources once a structure is no longer needed.
3386#[no_mangle]
3387pub unsafe extern "C" fn yinput_json(str: *const c_char) -> YInput {
3388    YInput {
3389        tag: Y_JSON,
3390        len: 1,
3391        value: YInputContent {
3392            str: str as *mut c_char,
3393        },
3394    }
3395}
3396
3397/// Function constructor used to create a binary `YInput` cell of a specified length.
3398/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3399/// its up to a caller to free resources once a structure is no longer needed.
3400#[no_mangle]
3401pub unsafe extern "C" fn yinput_binary(buf: *const c_char, len: u32) -> YInput {
3402    YInput {
3403        tag: Y_JSON_BUF,
3404        len,
3405        value: YInputContent {
3406            buf: buf as *mut c_char,
3407        },
3408    }
3409}
3410
3411/// Function constructor used to create a JSON-like array `YInput` cell of other JSON-like values of
3412/// a given length. This function doesn't allocate any heap resources and doesn't release any on its
3413/// own, therefore its up to a caller to free resources once a structure is no longer needed.
3414#[no_mangle]
3415pub unsafe extern "C" fn yinput_json_array(values: *mut YInput, len: u32) -> YInput {
3416    YInput {
3417        tag: Y_JSON_ARR,
3418        len,
3419        value: YInputContent { values },
3420    }
3421}
3422
3423/// Function constructor used to create a JSON-like map `YInput` cell of other JSON-like key-value
3424/// pairs. These pairs are build from corresponding indexes of `keys` and `values`, which must have
3425/// the same specified length.
3426///
3427/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3428/// its up to a caller to free resources once a structure is no longer needed.
3429#[no_mangle]
3430pub unsafe extern "C" fn yinput_json_map(
3431    keys: *mut *mut c_char,
3432    values: *mut YInput,
3433    len: u32,
3434) -> YInput {
3435    YInput {
3436        tag: Y_JSON_MAP,
3437        len,
3438        value: YInputContent {
3439            map: ManuallyDrop::new(YMapInputData { keys, values }),
3440        },
3441    }
3442}
3443
3444/// Function constructor used to create a nested `YArray` `YInput` cell prefilled with other
3445/// values of a given length. This function doesn't allocate any heap resources and doesn't release
3446/// any on its own, therefore its up to a caller to free resources once a structure is no longer
3447/// needed.
3448#[no_mangle]
3449pub unsafe extern "C" fn yinput_yarray(values: *mut YInput, len: u32) -> YInput {
3450    YInput {
3451        tag: Y_ARRAY,
3452        len,
3453        value: YInputContent { values },
3454    }
3455}
3456
3457/// Function constructor used to create a nested `YMap` `YInput` cell prefilled with other key-value
3458/// pairs. These pairs are build from corresponding indexes of `keys` and `values`, which must have
3459/// the same specified length.
3460///
3461/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3462/// its up to a caller to free resources once a structure is no longer needed.
3463#[no_mangle]
3464pub unsafe extern "C" fn yinput_ymap(
3465    keys: *mut *mut c_char,
3466    values: *mut YInput,
3467    len: u32,
3468) -> YInput {
3469    YInput {
3470        tag: Y_MAP,
3471        len,
3472        value: YInputContent {
3473            map: ManuallyDrop::new(YMapInputData { keys, values }),
3474        },
3475    }
3476}
3477
3478/// Function constructor used to create a nested `YText` `YInput` cell prefilled with a specified
3479/// string, which must be a null-terminated UTF-8 character pointer.
3480///
3481/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3482/// its up to a caller to free resources once a structure is no longer needed.
3483#[no_mangle]
3484pub unsafe extern "C" fn yinput_ytext(str: *mut c_char) -> YInput {
3485    YInput {
3486        tag: Y_TEXT,
3487        len: 1,
3488        value: YInputContent { str },
3489    }
3490}
3491
3492/// Function constructor used to create a nested `YXmlElement` `YInput` cell with a specified
3493/// tag name, which must be a null-terminated UTF-8 character pointer.
3494///
3495/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3496/// its up to a caller to free resources once a structure is no longer needed.
3497#[no_mangle]
3498pub unsafe extern "C" fn yinput_yxmlelem(name: *mut c_char) -> YInput {
3499    YInput {
3500        tag: Y_XML_ELEM,
3501        len: 1,
3502        value: YInputContent { str: name },
3503    }
3504}
3505
3506/// Function constructor used to create a nested `YXmlText` `YInput` cell prefilled with a specified
3507/// string, which must be a null-terminated UTF-8 character pointer.
3508///
3509/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3510/// its up to a caller to free resources once a structure is no longer needed.
3511#[no_mangle]
3512pub unsafe extern "C" fn yinput_yxmltext(str: *mut c_char) -> YInput {
3513    YInput {
3514        tag: Y_XML_TEXT,
3515        len: 1,
3516        value: YInputContent { str },
3517    }
3518}
3519
3520/// Function constructor used to create a nested `YDoc` `YInput` cell.
3521///
3522/// This function doesn't allocate any heap resources and doesn't release any on its own, therefore
3523/// its up to a caller to free resources once a structure is no longer needed.
3524#[no_mangle]
3525pub unsafe extern "C" fn yinput_ydoc(doc: *mut Doc) -> YInput {
3526    YInput {
3527        tag: Y_DOC,
3528        len: 1,
3529        value: YInputContent { doc },
3530    }
3531}
3532
3533/// Function constructor used to create a string `YInput` cell with weak reference to another
3534/// element(s) living inside of the same document.
3535#[no_mangle]
3536pub unsafe extern "C" fn yinput_weak(weak: *const Weak) -> YInput {
3537    YInput {
3538        tag: Y_WEAK_LINK,
3539        len: 1,
3540        value: YInputContent { weak },
3541    }
3542}
3543
3544/// Attempts to read the value for a given `YOutput` pointer as a `YDocRef` reference to a nested
3545/// document.
3546#[no_mangle]
3547pub unsafe extern "C" fn youtput_read_ydoc(val: *const YOutput) -> *mut Doc {
3548    let v = val.as_ref().unwrap();
3549    if v.tag == Y_DOC {
3550        v.value.y_doc
3551    } else {
3552        std::ptr::null_mut()
3553    }
3554}
3555
3556/// Attempts to read the value for a given `YOutput` pointer as a boolean flag, which can be either
3557/// `1` for truthy case and `0` otherwise. Returns a null pointer in case when a value stored under
3558/// current `YOutput` cell is not of a boolean type.
3559#[no_mangle]
3560pub unsafe extern "C" fn youtput_read_bool(val: *const YOutput) -> *const u8 {
3561    let v = val.as_ref().unwrap();
3562    if v.tag == Y_JSON_BOOL {
3563        &v.value.flag
3564    } else {
3565        std::ptr::null()
3566    }
3567}
3568
3569/// Attempts to read the value for a given `YOutput` pointer as a 64-bit floating point number.
3570///
3571/// Returns a null pointer in case when a value stored under current `YOutput` cell
3572/// is not a floating point number.
3573#[no_mangle]
3574pub unsafe extern "C" fn youtput_read_float(val: *const YOutput) -> *const f64 {
3575    let v = val.as_ref().unwrap();
3576    if v.tag == Y_JSON_NUM {
3577        &v.value.num
3578    } else {
3579        std::ptr::null()
3580    }
3581}
3582
3583/// Attempts to read the value for a given `YOutput` pointer as a 64-bit signed integer.
3584///
3585/// Returns a null pointer in case when a value stored under current `YOutput` cell
3586/// is not a signed integer.
3587#[no_mangle]
3588pub unsafe extern "C" fn youtput_read_long(val: *const YOutput) -> *const i64 {
3589    let v = val.as_ref().unwrap();
3590    if v.tag == Y_JSON_INT {
3591        &v.value.integer
3592    } else {
3593        std::ptr::null()
3594    }
3595}
3596
3597/// Attempts to read the value for a given `YOutput` pointer as a null-terminated UTF-8 encoded
3598/// string.
3599///
3600/// Returns a null pointer in case when a value stored under current `YOutput` cell
3601/// is not a string. Underlying string is released automatically as part of [youtput_destroy]
3602/// destructor.
3603#[no_mangle]
3604pub unsafe extern "C" fn youtput_read_string(val: *const YOutput) -> *mut c_char {
3605    let v = val.as_ref().unwrap();
3606    if v.tag == Y_JSON_STR {
3607        v.value.str
3608    } else {
3609        std::ptr::null_mut()
3610    }
3611}
3612
3613/// Attempts to read the value for a given `YOutput` pointer as a binary payload (which length is
3614/// stored within `len` filed of a cell itself).
3615///
3616/// Returns a null pointer in case when a value stored under current `YOutput` cell
3617/// is not a binary type. Underlying binary is released automatically as part of [youtput_destroy]
3618/// destructor.
3619#[no_mangle]
3620pub unsafe extern "C" fn youtput_read_binary(val: *const YOutput) -> *const c_char {
3621    let v = val.as_ref().unwrap();
3622    if v.tag == Y_JSON_BUF {
3623        v.value.buf
3624    } else {
3625        std::ptr::null()
3626    }
3627}
3628
3629/// Attempts to read the value for a given `YOutput` pointer as a JSON-like array of `YOutput`
3630/// values (which length is stored within `len` filed of a cell itself).
3631///
3632/// Returns a null pointer in case when a value stored under current `YOutput` cell
3633/// is not a JSON-like array. Underlying heap resources are released automatically as part of
3634/// [youtput_destroy] destructor.
3635#[no_mangle]
3636pub unsafe extern "C" fn youtput_read_json_array(val: *const YOutput) -> *mut YOutput {
3637    let v = val.as_ref().unwrap();
3638    if v.tag == Y_JSON_ARR {
3639        v.value.array
3640    } else {
3641        std::ptr::null_mut()
3642    }
3643}
3644
3645/// Attempts to read the value for a given `YOutput` pointer as a JSON-like map of key-value entries
3646/// (which length is stored within `len` filed of a cell itself).
3647///
3648/// Returns a null pointer in case when a value stored under current `YOutput` cell
3649/// is not a JSON-like map. Underlying heap resources are released automatically as part of
3650/// [youtput_destroy] destructor.
3651#[no_mangle]
3652pub unsafe extern "C" fn youtput_read_json_map(val: *const YOutput) -> *mut YMapEntry {
3653    let v = val.as_ref().unwrap();
3654    if v.tag == Y_JSON_MAP {
3655        v.value.map
3656    } else {
3657        std::ptr::null_mut()
3658    }
3659}
3660
3661/// Attempts to read the value for a given `YOutput` pointer as an `YArray`.
3662///
3663/// Returns a null pointer in case when a value stored under current `YOutput` cell
3664/// is not an `YArray`. Underlying heap resources are released automatically as part of
3665/// [youtput_destroy] destructor.
3666#[no_mangle]
3667pub unsafe extern "C" fn youtput_read_yarray(val: *const YOutput) -> *mut Branch {
3668    let v = val.as_ref().unwrap();
3669    if v.tag == Y_ARRAY {
3670        v.value.y_type
3671    } else {
3672        std::ptr::null_mut()
3673    }
3674}
3675
3676/// Attempts to read the value for a given `YOutput` pointer as an `YXmlElement`.
3677///
3678/// Returns a null pointer in case when a value stored under current `YOutput` cell
3679/// is not an `YXmlElement`. Underlying heap resources are released automatically as part of
3680/// [youtput_destroy] destructor.
3681#[no_mangle]
3682pub unsafe extern "C" fn youtput_read_yxmlelem(val: *const YOutput) -> *mut Branch {
3683    let v = val.as_ref().unwrap();
3684    if v.tag == Y_XML_ELEM {
3685        v.value.y_type
3686    } else {
3687        std::ptr::null_mut()
3688    }
3689}
3690
3691/// Attempts to read the value for a given `YOutput` pointer as an `YMap`.
3692///
3693/// Returns a null pointer in case when a value stored under current `YOutput` cell
3694/// is not an `YMap`. Underlying heap resources are released automatically as part of
3695/// [youtput_destroy] destructor.
3696#[no_mangle]
3697pub unsafe extern "C" fn youtput_read_ymap(val: *const YOutput) -> *mut Branch {
3698    let v = val.as_ref().unwrap();
3699    if v.tag == Y_MAP {
3700        v.value.y_type
3701    } else {
3702        std::ptr::null_mut()
3703    }
3704}
3705
3706/// Attempts to read the value for a given `YOutput` pointer as an `YText`.
3707///
3708/// Returns a null pointer in case when a value stored under current `YOutput` cell
3709/// is not an `YText`. Underlying heap resources are released automatically as part of
3710/// [youtput_destroy] destructor.
3711#[no_mangle]
3712pub unsafe extern "C" fn youtput_read_ytext(val: *const YOutput) -> *mut Branch {
3713    let v = val.as_ref().unwrap();
3714    if v.tag == Y_TEXT {
3715        v.value.y_type
3716    } else {
3717        std::ptr::null_mut()
3718    }
3719}
3720
3721/// Attempts to read the value for a given `YOutput` pointer as an `YXmlText`.
3722///
3723/// Returns a null pointer in case when a value stored under current `YOutput` cell
3724/// is not an `YXmlText`. Underlying heap resources are released automatically as part of
3725/// [youtput_destroy] destructor.
3726#[no_mangle]
3727pub unsafe extern "C" fn youtput_read_yxmltext(val: *const YOutput) -> *mut Branch {
3728    let v = val.as_ref().unwrap();
3729    if v.tag == Y_XML_TEXT {
3730        v.value.y_type
3731    } else {
3732        std::ptr::null_mut()
3733    }
3734}
3735
3736/// Attempts to read the value for a given `YOutput` pointer as an `YWeakRef`.
3737///
3738/// Returns a null pointer in case when a value stored under current `YOutput` cell
3739/// is not an `YWeakRef`. Underlying heap resources are released automatically as part of
3740/// [youtput_destroy] destructor.
3741#[no_mangle]
3742pub unsafe extern "C" fn youtput_read_yweak(val: *const YOutput) -> *mut Branch {
3743    let v = val.as_ref().unwrap();
3744    if v.tag == Y_WEAK_LINK {
3745        v.value.y_type
3746    } else {
3747        std::ptr::null_mut()
3748    }
3749}
3750
3751/// Unsubscribe callback from the oberver event it was previously subscribed to.
3752#[no_mangle]
3753pub unsafe extern "C" fn yunobserve(subscription: *mut Subscription) {
3754    drop(unsafe { Box::from_raw(subscription) })
3755}
3756
3757/// Subscribes a given callback function `cb` to changes made by this `YText` instance. Callbacks
3758/// are triggered whenever a `ytransaction_commit` is called.
3759/// Returns a subscription ID which can be then used to unsubscribe this callback by using
3760/// `yunobserve` function.
3761#[no_mangle]
3762pub unsafe extern "C" fn ytext_observe(
3763    txt: *const Branch,
3764    state: *mut c_void,
3765    cb: extern "C" fn(*mut c_void, *const YTextEvent),
3766) -> *mut Subscription {
3767    assert!(!txt.is_null());
3768    let state = CallbackState::new(state);
3769
3770    let txt = TextRef::from_raw_branch(txt);
3771    let subscription = txt.observe(move |txn, e| {
3772        let e = YTextEvent::new(e, txn);
3773        cb(state.0, &e as *const YTextEvent);
3774    });
3775    Box::into_raw(Box::new(subscription))
3776}
3777
3778/// Subscribes a given callback function `cb` to changes made by this `YMap` instance. Callbacks
3779/// are triggered whenever a `ytransaction_commit` is called.
3780/// Returns a subscription ID which can be then used to unsubscribe this callback by using
3781/// `yunobserve` function.
3782#[no_mangle]
3783pub unsafe extern "C" fn ymap_observe(
3784    map: *const Branch,
3785    state: *mut c_void,
3786    cb: extern "C" fn(*mut c_void, *const YMapEvent),
3787) -> *mut Subscription {
3788    assert!(!map.is_null());
3789    let state = CallbackState::new(state);
3790
3791    let map = MapRef::from_raw_branch(map);
3792    let subscription = map.observe(move |txn, e| {
3793        let e = YMapEvent::new(e, txn);
3794        cb(state.0, &e as *const YMapEvent);
3795    });
3796    Box::into_raw(Box::new(subscription))
3797}
3798
3799/// Subscribes a given callback function `cb` to changes made by this `YArray` instance. Callbacks
3800/// are triggered whenever a `ytransaction_commit` is called.
3801/// Returns a subscription ID which can be then used to unsubscribe this callback by using
3802/// `yunobserve` function.
3803#[no_mangle]
3804pub unsafe extern "C" fn yarray_observe(
3805    array: *const Branch,
3806    state: *mut c_void,
3807    cb: extern "C" fn(*mut c_void, *const YArrayEvent),
3808) -> *mut Subscription {
3809    assert!(!array.is_null());
3810    let state = CallbackState::new(state);
3811
3812    let array = ArrayRef::from_raw_branch(array);
3813    let subscription = array.observe(move |txn, e| {
3814        let e = YArrayEvent::new(e, txn);
3815        cb(state.0, &e as *const YArrayEvent);
3816    });
3817    Box::into_raw(Box::new(subscription))
3818}
3819
3820/// Subscribes a given callback function `cb` to changes made by this `YXmlElement` instance.
3821/// Callbacks are triggered whenever a `ytransaction_commit` is called.
3822/// Returns a subscription ID which can be then used to unsubscribe this callback by using
3823/// `yunobserve` function.
3824#[no_mangle]
3825pub unsafe extern "C" fn yxmlelem_observe(
3826    xml: *const Branch,
3827    state: *mut c_void,
3828    cb: extern "C" fn(*mut c_void, *const YXmlEvent),
3829) -> *mut Subscription {
3830    assert!(!xml.is_null());
3831    let state = CallbackState::new(state);
3832
3833    let xml = XmlElementRef::from_raw_branch(xml);
3834    let subscription = xml.observe(move |txn, e| {
3835        let e = YXmlEvent::new(e, txn);
3836        cb(state.0, &e as *const YXmlEvent);
3837    });
3838    Box::into_raw(Box::new(subscription))
3839}
3840
3841/// Subscribes a given callback function `cb` to changes made by this `YXmlText` instance. Callbacks
3842/// are triggered whenever a `ytransaction_commit` is called.
3843/// Returns a subscription ID which can be then used to unsubscribe this callback by using
3844/// `yunobserve` function.
3845#[no_mangle]
3846pub unsafe extern "C" fn yxmltext_observe(
3847    xml: *const Branch,
3848    state: *mut c_void,
3849    cb: extern "C" fn(*mut c_void, *const YXmlTextEvent),
3850) -> *mut Subscription {
3851    assert!(!xml.is_null());
3852
3853    let state = CallbackState::new(state);
3854    let xml = XmlTextRef::from_raw_branch(xml);
3855    let subscription = xml.observe(move |txn, e| {
3856        let e = YXmlTextEvent::new(e, txn);
3857        cb(state.0, &e as *const YXmlTextEvent);
3858    });
3859    Box::into_raw(Box::new(subscription))
3860}
3861
3862/// Subscribes a given callback function `cb` to changes made by this shared type instance as well
3863/// as all nested shared types living within it. Callbacks are triggered whenever a
3864/// `ytransaction_commit` is called.
3865///
3866/// Returns a subscription ID which can be then used to unsubscribe this callback by using
3867/// `yunobserve` function.
3868#[no_mangle]
3869pub unsafe extern "C" fn yobserve_deep(
3870    ytype: *mut Branch,
3871    state: *mut c_void,
3872    cb: extern "C" fn(*mut c_void, u32, *const YEvent),
3873) -> *mut Subscription {
3874    assert!(!ytype.is_null());
3875
3876    let state = CallbackState::new(state);
3877    let branch = ytype.as_mut().unwrap();
3878    let subscription = branch.observe_deep(move |txn, events| {
3879        let events: Vec<_> = events.iter().map(|e| YEvent::new(txn, e)).collect();
3880        let len = events.len() as u32;
3881        cb(state.0, len, events.as_ptr());
3882    });
3883    Box::into_raw(Box::new(subscription))
3884}
3885
3886/// Event generated for callbacks subscribed using `ydoc_observe_after_transaction`. It contains
3887/// snapshot of changes made within any committed transaction.
3888#[repr(C)]
3889pub struct YAfterTransactionEvent {
3890    /// Descriptor of a document state at the moment of creating the transaction.
3891    pub before_state: YStateVector,
3892    /// Descriptor of a document state at the moment of committing the transaction.
3893    pub after_state: YStateVector,
3894    /// Information about all items deleted within the scope of a transaction.
3895    pub delete_set: YIdSet,
3896}
3897
3898impl YAfterTransactionEvent {
3899    unsafe fn new(e: &TransactionCleanupEvent) -> Self {
3900        YAfterTransactionEvent {
3901            before_state: YStateVector::new(&e.before_state),
3902            after_state: YStateVector::new(&e.after_state),
3903            delete_set: YIdSet::new(&e.delete_set),
3904        }
3905    }
3906}
3907
3908#[repr(C)]
3909pub struct YSubdocsEvent {
3910    added_len: u32,
3911    removed_len: u32,
3912    loaded_len: u32,
3913    added: *mut *mut Doc,
3914    removed: *mut *mut Doc,
3915    loaded: *mut *mut Doc,
3916}
3917
3918impl YSubdocsEvent {
3919    unsafe fn new(e: &SubdocsEvent) -> Self {
3920        fn into_ptr(v: SubdocsEventIter) -> *mut *mut Doc {
3921            let array: Vec<_> = v.map(|doc| Box::into_raw(Box::new(doc.clone()))).collect();
3922            let mut boxed = array.into_boxed_slice();
3923            let ptr = boxed.as_mut_ptr();
3924            forget(boxed);
3925            ptr
3926        }
3927
3928        let added = e.added();
3929        let removed = e.removed();
3930        let loaded = e.loaded();
3931
3932        YSubdocsEvent {
3933            added_len: added.len() as u32,
3934            removed_len: removed.len() as u32,
3935            loaded_len: loaded.len() as u32,
3936            added: into_ptr(added),
3937            removed: into_ptr(removed),
3938            loaded: into_ptr(loaded),
3939        }
3940    }
3941}
3942
3943impl Drop for YSubdocsEvent {
3944    fn drop(&mut self) {
3945        fn release(len: u32, buf: *mut *mut Doc) {
3946            unsafe {
3947                let docs = Vec::from_raw_parts(buf, len as usize, len as usize);
3948                for d in docs {
3949                    drop(Box::from_raw(d));
3950                }
3951            }
3952        }
3953
3954        release(self.added_len, self.added);
3955        release(self.removed_len, self.removed);
3956        release(self.loaded_len, self.loaded);
3957    }
3958}
3959
3960/// Struct representing a state of a document. It contains the last seen clocks for blocks submitted
3961/// per any of the clients collaborating on document updates.
3962#[repr(C)]
3963pub struct YStateVector {
3964    /// Number of clients. It describes a length of both `client_ids` and `clocks` arrays.
3965    pub entries_count: u32,
3966    /// Array of unique client identifiers (length is given in `entries_count` field). Each client
3967    /// ID has corresponding clock attached, which can be found in `clocks` field under the same
3968    /// index.
3969    pub client_ids: *mut u64,
3970    /// Array of clocks (length is given in `entries_count` field) known for each client. Each clock
3971    /// has a corresponding client identifier attached, which can be found in `client_ids` field
3972    /// under the same index.
3973    pub clocks: *mut u32,
3974}
3975
3976impl YStateVector {
3977    unsafe fn new(sv: &StateVector) -> Self {
3978        let entries_count = sv.len() as u32;
3979        let mut client_ids = Vec::with_capacity(sv.len());
3980        let mut clocks = Vec::with_capacity(sv.len());
3981        for (&client, &clock) in sv.iter() {
3982            client_ids.push(client.get());
3983            clocks.push(clock as u32);
3984        }
3985
3986        YStateVector {
3987            entries_count,
3988            client_ids: Box::into_raw(client_ids.into_boxed_slice()) as *mut _,
3989            clocks: Box::into_raw(clocks.into_boxed_slice()) as *mut _,
3990        }
3991    }
3992}
3993
3994impl Drop for YStateVector {
3995    fn drop(&mut self) {
3996        let len = self.entries_count as usize;
3997        drop(unsafe { Vec::from_raw_parts(self.client_ids, len, len) });
3998        drop(unsafe { Vec::from_raw_parts(self.clocks, len, len) });
3999    }
4000}
4001
4002/// Delete set is a map of `(ClientID, Range[])` entries. Length of a map is stored in
4003/// `entries_count` field. ClientIDs reside under `client_ids` and their corresponding range
4004/// sequences can be found under the same index of `ranges` field.
4005#[repr(C)]
4006pub struct YIdSet {
4007    /// Number of client identifier entries.
4008    pub entries_count: u32,
4009    /// Array of unique client identifiers (length is given in `entries_count` field). Each client
4010    /// ID has corresponding sequence of ranges attached, which can be found in `ranges` field under
4011    /// the same index.
4012    pub client_ids: *mut u64,
4013    /// Array of range sequences (length is given in `entries_count` field). Each sequence has
4014    /// a corresponding client ID attached, which can be found in `client_ids` field under
4015    /// the same index.
4016    pub ranges: *mut YIdRangeSeq,
4017}
4018
4019impl YIdSet {
4020    unsafe fn new(ds: &IdSet) -> Self {
4021        let len = ds.len();
4022        let mut client_ids = Vec::with_capacity(len);
4023        let mut ranges = Vec::with_capacity(len);
4024
4025        for (&client, range) in ds.iter() {
4026            client_ids.push(client.get());
4027            let seq: Vec<_> = range
4028                .iter()
4029                .map(|r| YIdRange {
4030                    start: r.start as u32,
4031                    end: r.end as u32,
4032                })
4033                .collect();
4034            ranges.push(YIdRangeSeq {
4035                len: seq.len() as u32,
4036                seq: Box::into_raw(seq.into_boxed_slice()) as *mut _,
4037            })
4038        }
4039
4040        YIdSet {
4041            entries_count: len as u32,
4042            client_ids: Box::into_raw(client_ids.into_boxed_slice()) as *mut _,
4043            ranges: Box::into_raw(ranges.into_boxed_slice()) as *mut _,
4044        }
4045    }
4046}
4047
4048impl Drop for YIdSet {
4049    fn drop(&mut self) {
4050        let len = self.entries_count as usize;
4051        drop(unsafe { Vec::from_raw_parts(self.client_ids, len, len) });
4052        drop(unsafe { Vec::from_raw_parts(self.ranges, len, len) });
4053    }
4054}
4055
4056/// Fixed-length sequence of ID ranges. Each range is a pair of [start, end) values, describing the
4057/// range of items identified by clock values, that this range refers to.
4058#[repr(C)]
4059pub struct YIdRangeSeq {
4060    /// Number of ranges stored in this sequence.
4061    pub len: u32,
4062    /// Array (length is stored in `len` field) or ranges. Each range is a pair of [start, end)
4063    /// values, describing continuous collection of items produced by the same client, identified
4064    /// by clock values, that this range refers to.
4065    pub seq: *mut YIdRange,
4066}
4067
4068impl Drop for YIdRangeSeq {
4069    fn drop(&mut self) {
4070        let len = self.len as usize;
4071        drop(unsafe { Vec::from_raw_parts(self.seq, len, len) })
4072    }
4073}
4074
4075#[repr(C)]
4076pub struct YIdRange {
4077    pub start: u32,
4078    pub end: u32,
4079}
4080
4081#[repr(C)]
4082pub struct YEvent {
4083    /// Tag describing, which shared type emitted this event.
4084    ///
4085    /// - [Y_TEXT] for pointers to `YText` data types.
4086    /// - [Y_ARRAY] for pointers to `YArray` data types.
4087    /// - [Y_MAP] for pointers to `YMap` data types.
4088    /// - [Y_XML_ELEM] for pointers to `YXmlElement` data types.
4089    /// - [Y_XML_TEXT] for pointers to `YXmlText` data types.
4090    pub tag: i8,
4091
4092    /// A nested event type, specific for a shared data type that triggered it. Type of an
4093    /// event can be verified using `tag` field.
4094    pub content: YEventContent,
4095}
4096
4097impl YEvent {
4098    fn new<'doc>(txn: &yrs::TransactionMut<'doc>, e: &Event) -> YEvent {
4099        match e {
4100            Event::Text(e) => YEvent {
4101                tag: Y_TEXT,
4102                content: YEventContent {
4103                    text: YTextEvent::new(e, txn),
4104                },
4105            },
4106            Event::Array(e) => YEvent {
4107                tag: Y_ARRAY,
4108                content: YEventContent {
4109                    array: YArrayEvent::new(e, txn),
4110                },
4111            },
4112            Event::Map(e) => YEvent {
4113                tag: Y_MAP,
4114                content: YEventContent {
4115                    map: YMapEvent::new(e, txn),
4116                },
4117            },
4118            Event::XmlFragment(e) => YEvent {
4119                tag: if let XmlOut::Fragment(_) = e.target() {
4120                    Y_XML_FRAG
4121                } else {
4122                    Y_XML_ELEM
4123                },
4124                content: YEventContent {
4125                    xml_elem: YXmlEvent::new(e, txn),
4126                },
4127            },
4128            Event::XmlText(e) => YEvent {
4129                tag: Y_XML_TEXT,
4130                content: YEventContent {
4131                    xml_text: YXmlTextEvent::new(e, txn),
4132                },
4133            },
4134            Event::Weak(e) => YEvent {
4135                tag: Y_WEAK_LINK,
4136                content: YEventContent {
4137                    weak: YWeakLinkEvent::new(e, txn),
4138                },
4139            },
4140        }
4141    }
4142}
4143
4144#[repr(C)]
4145pub union YEventContent {
4146    pub text: YTextEvent,
4147    pub map: YMapEvent,
4148    pub array: YArrayEvent,
4149    pub xml_elem: YXmlEvent,
4150    pub xml_text: YXmlTextEvent,
4151    pub weak: YWeakLinkEvent,
4152}
4153
4154/// Event pushed into callbacks registered with `ytext_observe` function. It contains delta of all
4155/// text changes made within a scope of corresponding transaction (see: `ytext_event_delta`) as
4156/// well as navigation data used to identify a `YText` instance which triggered this event.
4157#[repr(C)]
4158#[derive(Copy, Clone)]
4159pub struct YTextEvent {
4160    inner: *const c_void,
4161    txn: *const yrs::TransactionMut<'static>,
4162}
4163
4164impl YTextEvent {
4165    fn new<'dev>(inner: &TextEvent, txn: &yrs::TransactionMut<'dev>) -> Self {
4166        let inner = inner as *const TextEvent as *const _;
4167        let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
4168        let txn = txn as *const _;
4169        YTextEvent { inner, txn }
4170    }
4171
4172    fn txn(&self) -> &yrs::TransactionMut {
4173        unsafe { self.txn.as_ref().unwrap() }
4174    }
4175}
4176
4177impl Deref for YTextEvent {
4178    type Target = TextEvent;
4179
4180    fn deref(&self) -> &Self::Target {
4181        unsafe { (self.inner as *const TextEvent).as_ref().unwrap() }
4182    }
4183}
4184
4185/// Event pushed into callbacks registered with `yarray_observe` function. It contains delta of all
4186/// content changes made within a scope of corresponding transaction (see: `yarray_event_delta`) as
4187/// well as navigation data used to identify a `YArray` instance which triggered this event.
4188#[repr(C)]
4189#[derive(Copy, Clone)]
4190pub struct YArrayEvent {
4191    inner: *const c_void,
4192    txn: *const yrs::TransactionMut<'static>,
4193}
4194
4195impl YArrayEvent {
4196    fn new<'doc>(inner: &ArrayEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
4197        let inner = inner as *const ArrayEvent as *const _;
4198        let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
4199        let txn = txn as *const _;
4200        YArrayEvent { inner, txn }
4201    }
4202
4203    fn txn(&self) -> &yrs::TransactionMut {
4204        unsafe { self.txn.as_ref().unwrap() }
4205    }
4206}
4207
4208impl Deref for YArrayEvent {
4209    type Target = ArrayEvent;
4210
4211    fn deref(&self) -> &Self::Target {
4212        unsafe { (self.inner as *const ArrayEvent).as_ref().unwrap() }
4213    }
4214}
4215
4216/// Event pushed into callbacks registered with `ymap_observe` function. It contains all
4217/// key-value changes made within a scope of corresponding transaction (see: `ymap_event_keys`) as
4218/// well as navigation data used to identify a `YMap` instance which triggered this event.
4219#[repr(C)]
4220#[derive(Copy, Clone)]
4221pub struct YMapEvent {
4222    inner: *const c_void,
4223    txn: *const yrs::TransactionMut<'static>,
4224}
4225
4226impl YMapEvent {
4227    fn new<'doc>(inner: &MapEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
4228        let inner = inner as *const MapEvent as *const _;
4229        let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
4230        let txn = txn as *const _;
4231        YMapEvent { inner, txn }
4232    }
4233
4234    fn txn(&self) -> &yrs::TransactionMut<'static> {
4235        unsafe { self.txn.as_ref().unwrap() }
4236    }
4237}
4238
4239impl Deref for YMapEvent {
4240    type Target = MapEvent;
4241
4242    fn deref(&self) -> &Self::Target {
4243        unsafe { (self.inner as *const MapEvent).as_ref().unwrap() }
4244    }
4245}
4246
4247/// Event pushed into callbacks registered with `yxmlelem_observe` function. It contains
4248/// all attribute changes made within a scope of corresponding transaction
4249/// (see: `yxmlelem_event_keys`) as well as child XML nodes changes (see: `yxmlelem_event_delta`)
4250/// and navigation data used to identify a `YXmlElement` instance which triggered this event.
4251#[repr(C)]
4252#[derive(Copy, Clone)]
4253pub struct YXmlEvent {
4254    inner: *const c_void,
4255    txn: *const yrs::TransactionMut<'static>,
4256}
4257
4258impl YXmlEvent {
4259    fn new<'doc>(inner: &XmlEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
4260        let inner = inner as *const XmlEvent as *const _;
4261        let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
4262        let txn = txn as *const _;
4263        YXmlEvent { inner, txn }
4264    }
4265
4266    fn txn(&self) -> &yrs::TransactionMut<'static> {
4267        unsafe { self.txn.as_ref().unwrap() }
4268    }
4269}
4270
4271impl Deref for YXmlEvent {
4272    type Target = XmlEvent;
4273
4274    fn deref(&self) -> &Self::Target {
4275        unsafe { (self.inner as *const XmlEvent).as_ref().unwrap() }
4276    }
4277}
4278
4279/// Event pushed into callbacks registered with `yxmltext_observe` function. It contains
4280/// all attribute changes made within a scope of corresponding transaction
4281/// (see: `yxmltext_event_keys`) as well as text edits (see: `yxmltext_event_delta`)
4282/// and navigation data used to identify a `YXmlText` instance which triggered this event.
4283#[repr(C)]
4284#[derive(Copy, Clone)]
4285pub struct YXmlTextEvent {
4286    inner: *const c_void,
4287    txn: *const yrs::TransactionMut<'static>,
4288}
4289
4290impl YXmlTextEvent {
4291    fn new<'doc>(inner: &XmlTextEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
4292        let inner = inner as *const XmlTextEvent as *const _;
4293        let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
4294        let txn = txn as *const _;
4295        YXmlTextEvent { inner, txn }
4296    }
4297
4298    fn txn(&self) -> &yrs::TransactionMut<'static> {
4299        unsafe { self.txn.as_ref().unwrap() }
4300    }
4301}
4302
4303impl Deref for YXmlTextEvent {
4304    type Target = XmlTextEvent;
4305
4306    fn deref(&self) -> &Self::Target {
4307        unsafe { (self.inner as *const XmlTextEvent).as_ref().unwrap() }
4308    }
4309}
4310
4311/// Event pushed into callbacks registered with `yweak_observe` function. It contains
4312/// all an event changes of the underlying transaction.
4313#[repr(C)]
4314#[derive(Copy, Clone)]
4315pub struct YWeakLinkEvent {
4316    inner: *const c_void,
4317    txn: *const yrs::TransactionMut<'static>,
4318}
4319
4320impl YWeakLinkEvent {
4321    fn new<'doc>(inner: &WeakEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
4322        let inner = inner as *const WeakEvent as *const _;
4323        let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
4324        let txn = txn as *const _;
4325        YWeakLinkEvent { inner, txn }
4326    }
4327}
4328
4329impl Deref for YWeakLinkEvent {
4330    type Target = WeakEvent;
4331
4332    fn deref(&self) -> &Self::Target {
4333        unsafe { (self.inner as *const WeakEvent).as_ref().unwrap() }
4334    }
4335}
4336
4337/// Returns a pointer to a shared collection, which triggered passed event `e`.
4338#[no_mangle]
4339pub unsafe extern "C" fn ytext_event_target(e: *const YTextEvent) -> *mut Branch {
4340    assert!(!e.is_null());
4341    let out = (&*e).target().clone();
4342    out.into_raw_branch()
4343}
4344
4345/// Returns a pointer to a shared collection, which triggered passed event `e`.
4346#[no_mangle]
4347pub unsafe extern "C" fn yarray_event_target(e: *const YArrayEvent) -> *mut Branch {
4348    assert!(!e.is_null());
4349    let out = (&*e).target().clone();
4350    out.into_raw_branch()
4351}
4352
4353/// Returns a pointer to a shared collection, which triggered passed event `e`.
4354#[no_mangle]
4355pub unsafe extern "C" fn ymap_event_target(e: *const YMapEvent) -> *mut Branch {
4356    assert!(!e.is_null());
4357    let out = (&*e).target().clone();
4358    out.into_raw_branch()
4359}
4360
4361/// Returns a pointer to a shared collection, which triggered passed event `e`.
4362#[no_mangle]
4363pub unsafe extern "C" fn yxmlelem_event_target(e: *const YXmlEvent) -> *mut Branch {
4364    assert!(!e.is_null());
4365    let out = (&*e).target().clone();
4366    match out {
4367        XmlOut::Element(e) => e.into_raw_branch(),
4368        XmlOut::Fragment(e) => e.into_raw_branch(),
4369        XmlOut::Text(e) => e.into_raw_branch(),
4370    }
4371}
4372
4373/// Returns a pointer to a shared collection, which triggered passed event `e`.
4374#[no_mangle]
4375pub unsafe extern "C" fn yxmltext_event_target(e: *const YXmlTextEvent) -> *mut Branch {
4376    assert!(!e.is_null());
4377    let out = (&*e).target().clone();
4378    out.into_raw_branch()
4379}
4380
4381/// Returns a path from a root type down to a current shared collection (which can be obtained using
4382/// `ytext_event_target` function). It can consist of either integer indexes (used by sequence
4383/// components) or *char keys (used by map components). `len` output parameter is used to provide
4384/// information about length of the path.
4385///
4386/// Path returned this way should be eventually released using `ypath_destroy`.
4387#[no_mangle]
4388pub unsafe extern "C" fn ytext_event_path(
4389    e: *const YTextEvent,
4390    len: *mut u32,
4391) -> *mut YPathSegment {
4392    assert!(!e.is_null());
4393    let e = &*e;
4394    let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
4395    let out = path.into_boxed_slice();
4396    *len = out.len() as u32;
4397    Box::into_raw(out) as *mut _
4398}
4399
4400/// Returns a path from a root type down to a current shared collection (which can be obtained using
4401/// `ymap_event_target` function). It can consist of either integer indexes (used by sequence
4402/// components) or *char keys (used by map components). `len` output parameter is used to provide
4403/// information about length of the path.
4404///
4405/// Path returned this way should be eventually released using `ypath_destroy`.
4406#[no_mangle]
4407pub unsafe extern "C" fn ymap_event_path(e: *const YMapEvent, len: *mut u32) -> *mut YPathSegment {
4408    assert!(!e.is_null());
4409    let e = &*e;
4410    let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
4411    let out = path.into_boxed_slice();
4412    *len = out.len() as u32;
4413    Box::into_raw(out) as *mut _
4414}
4415
4416/// Returns a path from a root type down to a current shared collection (which can be obtained using
4417/// `yxmlelem_event_path` function). It can consist of either integer indexes (used by sequence
4418/// components) or *char keys (used by map components). `len` output parameter is used to provide
4419/// information about length of the path.
4420///
4421/// Path returned this way should be eventually released using `ypath_destroy`.
4422#[no_mangle]
4423pub unsafe extern "C" fn yxmlelem_event_path(
4424    e: *const YXmlEvent,
4425    len: *mut u32,
4426) -> *mut YPathSegment {
4427    assert!(!e.is_null());
4428    let e = &*e;
4429    let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
4430    let out = path.into_boxed_slice();
4431    *len = out.len() as u32;
4432    Box::into_raw(out) as *mut _
4433}
4434
4435/// Returns a path from a root type down to a current shared collection (which can be obtained using
4436/// `yxmltext_event_path` function). It can consist of either integer indexes (used by sequence
4437/// components) or *char keys (used by map components). `len` output parameter is used to provide
4438/// information about length of the path.
4439///
4440/// Path returned this way should be eventually released using `ypath_destroy`.
4441#[no_mangle]
4442pub unsafe extern "C" fn yxmltext_event_path(
4443    e: *const YXmlTextEvent,
4444    len: *mut u32,
4445) -> *mut YPathSegment {
4446    assert!(!e.is_null());
4447    let e = &*e;
4448    let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
4449    let out = path.into_boxed_slice();
4450    *len = out.len() as u32;
4451    Box::into_raw(out) as *mut _
4452}
4453
4454/// Returns a path from a root type down to a current shared collection (which can be obtained using
4455/// `yarray_event_target` function). It can consist of either integer indexes (used by sequence
4456/// components) or *char keys (used by map components). `len` output parameter is used to provide
4457/// information about length of the path.
4458///
4459/// Path returned this way should be eventually released using `ypath_destroy`.
4460#[no_mangle]
4461pub unsafe extern "C" fn yarray_event_path(
4462    e: *const YArrayEvent,
4463    len: *mut u32,
4464) -> *mut YPathSegment {
4465    assert!(!e.is_null());
4466    let e = &*e;
4467    let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
4468    let out = path.into_boxed_slice();
4469    *len = out.len() as u32;
4470    Box::into_raw(out) as *mut _
4471}
4472
4473/// Releases allocated memory used by objects returned from path accessor functions of shared type
4474/// events.
4475#[no_mangle]
4476pub unsafe extern "C" fn ypath_destroy(path: *mut YPathSegment, len: u32) {
4477    if !path.is_null() {
4478        drop(Vec::from_raw_parts(path, len as usize, len as usize));
4479    }
4480}
4481
4482/// Returns a sequence of changes produced by sequence component of shared collections (such as
4483/// `YText`, `YXmlText` and XML nodes added to `YXmlElement`). `len` output parameter is used to
4484/// provide information about number of changes produced.
4485///
4486/// Delta returned from this function should eventually be released using `ytext_delta_destroy`
4487/// function.
4488#[no_mangle]
4489pub unsafe extern "C" fn ytext_event_delta(e: *const YTextEvent, len: *mut u32) -> *mut YDeltaOut {
4490    assert!(!e.is_null());
4491    let e = &*e;
4492    let delta: Vec<_> = e.delta(e.txn()).into_iter().map(YDeltaOut::from).collect();
4493
4494    let out = delta.into_boxed_slice();
4495    *len = out.len() as u32;
4496    Box::into_raw(out) as *mut _
4497}
4498
4499/// Returns a sequence of changes produced by sequence component of shared collections (such as
4500/// `YText`, `YXmlText` and XML nodes added to `YXmlElement`). `len` output parameter is used to
4501/// provide information about number of changes produced.
4502///
4503/// Delta returned from this function should eventually be released using `ytext_delta_destroy`
4504/// function.
4505#[no_mangle]
4506pub unsafe extern "C" fn yxmltext_event_delta(
4507    e: *const YXmlTextEvent,
4508    len: *mut u32,
4509) -> *mut YDeltaOut {
4510    assert!(!e.is_null());
4511    let e = &*e;
4512    let delta: Vec<_> = e.delta(e.txn()).into_iter().map(YDeltaOut::from).collect();
4513
4514    let out = delta.into_boxed_slice();
4515    *len = out.len() as u32;
4516    Box::into_raw(out) as *mut _
4517}
4518
4519/// Returns a sequence of changes produced by sequence component of shared collections (such as
4520/// `YText`, `YXmlText` and XML nodes added to `YXmlElement`). `len` output parameter is used to
4521/// provide information about number of changes produced.
4522///
4523/// Delta returned from this function should eventually be released using `yevent_delta_destroy`
4524/// function.
4525#[no_mangle]
4526pub unsafe extern "C" fn yarray_event_delta(
4527    e: *const YArrayEvent,
4528    len: *mut u32,
4529) -> *mut YEventChange {
4530    assert!(!e.is_null());
4531    let e = &*e;
4532    let delta: Vec<_> = e
4533        .delta(e.txn())
4534        .into_iter()
4535        .map(YEventChange::from)
4536        .collect();
4537
4538    let out = delta.into_boxed_slice();
4539    *len = out.len() as u32;
4540    Box::into_raw(out) as *mut _
4541}
4542
4543/// Returns a sequence of changes produced by sequence component of shared collections (such as
4544/// `YText`, `YXmlText` and XML nodes added to `YXmlElement`). `len` output parameter is used to
4545/// provide information about number of changes produced.
4546///
4547/// Delta returned from this function should eventually be released using `yevent_delta_destroy`
4548/// function.
4549#[no_mangle]
4550pub unsafe extern "C" fn yxmlelem_event_delta(
4551    e: *const YXmlEvent,
4552    len: *mut u32,
4553) -> *mut YEventChange {
4554    assert!(!e.is_null());
4555    let e = &*e;
4556    let delta: Vec<_> = e
4557        .delta(e.txn())
4558        .into_iter()
4559        .map(YEventChange::from)
4560        .collect();
4561
4562    let out = delta.into_boxed_slice();
4563    *len = out.len() as u32;
4564    Box::into_raw(out) as *mut _
4565}
4566
4567/// Releases memory allocated by the object returned from `ytext_delta` function.
4568#[no_mangle]
4569pub unsafe extern "C" fn ytext_delta_destroy(delta: *mut YDeltaOut, len: u32) {
4570    if !delta.is_null() {
4571        let delta = Vec::from_raw_parts(delta, len as usize, len as usize);
4572        drop(delta);
4573    }
4574}
4575
4576/// Releases memory allocated by the object returned from `yevent_delta` function.
4577#[no_mangle]
4578pub unsafe extern "C" fn yevent_delta_destroy(delta: *mut YEventChange, len: u32) {
4579    if !delta.is_null() {
4580        let delta = Vec::from_raw_parts(delta, len as usize, len as usize);
4581        drop(delta);
4582    }
4583}
4584
4585/// Returns a sequence of changes produced by map component of shared collections (such as
4586/// `YMap` and `YXmlText`/`YXmlElement` attribute changes). `len` output parameter is used to
4587/// provide information about number of changes produced.
4588///
4589/// Delta returned from this function should eventually be released using `yevent_keys_destroy`
4590/// function.
4591#[no_mangle]
4592pub unsafe extern "C" fn ymap_event_keys(
4593    e: *const YMapEvent,
4594    len: *mut u32,
4595) -> *mut YEventKeyChange {
4596    assert!(!e.is_null());
4597    let e = &*e;
4598    let delta: Vec<_> = e
4599        .keys(e.txn())
4600        .into_iter()
4601        .map(|(k, v)| YEventKeyChange::new(k.as_ref(), v))
4602        .collect();
4603
4604    let out = delta.into_boxed_slice();
4605    *len = out.len() as u32;
4606    Box::into_raw(out) as *mut _
4607}
4608
4609/// Returns a sequence of changes produced by map component of shared collections.
4610/// `len` output parameter is used to provide information about number of changes produced.
4611///
4612/// Delta returned from this function should eventually be released using `yevent_keys_destroy`
4613/// function.
4614#[no_mangle]
4615pub unsafe extern "C" fn yxmlelem_event_keys(
4616    e: *const YXmlEvent,
4617    len: *mut u32,
4618) -> *mut YEventKeyChange {
4619    assert!(!e.is_null());
4620    let e = &*e;
4621    let delta: Vec<_> = e
4622        .keys(e.txn())
4623        .into_iter()
4624        .map(|(k, v)| YEventKeyChange::new(k.as_ref(), v))
4625        .collect();
4626
4627    let out = delta.into_boxed_slice();
4628    *len = out.len() as u32;
4629    Box::into_raw(out) as *mut _
4630}
4631
4632/// Returns a sequence of changes produced by map component of shared collections.
4633/// `len` output parameter is used to provide information about number of changes produced.
4634///
4635/// Delta returned from this function should eventually be released using `yevent_keys_destroy`
4636/// function.
4637#[no_mangle]
4638pub unsafe extern "C" fn yxmltext_event_keys(
4639    e: *const YXmlTextEvent,
4640    len: *mut u32,
4641) -> *mut YEventKeyChange {
4642    assert!(!e.is_null());
4643    let e = &*e;
4644    let delta: Vec<_> = e
4645        .keys(e.txn())
4646        .into_iter()
4647        .map(|(k, v)| YEventKeyChange::new(k.as_ref(), v))
4648        .collect();
4649
4650    let out = delta.into_boxed_slice();
4651    *len = out.len() as u32;
4652    Box::into_raw(out) as *mut _
4653}
4654
4655/// Releases memory allocated by the object returned from `yxml_event_keys` and `ymap_event_keys`
4656/// functions.
4657#[no_mangle]
4658pub unsafe extern "C" fn yevent_keys_destroy(keys: *mut YEventKeyChange, len: u32) {
4659    if !keys.is_null() {
4660        drop(Vec::from_raw_parts(keys, len as usize, len as usize));
4661    }
4662}
4663
4664pub type YUndoManager = yrs::undo::UndoManager<AtomicPtr<c_void>>;
4665
4666#[repr(C)]
4667pub struct YUndoManagerOptions {
4668    pub capture_timeout_millis: i32,
4669}
4670
4671// TODO [LSViana] Maybe rename this to `yundo_manager_new_with_options` to match `ydoc_new_with_options`?
4672/// Creates a new instance of undo manager bound to a current `doc`. It can be used to track
4673/// specific shared refs via `yundo_manager_add_scope` and updates coming from specific origin
4674/// - like ability to undo/redo operations originating only at the local peer - by using
4675/// `yundo_manager_add_origin`.
4676///
4677/// This object can be deallocated via `yundo_manager_destroy`.
4678#[no_mangle]
4679pub unsafe extern "C" fn yundo_manager(options: *const YUndoManagerOptions) -> *mut YUndoManager {
4680    let mut o = yrs::undo::Options::default();
4681    if let Some(options) = options.as_ref() {
4682        if options.capture_timeout_millis >= 0 {
4683            o.capture_timeout_millis = options.capture_timeout_millis as u64;
4684        }
4685    };
4686    let boxed = Box::new(yrs::undo::UndoManager::with_options(o));
4687    Box::into_raw(boxed)
4688}
4689
4690/// Deallocated undo manager instance created via `yundo_manager`.
4691#[no_mangle]
4692pub unsafe extern "C" fn yundo_manager_destroy(mgr: *mut YUndoManager) {
4693    drop(Box::from_raw(mgr));
4694}
4695
4696/// Adds an origin to be tracked by current undo manager. This way only changes made within context
4697/// of transactions created with specific origin will be subjects of undo/redo operations. This is
4698/// useful when you want to be able to revert changed done by specific user without reverting
4699/// changes made by other users that were applied in the meantime.
4700#[no_mangle]
4701pub unsafe extern "C" fn yundo_manager_add_origin(
4702    mgr: *mut YUndoManager,
4703    origin_len: u32,
4704    origin: *const c_char,
4705) {
4706    let mgr = mgr.as_mut().unwrap();
4707    let bytes = std::slice::from_raw_parts(origin as *const u8, origin_len as usize);
4708    mgr.include_origin(Origin::from(bytes));
4709}
4710
4711/// Removes an origin previously added to undo manager via `yundo_manager_add_origin`.
4712#[no_mangle]
4713pub unsafe extern "C" fn yundo_manager_remove_origin(
4714    mgr: *mut YUndoManager,
4715    origin_len: u32,
4716    origin: *const c_char,
4717) {
4718    let mgr = mgr.as_mut().unwrap();
4719    let bytes = std::slice::from_raw_parts(origin as *const u8, origin_len as usize);
4720    mgr.exclude_origin(Origin::from(bytes));
4721}
4722
4723/// Add specific shared type to be tracked by this instance of an undo manager.
4724#[no_mangle]
4725pub unsafe extern "C" fn yundo_manager_add_scope(
4726    mgr: *mut YUndoManager,
4727    doc: *const Doc,
4728    ytype: *const Branch,
4729) {
4730    let mgr = mgr.as_mut().unwrap();
4731    let doc = doc.as_ref().unwrap();
4732    let branch = ytype.as_ref().unwrap();
4733    mgr.expand_scope(doc, &BranchPtr::from(branch));
4734}
4735
4736/// Removes all the undo/redo stack changes tracked by current undo manager. This also cleans up
4737/// all the items that couldn't be deallocated / garbage collected for the sake of possible
4738/// undo/redo operations.
4739///
4740/// Keep in mind that this function call requires that underlying document store is not concurrently
4741/// modified by other read-write transaction. This is done by acquiring the read-only transaction
4742/// itself. If such transaction could be acquired (because of another read-write transaction is in
4743/// progress, this function will hold current thread until acquisition is possible.
4744#[no_mangle]
4745pub unsafe extern "C" fn yundo_manager_clear(mgr: *mut YUndoManager) {
4746    let mgr = mgr.as_mut().unwrap();
4747    mgr.clear_all();
4748}
4749
4750/// Cuts off tracked changes, producing a new stack item on undo stack.
4751///
4752/// By default, undo manager gathers undergoing changes together into undo stack items on periodic
4753/// basis (defined by `YUndoManagerOptions.capture_timeout_millis`). By calling this function, we're
4754/// explicitly creating a new stack item will all the changes registered since last stack item was
4755/// created.
4756#[no_mangle]
4757pub unsafe extern "C" fn yundo_manager_stop(mgr: *mut YUndoManager) {
4758    let mgr = mgr.as_mut().unwrap();
4759    mgr.reset();
4760}
4761
4762/// Performs an undo operations, reverting all the changes defined by the last undo stack item.
4763/// These changes can be then reapplied again by calling `yundo_manager_redo` function.
4764///
4765/// Returns `Y_TRUE` if successfully managed to do an undo operation.
4766/// Returns `Y_FALSE` if undo stack was empty or if undo couldn't be performed (because another
4767/// transaction is in progress).
4768#[no_mangle]
4769pub unsafe extern "C" fn yundo_manager_undo(mgr: *mut YUndoManager) -> u8 {
4770    let mgr = mgr.as_mut().unwrap();
4771
4772    if mgr.undo_blocking() {
4773        Y_TRUE
4774    } else {
4775        Y_FALSE
4776    }
4777}
4778
4779/// Performs a redo operations, reapplying changes undone by `yundo_manager_undo` operation.
4780///
4781/// Returns `Y_TRUE` if successfully managed to do a redo operation.
4782/// Returns `Y_FALSE` if redo stack was empty or if redo couldn't be performed (because another
4783/// transaction is in progress).
4784#[no_mangle]
4785pub unsafe extern "C" fn yundo_manager_redo(mgr: *mut YUndoManager) -> u8 {
4786    let mgr = mgr.as_mut().unwrap();
4787    if mgr.redo_blocking() {
4788        Y_TRUE
4789    } else {
4790        Y_FALSE
4791    }
4792}
4793
4794/// Returns number of elements stored on undo stack.
4795#[no_mangle]
4796pub unsafe extern "C" fn yundo_manager_undo_stack_len(mgr: *mut YUndoManager) -> u32 {
4797    let mgr = mgr.as_mut().unwrap();
4798    mgr.undo_stack().len() as u32
4799}
4800
4801/// Returns number of elements stored on redo stack.
4802#[no_mangle]
4803pub unsafe extern "C" fn yundo_manager_redo_stack_len(mgr: *mut YUndoManager) -> u32 {
4804    let mgr = mgr.as_mut().unwrap();
4805    mgr.redo_stack().len() as u32
4806}
4807
4808/// Subscribes a `callback` function pointer to a given undo manager event. This event will be
4809/// triggered every time a new undo/redo stack item is added.
4810///
4811/// Returns a subscription pointer that can be used to cancel current callback registration via
4812/// `yunobserve`.
4813#[no_mangle]
4814pub unsafe extern "C" fn yundo_manager_observe_added(
4815    mgr: *mut YUndoManager,
4816    state: *mut c_void,
4817    callback: extern "C" fn(*mut c_void, *const YUndoEvent),
4818) -> *mut Subscription {
4819    let state = CallbackState::new(state);
4820    let mgr = mgr.as_mut().unwrap();
4821    let subscription = mgr.observe_item_added(move |_, e| {
4822        let meta_ptr = {
4823            let event = YUndoEvent::new(e);
4824            callback(state.0, &event as *const YUndoEvent);
4825            event.meta
4826        };
4827        e.meta().store(meta_ptr, Ordering::Release);
4828    });
4829    Box::into_raw(Box::new(subscription))
4830}
4831
4832/// Subscribes a `callback` function pointer to a given undo manager event. This event will be
4833/// triggered every time a undo/redo operation was called.
4834///
4835/// Returns a subscription pointer that can be used to cancel current callback registration via
4836/// `yunobserve`.
4837#[no_mangle]
4838pub unsafe extern "C" fn yundo_manager_observe_popped(
4839    mgr: *mut YUndoManager,
4840    state: *mut c_void,
4841    callback: extern "C" fn(*mut c_void, *const YUndoEvent),
4842) -> *mut Subscription {
4843    let mgr = mgr.as_mut().unwrap();
4844    let state = CallbackState::new(state);
4845    let subscription = mgr
4846        .observe_item_popped(move |_, e| {
4847            let meta_ptr = {
4848                let event = YUndoEvent::new(e);
4849                callback(state.0, &event as *const YUndoEvent);
4850                event.meta
4851            };
4852            e.meta().store(meta_ptr, Ordering::Release);
4853        })
4854        .into();
4855    Box::into_raw(Box::new(subscription))
4856}
4857
4858pub const Y_KIND_UNDO: c_char = 0;
4859pub const Y_KIND_REDO: c_char = 1;
4860
4861/// Event type related to `UndoManager` observer operations, such as `yundo_manager_observe_popped`
4862/// and `yundo_manager_observe_added`. It contains various informations about the context in which
4863/// undo/redo operations are executed.
4864#[repr(C)]
4865pub struct YUndoEvent {
4866    /// Informs if current event is related to executed undo (`Y_KIND_UNDO`) or redo (`Y_KIND_REDO`)
4867    /// operation.
4868    pub kind: c_char,
4869    /// Origin assigned to a transaction, in context of which this event is being executed.
4870    /// Transaction origin is specified via `ydoc_write_transaction(doc, origin_len, origin)`.
4871    pub origin: *const c_char,
4872    /// Length of an `origin` field assigned to a transaction, in context of which this event is
4873    /// being executed.
4874    /// Transaction origin is specified via `ydoc_write_transaction(doc, origin_len, origin)`.
4875    pub origin_len: u32,
4876    /// Pointer to a custom metadata object that can be passed between
4877    /// `yundo_manager_observe_popped` and `yundo_manager_observe_added`. It's useful for passing
4878    /// around custom user data ie. cursor position, that needs to be remembered and restored as
4879    /// part of undo/redo operations.
4880    ///
4881    /// This field always starts with no value (`NULL`) assigned to it and can be set/unset in
4882    /// corresponding callback calls. In such cases it's up to a programmer to handle allocation
4883    /// and deallocation of memory that this pointer will point to. Not releasing it properly may
4884    /// lead to memory leaks.
4885    pub meta: *mut c_void,
4886}
4887
4888impl YUndoEvent {
4889    unsafe fn new(e: &yrs::undo::Event<AtomicPtr<c_void>>) -> Self {
4890        let (origin, origin_len) = if let Some(origin) = e.origin() {
4891            let bytes = origin.as_ref();
4892            let origin_len = bytes.len() as u32;
4893            let origin = bytes.as_ptr() as *const c_char;
4894            (origin, origin_len)
4895        } else {
4896            (null(), 0)
4897        };
4898        YUndoEvent {
4899            kind: match e.kind() {
4900                EventKind::Undo => Y_KIND_UNDO,
4901                EventKind::Redo => Y_KIND_REDO,
4902            },
4903            origin,
4904            origin_len,
4905            meta: e.meta().load(Ordering::Acquire),
4906        }
4907    }
4908}
4909
4910/// Returns a value informing what kind of Yrs shared collection given `branch` represents.
4911/// Returns either 0 when `branch` is null or one of values: `Y_ARRAY`, `Y_TEXT`, `Y_MAP`,
4912/// `Y_XML_ELEM`, `Y_XML_TEXT`.
4913#[no_mangle]
4914pub unsafe extern "C" fn ytype_kind(branch: *const Branch) -> i8 {
4915    if let Some(branch) = branch.as_ref() {
4916        match branch.type_ref() {
4917            TypeRef::Array => Y_ARRAY,
4918            TypeRef::Map => Y_MAP,
4919            TypeRef::Text => Y_TEXT,
4920            TypeRef::XmlElement(_) => Y_XML_ELEM,
4921            TypeRef::XmlText => Y_XML_TEXT,
4922            TypeRef::XmlFragment => Y_XML_FRAG,
4923            TypeRef::SubDoc => Y_DOC,
4924            TypeRef::WeakLink(_) => Y_WEAK_LINK,
4925            TypeRef::XmlHook => 0,
4926            TypeRef::Undefined => 0,
4927        }
4928    } else {
4929        0
4930    }
4931}
4932
4933/// Tag used to identify `YPathSegment` storing a *char parameter.
4934pub const Y_EVENT_PATH_KEY: c_char = 1;
4935
4936/// Tag used to identify `YPathSegment` storing an int parameter.
4937pub const Y_EVENT_PATH_INDEX: c_char = 2;
4938
4939/// A single segment of a path returned from `yevent_path` function. It can be one of two cases,
4940/// recognized by it's `tag` field:
4941///
4942/// 1. `Y_EVENT_PATH_KEY` means that segment value can be accessed by `segment.value.key` and is
4943/// referring to a string key used by map component (eg. `YMap` entry).
4944/// 2. `Y_EVENT_PATH_INDEX` means that segment value can be accessed by `segment.value.index` and is
4945/// referring to an int index used by sequence component (eg. `YArray` item or `YXmlElement` child).
4946#[repr(C)]
4947pub struct YPathSegment {
4948    /// Tag used to identify which case current segment is referring to:
4949    ///
4950    /// 1. `Y_EVENT_PATH_KEY` means that segment value can be accessed by `segment.value.key` and is
4951    /// referring to a string key used by map component (eg. `YMap` entry).
4952    /// 2. `Y_EVENT_PATH_INDEX` means that segment value can be accessed by `segment.value.index`
4953    /// and is referring to an int index used by sequence component (eg. `YArray` item or
4954    /// `YXmlElement` child).
4955    pub tag: c_char,
4956
4957    /// Union field containing either `key` or `index`. A particular case can be recognized by using
4958    /// segment's `tag` field.
4959    pub value: YPathSegmentCase,
4960}
4961
4962impl From<PathSegment> for YPathSegment {
4963    fn from(ps: PathSegment) -> Self {
4964        match ps {
4965            PathSegment::Key(key) => {
4966                let key = CString::new(key.as_ref()).unwrap().into_raw() as *const _;
4967                YPathSegment {
4968                    tag: Y_EVENT_PATH_KEY,
4969                    value: YPathSegmentCase { key },
4970                }
4971            }
4972            PathSegment::Index(index) => YPathSegment {
4973                tag: Y_EVENT_PATH_INDEX,
4974                value: YPathSegmentCase {
4975                    index: index as u32,
4976                },
4977            },
4978        }
4979    }
4980}
4981
4982impl Drop for YPathSegment {
4983    fn drop(&mut self) {
4984        if self.tag == Y_EVENT_PATH_KEY {
4985            unsafe {
4986                ystring_destroy(self.value.key as *mut _);
4987            }
4988        }
4989    }
4990}
4991
4992#[repr(C)]
4993pub union YPathSegmentCase {
4994    pub key: *const c_char,
4995    pub index: u32,
4996}
4997
4998/// Tag used to identify `YEventChange` (see: `yevent_delta` function) case, when a new element
4999/// has been added to an observed collection.
5000pub const Y_EVENT_CHANGE_ADD: u8 = 1;
5001
5002/// Tag used to identify `YEventChange` (see: `yevent_delta` function) case, when an existing
5003/// element has been removed from an observed collection.
5004pub const Y_EVENT_CHANGE_DELETE: u8 = 2;
5005
5006/// Tag used to identify `YEventChange` (see: `yevent_delta` function) case, when no changes have
5007/// been detected for a particular range of observed collection.
5008pub const Y_EVENT_CHANGE_RETAIN: u8 = 3;
5009
5010/// A data type representing a single change detected over an observed shared collection. A type
5011/// of change can be detected using a `tag` field:
5012///
5013/// 1. `Y_EVENT_CHANGE_ADD` marks a new elements added to a collection. In this case `values` field
5014/// contains a pointer to a list of newly inserted values, while `len` field informs about their
5015/// count.
5016/// 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this case
5017/// `len` field informs about number of removed elements.
5018/// 3. `Y_EVENT_CHANGE_RETAIN` marks a number of elements that have not been changed, counted from
5019/// the previous element. `len` field informs about number of retained elements.
5020///
5021/// A list of changes returned by `yarray_event_delta`/`yxml_event_delta` enables to locate a
5022/// position of all changes within an observed collection by using a combination of added/deleted
5023/// change structs separated by retained changes (marking eg. number of elements that can be safely
5024/// skipped, since they remained unchanged).
5025#[repr(C)]
5026pub struct YEventChange {
5027    /// Tag field used to identify particular type of change made:
5028    ///
5029    /// 1. `Y_EVENT_CHANGE_ADD` marks a new elements added to a collection. In this case `values`
5030    /// field contains a pointer to a list of newly inserted values, while `len` field informs about
5031    /// their count.
5032    /// 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this
5033    /// case `len` field informs about number of removed elements.
5034    /// 3. `Y_EVENT_CHANGE_RETAIN` marks a number of elements that have not been changed, counted
5035    /// from the previous element. `len` field informs about number of retained elements.
5036    pub tag: u8,
5037
5038    /// Number of element affected by current type of a change. It can refer to a number of
5039    /// inserted `values`, number of deleted element or a number of retained (unchanged) values.
5040    pub len: u32,
5041
5042    /// Used in case when current change is of `Y_EVENT_CHANGE_ADD` type. Contains a list (of
5043    /// length stored in `len` field) of newly inserted values.
5044    pub values: *const YOutput,
5045}
5046
5047impl<'a> From<&'a Change> for YEventChange {
5048    fn from(change: &'a Change) -> Self {
5049        match change {
5050            Change::Added(values) => {
5051                let out: Vec<_> = values
5052                    .into_iter()
5053                    .map(|v| YOutput::from(v.clone()))
5054                    .collect();
5055                let len = out.len() as u32;
5056                let out = out.into_boxed_slice();
5057                let values = Box::into_raw(out) as *mut _;
5058
5059                YEventChange {
5060                    tag: Y_EVENT_CHANGE_ADD,
5061                    len,
5062                    values,
5063                }
5064            }
5065            Change::Removed(len) => YEventChange {
5066                tag: Y_EVENT_CHANGE_DELETE,
5067                len: *len as u32,
5068                values: null(),
5069            },
5070            Change::Retain(len) => YEventChange {
5071                tag: Y_EVENT_CHANGE_RETAIN,
5072                len: *len as u32,
5073                values: null(),
5074            },
5075        }
5076    }
5077}
5078
5079impl Drop for YEventChange {
5080    fn drop(&mut self) {
5081        if self.tag == Y_EVENT_CHANGE_ADD {
5082            unsafe {
5083                let len = self.len as usize;
5084                let values = Vec::from_raw_parts(self.values as *mut YOutput, len, len);
5085                drop(values);
5086            }
5087        }
5088    }
5089}
5090
5091/// A data type representing a single change detected over an observed `YText`/`YXmlText`. A type
5092/// of change can be detected using a `tag` field:
5093///
5094/// 1. `Y_EVENT_CHANGE_ADD` marks a new characters added to a collection. In this case `insert`
5095/// field contains a pointer to a list of newly inserted values, while `len` field informs about
5096/// their count. Additionally `attributes_len` and `attributes` carry information about optional
5097/// formatting attributes applied to edited blocks.
5098/// 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this case
5099/// `len` field informs about number of removed elements.
5100/// 3. `Y_EVENT_CHANGE_RETAIN` marks a number of characters that have not been changed, counted from
5101/// the previous element. `len` field informs about number of retained elements. Additionally
5102/// `attributes_len` and `attributes` carry information about optional formatting attributes applied
5103/// to edited blocks.
5104///
5105/// A list of changes returned by `ytext_event_delta`/`yxmltext_event_delta` enables to locate
5106/// a position of all changes within an observed collection by using a combination of added/deleted
5107/// change structs separated by retained changes (marking eg. number of elements that can be safely
5108/// skipped, since they remained unchanged).
5109#[repr(C)]
5110pub struct YDeltaOut {
5111    /// Tag field used to identify particular type of change made:
5112    ///
5113    /// 1. `Y_EVENT_CHANGE_ADD` marks a new elements added to a collection. In this case `values`
5114    /// field contains a pointer to a list of newly inserted values, while `len` field informs about
5115    /// their count.
5116    /// 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this
5117    /// case `len` field informs about number of removed elements.
5118    /// 3. `Y_EVENT_CHANGE_RETAIN` marks a number of elements that have not been changed, counted
5119    /// from the previous element. `len` field informs about number of retained elements.
5120    pub tag: u8,
5121
5122    /// Number of element affected by current type of change. It can refer to a number of
5123    /// inserted `values`, number of deleted element or a number of retained (unchanged) values.
5124    pub len: u32,
5125
5126    /// A number of formatting attributes assigned to an edited area represented by this delta.
5127    pub attributes_len: u32,
5128
5129    /// A nullable pointer to a list of formatting attributes assigned to an edited area represented
5130    /// by this delta.
5131    pub attributes: *mut YDeltaAttr,
5132
5133    /// Used in case when current change is of `Y_EVENT_CHANGE_ADD` type. Contains a list (of
5134    /// length stored in `len` field) of newly inserted values.
5135    pub insert: *mut YOutput,
5136}
5137
5138impl YDeltaOut {
5139    fn insert(value: &Out, attrs: &Option<Box<Attrs>>) -> Self {
5140        let insert = Box::into_raw(Box::new(YOutput::from(value.clone())));
5141        let (attributes_len, attributes) = if let Some(attrs) = attrs {
5142            let len = attrs.len() as u32;
5143            let attrs: Vec<_> = attrs.iter().map(|(k, v)| YDeltaAttr::new(k, v)).collect();
5144            let attrs = Box::into_raw(attrs.into_boxed_slice()) as *mut _;
5145            (len, attrs)
5146        } else {
5147            (0, null_mut())
5148        };
5149
5150        YDeltaOut {
5151            tag: Y_EVENT_CHANGE_ADD,
5152            len: 1,
5153            insert,
5154            attributes_len,
5155            attributes,
5156        }
5157    }
5158
5159    fn retain(len: u32, attrs: &Option<Box<Attrs>>) -> Self {
5160        let (attributes_len, attributes) = if let Some(attrs) = attrs {
5161            let len = attrs.len() as u32;
5162            let attrs: Vec<_> = attrs.iter().map(|(k, v)| YDeltaAttr::new(k, v)).collect();
5163            let attrs = Box::into_raw(attrs.into_boxed_slice()) as *mut _;
5164            (len, attrs)
5165        } else {
5166            (0, null_mut())
5167        };
5168        YDeltaOut {
5169            tag: Y_EVENT_CHANGE_RETAIN,
5170            len,
5171            insert: null_mut(),
5172            attributes_len,
5173            attributes,
5174        }
5175    }
5176
5177    fn delete(len: u32) -> Self {
5178        YDeltaOut {
5179            tag: Y_EVENT_CHANGE_DELETE,
5180            len,
5181            insert: null_mut(),
5182            attributes_len: 0,
5183            attributes: null_mut(),
5184        }
5185    }
5186}
5187
5188impl<'a> From<&'a Delta> for YDeltaOut {
5189    fn from(d: &Delta) -> Self {
5190        match d {
5191            Delta::Inserted(value, attrs) => YDeltaOut::insert(value, attrs),
5192            Delta::Retain(len, attrs) => YDeltaOut::retain(*len, attrs),
5193            Delta::Deleted(len) => YDeltaOut::delete(*len),
5194        }
5195    }
5196}
5197
5198impl Drop for YDeltaOut {
5199    fn drop(&mut self) {
5200        unsafe {
5201            if !self.attributes.is_null() {
5202                let len = self.attributes_len as usize;
5203                drop(Vec::from_raw_parts(self.attributes, len, len));
5204            }
5205            if !self.insert.is_null() {
5206                drop(Box::from_raw(self.insert));
5207            }
5208        }
5209    }
5210}
5211
5212/// A single instance of formatting attribute stored as part of `YDelta` instance.
5213#[repr(C)]
5214pub struct YDeltaAttr {
5215    /// A null-terminated UTF-8 encoded string containing a unique formatting attribute name.
5216    pub key: *const c_char,
5217    /// A value assigned to a formatting attribute.
5218    pub value: YOutput,
5219}
5220
5221impl YDeltaAttr {
5222    fn new(k: &Arc<str>, v: &Any) -> Self {
5223        let key = CString::new(k.as_ref()).unwrap().into_raw() as *const _;
5224        let value = YOutput::from(v);
5225        YDeltaAttr { key, value }
5226    }
5227}
5228
5229impl Drop for YDeltaAttr {
5230    fn drop(&mut self) {
5231        unsafe { ystring_destroy(self.key as *mut _) }
5232    }
5233}
5234
5235/// A data type representing a single change to be performed in sequence of changes defined
5236/// as parameter to a `ytext_insert_delta` function. A type of change can be detected using
5237/// a `tag` field:
5238///
5239/// 1. `Y_EVENT_CHANGE_ADD` marks a new characters added to a collection. In this case `insert`
5240/// field contains a pointer to a list of newly inserted values, while `len` field informs about
5241/// their count. Additionally `attributes_len` and `attributes` carry information about optional
5242/// formatting attributes applied to edited blocks.
5243/// 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this case
5244/// `len` field informs about number of removed elements.
5245/// 3. `Y_EVENT_CHANGE_RETAIN` marks a number of characters that have not been changed, counted from
5246/// the previous element. `len` field informs about number of retained elements. Additionally
5247/// `attributes_len` and `attributes` carry information about optional formatting attributes applied
5248/// to edited blocks.
5249#[repr(C)]
5250pub struct YDeltaIn {
5251    /// Tag field used to identify particular type of change made:
5252    ///
5253    /// 1. `Y_EVENT_CHANGE_ADD` marks a new elements added to a collection. In this case `values`
5254    /// field contains a pointer to a list of newly inserted values, while `len` field informs about
5255    /// their count.
5256    /// 2. `Y_EVENT_CHANGE_DELETE` marks an existing elements removed from the collection. In this
5257    /// case `len` field informs about number of removed elements.
5258    /// 3. `Y_EVENT_CHANGE_RETAIN` marks a number of elements that have not been changed, counted
5259    /// from the previous element. `len` field informs about number of retained elements.
5260    pub tag: u8,
5261
5262    /// Number of element affected by current type of change. It can refer to a number of
5263    /// inserted `values`, number of deleted element or a number of retained (unchanged) values.
5264    pub len: u32,
5265
5266    /// A nullable pointer to a list of formatting attributes assigned to an edited area represented
5267    /// by this delta.
5268    pub attributes: *const YInput,
5269
5270    /// Used in case when current change is of `Y_EVENT_CHANGE_ADD` type. Contains a list (of
5271    /// length stored in `len` field) of newly inserted values.
5272    pub insert: *const YInput,
5273}
5274
5275impl YDeltaIn {
5276    fn as_input(&self) -> Delta<YInput> {
5277        match self.tag {
5278            Y_EVENT_CHANGE_RETAIN => {
5279                let attrs = if self.attributes.is_null() {
5280                    None
5281                } else {
5282                    let attrs = unsafe { self.attributes.read() };
5283                    map_attrs(attrs.into()).map(Box::new)
5284                };
5285                Delta::Retain(self.len, attrs)
5286            }
5287            Y_EVENT_CHANGE_DELETE => Delta::Deleted(self.len),
5288            Y_EVENT_CHANGE_ADD => {
5289                let attrs = if self.attributes.is_null() {
5290                    None
5291                } else {
5292                    let attrs = unsafe { self.attributes.read() };
5293                    map_attrs(attrs.into()).map(Box::new)
5294                };
5295                let input = unsafe { self.insert.read() };
5296                Delta::Inserted(input, attrs)
5297            }
5298            tag => panic!("YDelta tag identifier is of unknown type: {}", tag),
5299        }
5300    }
5301}
5302
5303/// Tag used to identify `YEventKeyChange` (see: `yevent_keys` function) case, when a new entry has
5304/// been inserted into a map component of shared collection.
5305pub const Y_EVENT_KEY_CHANGE_ADD: c_char = 4;
5306
5307/// Tag used to identify `YEventKeyChange` (see: `yevent_keys` function) case, when an existing
5308/// entry has been removed from a map component of shared collection.
5309pub const Y_EVENT_KEY_CHANGE_DELETE: c_char = 5;
5310
5311/// Tag used to identify `YEventKeyChange` (see: `yevent_keys` function) case, when an existing
5312/// entry has been overridden with a new value within a map component of shared collection.
5313pub const Y_EVENT_KEY_CHANGE_UPDATE: c_char = 6;
5314
5315/// A data type representing a single change made over a map component of shared collection types,
5316/// such as `YMap` entries or `YXmlText`/`YXmlElement` attributes. A `key` field provides a
5317/// corresponding unique key string of a changed entry, while `tag` field informs about specific
5318/// type of change being done:
5319///
5320/// 1. `Y_EVENT_KEY_CHANGE_ADD` used to identify a newly added entry. In this case an `old_value`
5321/// field is NULL, while `new_value` field contains an inserted value.
5322/// 1. `Y_EVENT_KEY_CHANGE_DELETE` used to identify an existing entry being removed. In this case
5323/// an `old_value` field contains the removed value.
5324/// 1. `Y_EVENT_KEY_CHANGE_UPDATE` used to identify an existing entry, which value has been changed.
5325/// In this case `old_value` field contains replaced value, while `new_value` contains a newly
5326/// inserted one.
5327#[repr(C)]
5328pub struct YEventKeyChange {
5329    /// A UTF8-encoded null-terminated string containing a key of a changed entry.
5330    pub key: *const c_char,
5331    /// Tag field informing about type of change current struct refers to:
5332    ///
5333    /// 1. `Y_EVENT_KEY_CHANGE_ADD` used to identify a newly added entry. In this case an
5334    /// `old_value` field is NULL, while `new_value` field contains an inserted value.
5335    /// 1. `Y_EVENT_KEY_CHANGE_DELETE` used to identify an existing entry being removed. In this
5336    /// case an `old_value` field contains the removed value.
5337    /// 1. `Y_EVENT_KEY_CHANGE_UPDATE` used to identify an existing entry, which value has been
5338    /// changed. In this case `old_value` field contains replaced value, while `new_value` contains
5339    /// a newly inserted one.
5340    pub tag: c_char,
5341
5342    /// Contains a removed entry's value or replaced value of an updated entry.
5343    pub old_value: *const YOutput,
5344
5345    /// Contains a value of newly inserted entry or an updated entry's new value.
5346    pub new_value: *const YOutput,
5347}
5348
5349impl YEventKeyChange {
5350    fn new(key: &str, change: &EntryChange) -> Self {
5351        let key = CString::new(key).unwrap().into_raw() as *const _;
5352        match change {
5353            EntryChange::Inserted(new) => YEventKeyChange {
5354                key,
5355                tag: Y_EVENT_KEY_CHANGE_ADD,
5356                old_value: null(),
5357                new_value: Box::into_raw(Box::new(YOutput::from(new.clone()))),
5358            },
5359            EntryChange::Updated(old, new) => YEventKeyChange {
5360                key,
5361                tag: Y_EVENT_KEY_CHANGE_UPDATE,
5362                old_value: Box::into_raw(Box::new(YOutput::from(old.clone()))),
5363                new_value: Box::into_raw(Box::new(YOutput::from(new.clone()))),
5364            },
5365            EntryChange::Removed(old) => YEventKeyChange {
5366                key,
5367                tag: Y_EVENT_KEY_CHANGE_DELETE,
5368                old_value: Box::into_raw(Box::new(YOutput::from(old.clone()))),
5369                new_value: null(),
5370            },
5371        }
5372    }
5373}
5374
5375impl Drop for YEventKeyChange {
5376    fn drop(&mut self) {
5377        unsafe {
5378            ystring_destroy(self.key as *mut _);
5379            youtput_destroy(self.old_value as *mut _);
5380            youtput_destroy(self.new_value as *mut _);
5381        }
5382    }
5383}
5384
5385trait BranchPointable {
5386    fn into_raw_branch(self) -> *mut Branch;
5387    fn from_raw_branch(branch: *const Branch) -> Self;
5388}
5389
5390impl<T> BranchPointable for T
5391where
5392    T: AsRef<Branch> + From<BranchPtr>,
5393{
5394    fn into_raw_branch(self) -> *mut Branch {
5395        let branch_ref = self.as_ref();
5396        branch_ref as *const Branch as *mut Branch
5397    }
5398
5399    fn from_raw_branch(branch: *const Branch) -> Self {
5400        let b = unsafe { branch.as_ref().unwrap() };
5401        let branch_ref = BranchPtr::from(b);
5402        T::from(branch_ref)
5403    }
5404}
5405
5406/// A sticky index is based on the Yjs model and is not affected by document changes.
5407/// E.g. If you place a sticky index before a certain character, it will always point to this character.
5408/// If you place a sticky index at the end of a type, it will always point to the end of the type.
5409///
5410/// A numeric position is often unsuited for user selections, because it does not change when content is inserted
5411/// before or after.
5412///
5413/// ```Insert(0, 'x')('a.bc') = 'xa.bc'``` Where `.` is the sticky index position.
5414///
5415/// Instances of `YStickyIndex` can be freed using `ysticky_index_destroy`.
5416#[repr(transparent)]
5417pub struct YStickyIndex(StickyIndex);
5418
5419impl From<StickyIndex> for YStickyIndex {
5420    #[inline(always)]
5421    fn from(value: StickyIndex) -> Self {
5422        YStickyIndex(value)
5423    }
5424}
5425
5426/// Releases resources allocated by `YStickyIndex` pointers.
5427#[no_mangle]
5428pub unsafe extern "C" fn ysticky_index_destroy(pos: *mut YStickyIndex) {
5429    drop(Box::from_raw(pos))
5430}
5431
5432/// Returns association of current `YStickyIndex`.
5433/// If association is **after** the referenced inserted character, returned number will be >= 0.
5434/// If association is **before** the referenced inserted character, returned number will be < 0.
5435#[no_mangle]
5436pub unsafe extern "C" fn ysticky_index_assoc(pos: *const YStickyIndex) -> i8 {
5437    let pos = pos.as_ref().unwrap();
5438    match pos.0.assoc {
5439        Assoc::After => 0,
5440        Assoc::Before => -1,
5441    }
5442}
5443
5444/// Retrieves a `YStickyIndex` corresponding to a given human-readable `index` pointing into
5445/// the shared y-type `branch`. Unlike standard indexes sticky one enables to track
5446/// the location inside of a shared y-types, even in the face of concurrent updates.
5447///
5448/// If association is >= 0, the resulting position will point to location **after** the referenced index.
5449/// If association is < 0, the resulting position will point to location **before** the referenced index.
5450#[no_mangle]
5451pub unsafe extern "C" fn ysticky_index_from_index(
5452    branch: *const Branch,
5453    txn: *mut Transaction,
5454    index: u32,
5455    assoc: i8,
5456) -> *mut YStickyIndex {
5457    assert!(!branch.is_null());
5458    assert!(!txn.is_null());
5459
5460    let branch = BranchPtr::from_raw_branch(branch);
5461    let txn = txn.as_mut().unwrap();
5462    let index = index as u32;
5463    let assoc = if assoc >= 0 {
5464        Assoc::After
5465    } else {
5466        Assoc::Before
5467    };
5468
5469    if let Some(txn) = txn.as_mut() {
5470        if let Some(pos) = StickyIndex::at(txn, branch, index, assoc) {
5471            Box::into_raw(Box::new(YStickyIndex(pos)))
5472        } else {
5473            null_mut()
5474        }
5475    } else {
5476        panic!("ysticky_index_from_index requires a read-write transaction");
5477    }
5478}
5479
5480/// Serializes `YStickyIndex` into binary representation. `len` parameter is updated with byte
5481/// length of the generated binary. Returned binary can be free'd using `ybinary_destroy`.
5482#[no_mangle]
5483pub unsafe extern "C" fn ysticky_index_encode(
5484    pos: *const YStickyIndex,
5485    len: *mut u32,
5486) -> *mut c_char {
5487    let pos = pos.as_ref().unwrap();
5488    let binary = pos.0.encode_v1().into_boxed_slice();
5489    *len = binary.len() as u32;
5490    Box::into_raw(binary) as *mut c_char
5491}
5492
5493/// Serializes `YStickyIndex` into JSON representation. `len` parameter is updated with byte
5494/// length of the generated binary. Returned binary can be free'd using `ybinary_destroy`.
5495#[no_mangle]
5496pub unsafe extern "C" fn ysticky_index_decode(
5497    binary: *const c_char,
5498    len: u32,
5499) -> *mut YStickyIndex {
5500    let slice = std::slice::from_raw_parts(binary as *const u8, len as usize);
5501    if let Ok(pos) = StickyIndex::decode_v1(slice) {
5502        Box::into_raw(Box::new(YStickyIndex(pos)))
5503    } else {
5504        null_mut()
5505    }
5506}
5507
5508/// Serialize `YStickyIndex` into null-terminated UTF-8 encoded JSON string, that's compatible with
5509/// Yjs RelativePosition serialization format. The `len` parameter is updated with byte length of
5510/// of the output JSON string. This string can be freed using `ystring_destroy`.
5511#[no_mangle]
5512pub unsafe extern "C" fn ysticky_index_to_json(pos: *const YStickyIndex) -> *mut c_char {
5513    let pos = pos.as_ref().unwrap();
5514    let json = match serde_json::to_string(&pos.0) {
5515        Ok(json) => json,
5516        Err(_) => return null_mut(),
5517    };
5518    CString::new(json).unwrap().into_raw()
5519}
5520
5521/// Deserializes `YStickyIndex` from the payload previously serialized using `ysticky_index_to_json`.
5522/// The input `json` parameter is a NULL-terminated UTF-8 encoded string containing a JSON
5523/// compatible with Yjs RelativePosition serialization format.
5524///
5525/// Returns null pointer if deserialization failed.
5526///
5527/// This function DOESN'T release the `json` parameter: it needs to be done manually - if JSON
5528/// string was created using `ysticky_index_to_json` function, it can be freed using `ystring_destroy`.
5529#[no_mangle]
5530pub unsafe extern "C" fn ysticky_index_from_json(json: *const c_char) -> *mut YStickyIndex {
5531    let cstr = CStr::from_ptr(json);
5532    let json = match cstr.to_str() {
5533        Ok(json) => json,
5534        Err(_) => return null_mut(),
5535    };
5536    match serde_json::from_str(json) {
5537        Ok(pos) => Box::into_raw(Box::new(YStickyIndex(pos))),
5538        Err(_) => null_mut(),
5539    }
5540}
5541
5542/// Given `YStickyIndex` and transaction reference, if computes a human-readable index in a
5543/// context of the referenced shared y-type.
5544///
5545/// `out_branch` is getting assigned with a corresponding shared y-type reference.
5546/// `out_index` will be used to store computed human-readable index.
5547#[no_mangle]
5548pub unsafe extern "C" fn ysticky_index_read(
5549    pos: *const YStickyIndex,
5550    txn: *const Transaction,
5551    out_branch: *mut *mut Branch,
5552    out_index: *mut u32,
5553) {
5554    let pos = pos.as_ref().unwrap();
5555    let txn = txn.as_ref().unwrap();
5556
5557    if let Some(abs) = pos.0.get_offset(txn) {
5558        *out_branch = abs.branch.as_ref() as *const Branch as *mut Branch;
5559        *out_index = abs.index as u32;
5560    }
5561}
5562
5563pub type Weak = LinkSource;
5564
5565#[no_mangle]
5566pub unsafe extern "C" fn yweak_destroy(weak: *const Weak) {
5567    drop(Arc::from_raw(weak));
5568}
5569
5570#[no_mangle]
5571pub unsafe extern "C" fn yweak_deref(
5572    map_link: *const Branch,
5573    txn: *const Transaction,
5574) -> *mut YOutput {
5575    assert!(!map_link.is_null());
5576    assert!(!txn.is_null());
5577
5578    let txn = txn.as_ref().unwrap();
5579    let weak: WeakRef<MapRef> = WeakRef::from_raw_branch(map_link);
5580    if let Some(value) = weak.try_deref_value(txn) {
5581        Box::into_raw(Box::new(YOutput::from(value)))
5582    } else {
5583        null_mut()
5584    }
5585}
5586
5587#[no_mangle]
5588pub unsafe extern "C" fn yweak_read(
5589    text_link: *const Branch,
5590    txn: *const Transaction,
5591    out_branch: *mut *mut Branch,
5592    out_start_index: *mut u32,
5593    out_end_index: *mut u32,
5594) {
5595    assert!(!text_link.is_null());
5596    assert!(!txn.is_null());
5597
5598    let txn = txn.as_ref().unwrap();
5599    let weak: WeakRef<BranchPtr> = WeakRef::from_raw_branch(text_link);
5600    if let Some(id) = weak.start_id() {
5601        // Assoc must be After to get the same values back
5602        let start = StickyIndex::from_id(*id, Assoc::After);
5603        assert!(weak.end_id() != None);
5604        let end = StickyIndex::from_id(*weak.end_id().unwrap(), Assoc::After);
5605        if let Some(start_pos) = start.get_offset(txn) {
5606            *out_branch = start_pos.branch.as_ref() as *const Branch as *mut Branch;
5607            *out_start_index = start_pos.index as u32;
5608            if let Some(end_pos) = end.get_offset(txn) {
5609                assert!(*out_branch == end_pos.branch.as_ref() as *const Branch as *mut Branch);
5610                *out_end_index = end_pos.index as u32;
5611            }
5612        }
5613    } else {
5614        assert!(weak.end_id() == None); // both
5615                                        // unforunately no Branch in this case?
5616        *out_start_index = 0; // empty text
5617        *out_end_index = 0; // empty text
5618    }
5619}
5620
5621#[no_mangle]
5622pub unsafe extern "C" fn yweak_iter(
5623    array_link: *const Branch,
5624    txn: *const Transaction,
5625) -> *mut WeakIter {
5626    assert!(!array_link.is_null());
5627    assert!(!txn.is_null());
5628
5629    let txn = txn.as_ref().unwrap();
5630    let weak: WeakRef<ArrayRef> = WeakRef::from_raw_branch(array_link);
5631    let iter: NativeUnquote<'static, Transaction> = std::mem::transmute(weak.unquote(txn));
5632
5633    Box::into_raw(Box::new(WeakIter(iter)))
5634}
5635
5636#[no_mangle]
5637pub unsafe extern "C" fn yweak_iter_destroy(iter: *mut WeakIter) {
5638    drop(Box::from_raw(iter))
5639}
5640
5641#[no_mangle]
5642pub unsafe extern "C" fn yweak_iter_next(iter: *mut WeakIter) -> *mut YOutput {
5643    assert!(!iter.is_null());
5644    let iter = iter.as_mut().unwrap();
5645
5646    if let Some(value) = iter.0.next() {
5647        Box::into_raw(Box::new(YOutput::from(value)))
5648    } else {
5649        null_mut()
5650    }
5651}
5652
5653#[no_mangle]
5654pub unsafe extern "C" fn yweak_string(
5655    text_link: *const Branch,
5656    txn: *const Transaction,
5657) -> *mut c_char {
5658    assert!(!text_link.is_null());
5659    assert!(!txn.is_null());
5660
5661    let txn = txn.as_ref().unwrap();
5662    let weak: WeakRef<TextRef> = WeakRef::from_raw_branch(text_link);
5663
5664    let str = weak.get_string(txn);
5665    CString::new(str).unwrap().into_raw()
5666}
5667
5668#[no_mangle]
5669pub unsafe extern "C" fn yweak_xml_string(
5670    xml_text_link: *const Branch,
5671    txn: *const Transaction,
5672) -> *mut c_char {
5673    assert!(!xml_text_link.is_null());
5674    assert!(!txn.is_null());
5675
5676    let txn = txn.as_ref().unwrap();
5677    let weak: WeakRef<XmlTextRef> = WeakRef::from_raw_branch(xml_text_link);
5678
5679    let str = weak.get_string(txn);
5680    CString::new(str).unwrap().into_raw()
5681}
5682
5683/// Subscribes a given callback function `cb` to changes made by this `YText` instance. Callbacks
5684/// are triggered whenever a `ytransaction_commit` is called.
5685/// Returns a subscription ID which can be then used to unsubscribe this callback by using
5686/// `yunobserve` function.
5687#[no_mangle]
5688pub unsafe extern "C" fn yweak_observe(
5689    weak: *const Branch,
5690    state: *mut c_void,
5691    cb: extern "C" fn(*mut c_void, *const YWeakLinkEvent),
5692) -> *mut Subscription {
5693    assert!(!weak.is_null());
5694
5695    let state = CallbackState::new(state);
5696    let txt: WeakRef<BranchPtr> = WeakRef::from_raw_branch(weak);
5697    let subscription = txt.observe(move |txn, e| {
5698        let e = YWeakLinkEvent::new(e, txn);
5699        cb(state.0, &e as *const YWeakLinkEvent);
5700    });
5701    Box::into_raw(Box::new(subscription))
5702}
5703
5704#[no_mangle]
5705pub unsafe extern "C" fn ymap_link(
5706    map: *const Branch,
5707    txn: *const Transaction,
5708    key: *const c_char,
5709) -> *const Weak {
5710    assert!(!map.is_null());
5711    assert!(!txn.is_null());
5712
5713    let txn = txn.as_ref().unwrap();
5714    let map = MapRef::from_raw_branch(map);
5715    let key = CStr::from_ptr(key).to_str().unwrap();
5716    if let Some(weak) = map.link(txn, key) {
5717        let source = weak.source();
5718        Arc::into_raw(source.clone())
5719    } else {
5720        null()
5721    }
5722}
5723
5724#[no_mangle]
5725pub unsafe extern "C" fn ytext_quote(
5726    text: *const Branch,
5727    txn: *mut Transaction,
5728    start_index: *mut u32,
5729    end_index: *mut u32,
5730    start_exclusive: i8,
5731    end_exclusive: i8,
5732) -> *const Weak {
5733    assert!(!text.is_null());
5734    assert!(!txn.is_null());
5735
5736    let text = TextRef::from_raw_branch(text);
5737    let txn = txn.as_mut().unwrap();
5738    let txn = txn
5739        .as_mut()
5740        .expect("provided transaction was not writeable");
5741
5742    let start_index = start_index.as_ref().cloned();
5743    let end_index = end_index.as_ref().cloned();
5744    let range = ExplicitRange {
5745        start_index,
5746        end_index,
5747        start_exclusive,
5748        end_exclusive,
5749    };
5750    if let Ok(weak) = text.quote(txn, range) {
5751        let source = weak.source();
5752        Arc::into_raw(source.clone())
5753    } else {
5754        null()
5755    }
5756}
5757
5758#[no_mangle]
5759pub unsafe extern "C" fn yarray_quote(
5760    array: *const Branch,
5761    txn: *mut Transaction,
5762    start_index: *mut u32,
5763    end_index: *mut u32,
5764    start_exclusive: i8,
5765    end_exclusive: i8,
5766) -> *const Weak {
5767    assert!(!array.is_null());
5768    assert!(!txn.is_null());
5769
5770    let array = ArrayRef::from_raw_branch(array);
5771    let txn = txn.as_mut().unwrap();
5772    let txn = txn
5773        .as_mut()
5774        .expect("provided transaction was not writeable");
5775
5776    let start_index = start_index.as_ref().cloned();
5777    let end_index = end_index.as_ref().cloned();
5778    let range = ExplicitRange {
5779        start_index,
5780        end_index,
5781        start_exclusive,
5782        end_exclusive,
5783    };
5784    if let Ok(weak) = array.quote(txn, range) {
5785        let source = weak.source();
5786        Arc::into_raw(source.clone())
5787    } else {
5788        null()
5789    }
5790}
5791
5792struct ExplicitRange {
5793    start_index: Option<u32>,
5794    end_index: Option<u32>,
5795    start_exclusive: i8,
5796    end_exclusive: i8,
5797}
5798
5799impl RangeBounds<u32> for ExplicitRange {
5800    fn start_bound(&self) -> Bound<&u32> {
5801        match (&self.start_index, self.start_exclusive) {
5802            (None, _) => Bound::Unbounded,
5803            (Some(i), 0) => Bound::Included(i),
5804            (Some(i), _) => Bound::Excluded(i),
5805        }
5806    }
5807
5808    fn end_bound(&self) -> Bound<&u32> {
5809        match (&self.end_index, self.end_exclusive) {
5810            (None, _) => Bound::Unbounded,
5811            (Some(i), 0) => Bound::Included(i),
5812            (Some(i), _) => Bound::Excluded(i),
5813        }
5814    }
5815}
5816
5817/// A structure representing logical identifier of a specific shared collection.
5818/// Can be obtained by `ybranch_id` executed over alive `Branch`.
5819///
5820/// Use `ybranch_get` to resolve a `Branch` pointer from this branch ID.
5821///
5822/// This structure doesn't need to be destroyed. It's internal pointer reference is valid through
5823/// a lifetime of a document, which collection this branch ID has been created from.
5824#[repr(C)]
5825pub struct YBranchId {
5826    /// If positive: Client ID of a creator of a nested shared type, this identifier points to.
5827    /// If negative: a negated Length of a root-level shared collection name.
5828    pub client_or_len: i64,
5829    pub variant: YBranchIdVariant,
5830}
5831
5832#[repr(C)]
5833pub union YBranchIdVariant {
5834    /// Clock number timestamp when the creator of a nested shared type created it.
5835    pub clock: u32,
5836    /// Pointer to UTF-8 encoded string representing root-level type name. This pointer is valid
5837    /// as long as document - in which scope it was created in - was not destroyed. As usually
5838    /// root-level type names are statically allocated strings, it can also be supplied manually
5839    /// from the outside.
5840    pub name: *const u8,
5841}
5842
5843/// Returns a logical identifier for a given shared collection. That collection must be alive at
5844/// the moment of function call.
5845#[no_mangle]
5846pub unsafe extern "C" fn ybranch_id(branch: *const Branch) -> YBranchId {
5847    let branch = branch.as_ref().unwrap();
5848    match branch.id() {
5849        BranchID::Nested(id) => YBranchId {
5850            client_or_len: id.client.get() as i64,
5851            variant: YBranchIdVariant { clock: id.clock },
5852        },
5853        BranchID::Root(name) => {
5854            let len = -(name.len() as i64);
5855            YBranchId {
5856                client_or_len: len,
5857                variant: YBranchIdVariant {
5858                    name: name.as_ptr(),
5859                },
5860            }
5861        }
5862    }
5863}
5864
5865/// Given a logical identifier, returns a physical pointer to a shared collection.
5866/// Returns null if collection was not found - either because it was not defined or not synchronized
5867/// yet.
5868/// Returned pointer may still point to deleted collection. In such case a subsequent `ybranch_alive`
5869/// function call is required.
5870#[no_mangle]
5871pub unsafe extern "C" fn ybranch_get(
5872    branch_id: *const YBranchId,
5873    txn: *mut Transaction,
5874) -> *mut Branch {
5875    let txn = txn.as_ref().unwrap();
5876    let branch_id = branch_id.as_ref().unwrap();
5877    let client_or_len = branch_id.client_or_len;
5878    let ptr = if client_or_len >= 0 {
5879        BranchID::get_nested(
5880            txn,
5881            &ID::new(ClientID::new(client_or_len as u64), branch_id.variant.clock),
5882        )
5883    } else {
5884        let name = std::slice::from_raw_parts(branch_id.variant.name, (-client_or_len) as usize);
5885        BranchID::get_root(txn, std::str::from_utf8_unchecked(name))
5886    };
5887
5888    match ptr {
5889        None => null_mut(),
5890        Some(branch_ptr) => branch_ptr.into_raw_branch(),
5891    }
5892}
5893
5894/// Check if current branch is still alive (returns `Y_TRUE`, otherwise `Y_FALSE`).
5895/// If it was deleted, this branch pointer is no longer a valid pointer and cannot be used to
5896/// execute any functions using it.
5897#[no_mangle]
5898pub unsafe extern "C" fn ybranch_alive(branch: *mut Branch) -> u8 {
5899    if branch.is_null() {
5900        Y_FALSE
5901    } else {
5902        let branch = BranchPtr::from_raw_branch(branch);
5903        if branch.is_deleted() {
5904            Y_FALSE
5905        } else {
5906            Y_TRUE
5907        }
5908    }
5909}
5910
5911/// Returns a UTF-8 encoded, NULL-terminated JSON string representation of the current branch
5912/// contents. Once no longer needed, this string must be explicitly deallocated by user using
5913/// `ystring_destroy`.
5914///
5915/// If branch type couldn't be resolved (which usually happens for root-level types that were not
5916/// initialized locally) or doesn't have JSON representation a NULL pointer can be returned.
5917#[no_mangle]
5918pub unsafe extern "C" fn ybranch_json(branch: *mut Branch, txn: *mut Transaction) -> *mut c_char {
5919    if branch.is_null() {
5920        std::ptr::null_mut()
5921    } else {
5922        let txn = txn.as_ref().unwrap();
5923        let branch_ref = BranchPtr::from_raw_branch(branch);
5924        let any = match branch_ref.type_ref() {
5925            TypeRef::Array => ArrayRef::from_raw_branch(branch).to_json(txn),
5926            TypeRef::Map => MapRef::from_raw_branch(branch).to_json(txn),
5927            TypeRef::Text => TextRef::from_raw_branch(branch).get_string(txn).into(),
5928            TypeRef::XmlElement(_) => XmlElementRef::from_raw_branch(branch)
5929                .get_string(txn)
5930                .into(),
5931            TypeRef::XmlFragment => XmlFragmentRef::from_raw_branch(branch)
5932                .get_string(txn)
5933                .into(),
5934            TypeRef::XmlText => XmlTextRef::from_raw_branch(branch).get_string(txn).into(),
5935            TypeRef::SubDoc | TypeRef::XmlHook | TypeRef::WeakLink(_) | TypeRef::Undefined => {
5936                return std::ptr::null_mut()
5937            }
5938        };
5939        let json = match serde_json::to_string(&any) {
5940            Ok(json) => json,
5941            Err(_) => return std::ptr::null_mut(),
5942        };
5943        CString::new(json).unwrap().into_raw()
5944    }
5945}