use std::collections::{Bound, HashMap};
use std::ffi::{c_char, c_void, CStr, CString};
use std::mem::{forget, ManuallyDrop, MaybeUninit};
use std::ops::{Deref, RangeBounds};
use std::ptr::{null, null_mut};
use std::sync::atomic::{AtomicPtr, Ordering};
use std::sync::Arc;
use yrs::block::{ClientID, EmbedPrelim, ItemContent, Prelim, Unused};
use yrs::branch::BranchPtr;
use yrs::encoding::read::Error;
use yrs::error::UpdateError;
use yrs::json_path::JsonPathIter as NativeJsonPathIter;
use yrs::types::array::ArrayEvent;
use yrs::types::array::ArrayIter as NativeArrayIter;
use yrs::types::map::MapEvent;
use yrs::types::map::MapIter as NativeMapIter;
use yrs::types::text::{Diff, TextEvent, YChange};
use yrs::types::weak::{LinkSource, Unquote as NativeUnquote, WeakEvent, WeakRef};
use yrs::types::xml::{Attributes as NativeAttributes, XmlOut};
use yrs::types::xml::{TreeWalker as NativeTreeWalker, XmlFragment};
use yrs::types::xml::{XmlEvent, XmlTextEvent};
use yrs::types::{Attrs, Change, Delta, EntryChange, Event, PathSegment, ToJson, TypeRef};
use yrs::undo::EventKind;
use yrs::updates::decoder::{Decode, DecoderV1};
use yrs::updates::encoder::{Encode, Encoder, EncoderV1, EncoderV2};
use yrs::{
uuid_v4, Any, Array, ArrayRef, Assoc, BranchID, DeleteSet, GetString, JsonPath, JsonPathEval,
Map, MapRef, Observable, OffsetKind, Options, Origin, Out, Quotable, ReadTxn, Snapshot,
StateVector, StickyIndex, Store, SubdocsEvent, SubdocsEventIter, Text, TextRef, Transact,
TransactionCleanupEvent, Update, Xml, XmlElementPrelim, XmlElementRef, XmlFragmentRef,
XmlTextPrelim, XmlTextRef, ID,
};
pub const Y_JSON: i8 = -9;
pub const Y_JSON_BOOL: i8 = -8;
pub const Y_JSON_NUM: i8 = -7;
pub const Y_JSON_INT: i8 = -6;
pub const Y_JSON_STR: i8 = -5;
pub const Y_JSON_BUF: i8 = -4;
pub const Y_JSON_ARR: i8 = -3;
pub const Y_JSON_MAP: i8 = -2;
pub const Y_JSON_NULL: i8 = -1;
pub const Y_JSON_UNDEF: i8 = 0;
pub const Y_ARRAY: i8 = 1;
pub const Y_MAP: i8 = 2;
pub const Y_TEXT: i8 = 3;
pub const Y_XML_ELEM: i8 = 4;
pub const Y_XML_TEXT: i8 = 5;
pub const Y_XML_FRAG: i8 = 6;
pub const Y_DOC: i8 = 7;
pub const Y_WEAK_LINK: i8 = 8;
pub const Y_UNDEFINED: i8 = 9;
pub const Y_TRUE: u8 = 1;
pub const Y_FALSE: u8 = 0;
pub const Y_OFFSET_BYTES: u8 = 0;
pub const Y_OFFSET_UTF16: u8 = 1;
pub type Doc = yrs::Doc;
pub type Branch = yrs::branch::Branch;
pub type Subscription = yrs::Subscription;
#[repr(transparent)]
pub struct ArrayIter(NativeArrayIter<&'static Transaction, Transaction>);
#[repr(transparent)]
pub struct WeakIter(NativeUnquote<'static, Transaction>);
#[repr(transparent)]
pub struct MapIter(NativeMapIter<'static, &'static Transaction, Transaction>);
#[repr(transparent)]
pub struct Attributes(NativeAttributes<'static, &'static Transaction, Transaction>);
#[repr(transparent)]
pub struct TreeWalker(NativeTreeWalker<'static, &'static Transaction, Transaction>);
#[repr(transparent)]
pub struct Transaction(TransactionInner);
#[repr(C)]
pub struct JsonPathIter {
query: String,
json_path: Box<JsonPath<'static>>,
inner: NativeJsonPathIter<'static, Transaction>,
}
enum TransactionInner {
ReadOnly(yrs::Transaction<'static>),
ReadWrite(yrs::TransactionMut<'static>),
}
impl Transaction {
fn read_only(txn: yrs::Transaction) -> Self {
Transaction(TransactionInner::ReadOnly(unsafe {
std::mem::transmute(txn)
}))
}
fn read_write(txn: yrs::TransactionMut) -> Self {
Transaction(TransactionInner::ReadWrite(unsafe {
std::mem::transmute(txn)
}))
}
fn is_writeable(&self) -> bool {
match &self.0 {
TransactionInner::ReadOnly(_) => false,
TransactionInner::ReadWrite(_) => true,
}
}
fn as_mut(&mut self) -> Option<&mut yrs::TransactionMut<'static>> {
match &mut self.0 {
TransactionInner::ReadOnly(_) => None,
TransactionInner::ReadWrite(txn) => Some(txn),
}
}
}
impl ReadTxn for Transaction {
fn store(&self) -> &Store {
match &self.0 {
TransactionInner::ReadOnly(txn) => txn.store(),
TransactionInner::ReadWrite(txn) => txn.store(),
}
}
}
#[repr(C)]
pub struct YMapEntry {
pub key: *const c_char,
pub value: *const YOutput,
}
impl YMapEntry {
fn new(key: &str, value: Box<YOutput>) -> Self {
let key = CString::new(key).unwrap().into_raw();
let value = Box::into_raw(value) as *const YOutput;
YMapEntry { key, value }
}
}
impl Drop for YMapEntry {
fn drop(&mut self) {
unsafe {
drop(CString::from_raw(self.key as *mut c_char));
drop(Box::from_raw(self.value as *mut YOutput));
}
}
}
#[repr(C)]
pub struct YXmlAttr {
pub name: *const c_char,
pub value: *const c_char,
}
impl Drop for YXmlAttr {
fn drop(&mut self) {
unsafe {
drop(CString::from_raw(self.name as *mut _));
drop(CString::from_raw(self.value as *mut _));
}
}
}
#[repr(C)]
pub struct YOptions {
pub id: u64,
pub guid: *const c_char,
pub collection_id: *const c_char,
pub encoding: u8,
pub skip_gc: u8,
pub auto_load: u8,
pub should_load: u8,
}
impl Into<Options> for YOptions {
fn into(self) -> Options {
let encoding = match self.encoding {
Y_OFFSET_BYTES => OffsetKind::Bytes,
Y_OFFSET_UTF16 => OffsetKind::Utf16,
_ => panic!("Unrecognized YOptions.encoding type"),
};
let guid = if self.guid.is_null() {
uuid_v4()
} else {
let c_str = unsafe { CStr::from_ptr(self.guid) };
let str = c_str.to_str().unwrap();
str.into()
};
let collection_id = if self.collection_id.is_null() {
None
} else {
let c_str = unsafe { CStr::from_ptr(self.collection_id) };
let str = Arc::from(c_str.to_str().unwrap());
Some(str)
};
Options {
client_id: self.id as ClientID,
guid,
collection_id,
skip_gc: if self.skip_gc == 0 { false } else { true },
auto_load: if self.auto_load == 0 { false } else { true },
should_load: if self.should_load == 0 { false } else { true },
offset_kind: encoding,
}
}
}
impl From<Options> for YOptions {
fn from(o: Options) -> Self {
YOptions {
id: o.client_id,
guid: CString::new(o.guid.as_ref()).unwrap().into_raw(),
collection_id: if let Some(collection_id) = o.collection_id {
CString::new(collection_id.to_string()).unwrap().into_raw()
} else {
null_mut()
},
encoding: match o.offset_kind {
OffsetKind::Bytes => Y_OFFSET_BYTES,
OffsetKind::Utf16 => Y_OFFSET_UTF16,
},
skip_gc: if o.skip_gc { 1 } else { 0 },
auto_load: if o.auto_load { 1 } else { 0 },
should_load: if o.should_load { 1 } else { 0 },
}
}
}
#[no_mangle]
pub unsafe extern "C" fn yoptions() -> YOptions {
Options::default().into()
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_destroy(value: *mut Doc) {
if !value.is_null() {
drop(Box::from_raw(value));
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_entry_destroy(value: *mut YMapEntry) {
if !value.is_null() {
drop(Box::from_raw(value));
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlattr_destroy(attr: *mut YXmlAttr) {
if !attr.is_null() {
drop(Box::from_raw(attr));
}
}
#[no_mangle]
pub unsafe extern "C" fn ystring_destroy(str: *mut c_char) {
if !str.is_null() {
drop(CString::from_raw(str));
}
}
#[no_mangle]
pub unsafe extern "C" fn ybinary_destroy(ptr: *mut c_char, len: u32) {
if !ptr.is_null() {
drop(Vec::from_raw_parts(ptr, len as usize, len as usize));
}
}
#[no_mangle]
pub extern "C" fn ydoc_new() -> *mut Doc {
Box::into_raw(Box::new(Doc::new()))
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_clone(doc: *mut Doc) -> *mut Doc {
let doc = doc.as_mut().unwrap();
Box::into_raw(Box::new(doc.clone()))
}
#[no_mangle]
pub extern "C" fn ydoc_new_with_options(options: YOptions) -> *mut Doc {
Box::into_raw(Box::new(Doc::with_options(options.into())))
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_id(doc: *mut Doc) -> u64 {
let doc = doc.as_ref().unwrap();
doc.client_id()
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_guid(doc: *mut Doc) -> *mut c_char {
let doc = doc.as_ref().unwrap();
let uid = doc.guid();
CString::new(uid.as_ref()).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_collection_id(doc: *mut Doc) -> *mut c_char {
let doc = doc.as_ref().unwrap();
if let Some(cid) = doc.collection_id() {
CString::new(cid.as_ref()).unwrap().into_raw()
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_should_load(doc: *mut Doc) -> u8 {
let doc = doc.as_ref().unwrap();
doc.should_load() as u8
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_auto_load(doc: *mut Doc) -> u8 {
let doc = doc.as_ref().unwrap();
doc.auto_load() as u8
}
#[repr(transparent)]
struct CallbackState(*mut c_void);
unsafe impl Send for CallbackState {}
unsafe impl Sync for CallbackState {}
impl CallbackState {
#[inline]
fn new(state: *mut c_void) -> Self {
CallbackState(state)
}
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_observe_updates_v1(
doc: *mut Doc,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, u32, *const c_char),
) -> *mut Subscription {
let state = CallbackState::new(state);
let doc = doc.as_ref().unwrap();
let subscription = doc
.observe_update_v1(move |_, e| {
let bytes = &e.update;
let len = bytes.len() as u32;
cb(state.0, len, bytes.as_ptr() as *const c_char)
})
.unwrap();
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_observe_updates_v2(
doc: *mut Doc,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, u32, *const c_char),
) -> *mut Subscription {
let state = CallbackState::new(state);
let doc = doc.as_ref().unwrap();
let subscription = doc
.observe_update_v2(move |_, e| {
let bytes = &e.update;
let len = bytes.len() as u32;
cb(state.0, len, bytes.as_ptr() as *const c_char)
})
.unwrap();
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_observe_after_transaction(
doc: *mut Doc,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *mut YAfterTransactionEvent),
) -> *mut Subscription {
let state = CallbackState::new(state);
let doc = doc.as_ref().unwrap();
let subscription = doc
.observe_transaction_cleanup(move |_, e| {
let mut event = YAfterTransactionEvent::new(e);
cb(state.0, (&mut event) as *mut _);
})
.unwrap();
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_observe_subdocs(
doc: *mut Doc,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *mut YSubdocsEvent),
) -> *mut Subscription {
let state = CallbackState::new(state);
let doc = doc.as_mut().unwrap();
let subscription = doc
.observe_subdocs(move |_, e| {
let mut event = YSubdocsEvent::new(e);
cb(state.0, (&mut event) as *mut _);
})
.unwrap();
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_observe_clear(
doc: *mut Doc,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *mut Doc),
) -> *mut Subscription {
let state = CallbackState::new(state);
let doc = doc.as_mut().unwrap();
let subscription = doc
.observe_destroy(move |_, e| cb(state.0, e as *const Doc as *mut _))
.unwrap();
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_load(doc: *mut Doc, parent_txn: *mut Transaction) {
let doc = doc.as_ref().unwrap();
let txn = parent_txn.as_mut().unwrap();
if let Some(txn) = txn.as_mut() {
doc.load(txn)
} else {
panic!("ydoc_load: passed read-only parent transaction, where read-write one was expected")
}
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_clear(doc: *mut Doc, parent_txn: *mut Transaction) {
let doc = doc.as_mut().unwrap();
let txn = parent_txn.as_mut().unwrap();
if let Some(txn) = txn.as_mut() {
doc.destroy(txn)
} else {
panic!("ydoc_clear: passed read-only parent transaction, where read-write one was expected")
}
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_read_transaction(doc: *mut Doc) -> *mut Transaction {
assert!(!doc.is_null());
let doc = doc.as_mut().unwrap();
if let Ok(txn) = doc.try_transact() {
Box::into_raw(Box::new(Transaction::read_only(txn)))
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ydoc_write_transaction(
doc: *mut Doc,
origin_len: u32,
origin: *const c_char,
) -> *mut Transaction {
assert!(!doc.is_null());
let doc = doc.as_mut().unwrap();
if origin_len == 0 {
if let Ok(txn) = doc.try_transact_mut() {
Box::into_raw(Box::new(Transaction::read_write(txn)))
} else {
null_mut()
}
} else {
let origin = std::slice::from_raw_parts(origin as *const u8, origin_len as usize);
if let Ok(txn) = doc.try_transact_mut_with(origin) {
Box::into_raw(Box::new(Transaction::read_write(txn)))
} else {
null_mut()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_subdocs(
txn: *mut Transaction,
len: *mut u32,
) -> *mut *mut Doc {
let txn = txn.as_ref().unwrap();
let subdocs: Vec<_> = txn
.subdocs()
.map(|doc| doc as *const Doc as *mut Doc)
.collect();
let out = subdocs.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_commit(txn: *mut Transaction) {
assert!(!txn.is_null());
drop(Box::from_raw(txn)); }
#[no_mangle]
pub unsafe extern "C" fn ytransaction_force_gc(txn: *mut Transaction) {
assert!(!txn.is_null());
let txn = txn.as_mut().unwrap();
let txn = txn.as_mut().unwrap();
txn.force_gc();
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_writeable(txn: *mut Transaction) -> u8 {
assert!(!txn.is_null());
if txn.as_ref().unwrap().is_writeable() {
1
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_json_path(
txn: *mut Transaction,
json_path: *const c_char,
) -> *mut JsonPathIter {
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let query: String = CStr::from_ptr(json_path).to_str().unwrap().into();
let json_path: &'static str = unsafe { std::mem::transmute(query.as_str()) };
let json_path = match JsonPath::parse(json_path) {
Ok(query) => Box::new(query),
Err(_) => return null_mut(),
};
let json_path_ref: &'static JsonPath = unsafe { std::mem::transmute(json_path.as_ref()) };
let inner = txn.json_path(json_path_ref);
let iter = Box::new(JsonPathIter {
query,
json_path,
inner,
});
Box::into_raw(iter)
}
#[no_mangle]
pub unsafe extern "C" fn yjson_path_iter_next(iter: *mut JsonPathIter) -> *mut YOutput {
assert!(!iter.is_null());
let iter = iter.as_mut().unwrap();
if let Some(value) = iter.inner.next() {
let youtput = YOutput::from(value);
Box::into_raw(Box::new(youtput))
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yjson_path_iter_destroy(iter: *mut JsonPathIter) {
if !iter.is_null() {
drop(Box::from_raw(iter));
}
}
#[no_mangle]
pub unsafe extern "C" fn ytype_get(txn: *mut Transaction, name: *const c_char) -> *mut Branch {
assert!(!txn.is_null());
assert!(!name.is_null());
let name = CStr::from_ptr(name).to_str().unwrap();
if let Some(txt) = txn.as_mut().unwrap().get_text(name) {
txt.into_raw_branch()
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext(doc: *mut Doc, name: *const c_char) -> *mut Branch {
assert!(!doc.is_null());
assert!(!name.is_null());
let name = CStr::from_ptr(name).to_str().unwrap();
let txt = doc.as_mut().unwrap().get_or_insert_text(name);
txt.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn yarray(doc: *mut Doc, name: *const c_char) -> *mut Branch {
assert!(!doc.is_null());
assert!(!name.is_null());
let name = CStr::from_ptr(name).to_str().unwrap();
doc.as_mut()
.unwrap()
.get_or_insert_array(name)
.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn ymap(doc: *mut Doc, name: *const c_char) -> *mut Branch {
assert!(!doc.is_null());
assert!(!name.is_null());
let name = CStr::from_ptr(name).to_str().unwrap();
doc.as_mut()
.unwrap()
.get_or_insert_map(name)
.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn yxmlfragment(doc: *mut Doc, name: *const c_char) -> *mut Branch {
assert!(!doc.is_null());
assert!(!name.is_null());
let name = CStr::from_ptr(name).to_str().unwrap();
doc.as_mut()
.unwrap()
.get_or_insert_xml_fragment(name)
.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_state_vector_v1(
txn: *const Transaction,
len: *mut u32,
) -> *mut c_char {
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let state_vector = txn.state_vector();
let binary = state_vector.encode_v1().into_boxed_slice();
*len = binary.len() as u32;
Box::into_raw(binary) as *mut c_char
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_state_diff_v1(
txn: *const Transaction,
sv: *const c_char,
sv_len: u32,
len: *mut u32,
) -> *mut c_char {
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let sv = {
if sv.is_null() {
StateVector::default()
} else {
let sv_slice = std::slice::from_raw_parts(sv as *const u8, sv_len as usize);
if let Ok(sv) = StateVector::decode_v1(sv_slice) {
sv
} else {
return null_mut();
}
}
};
let mut encoder = EncoderV1::new();
txn.encode_diff(&sv, &mut encoder);
let binary = encoder.to_vec().into_boxed_slice();
*len = binary.len() as u32;
Box::into_raw(binary) as *mut c_char
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_state_diff_v2(
txn: *const Transaction,
sv: *const c_char,
sv_len: u32,
len: *mut u32,
) -> *mut c_char {
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let sv = {
if sv.is_null() {
StateVector::default()
} else {
let sv_slice = std::slice::from_raw_parts(sv as *const u8, sv_len as usize);
if let Ok(sv) = StateVector::decode_v1(sv_slice) {
sv
} else {
return null_mut();
}
}
};
let mut encoder = EncoderV2::new();
txn.encode_diff(&sv, &mut encoder);
let binary = encoder.to_vec().into_boxed_slice();
*len = binary.len() as u32;
Box::into_raw(binary) as *mut c_char
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_snapshot(
txn: *const Transaction,
len: *mut u32,
) -> *mut c_char {
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let binary = txn.snapshot().encode_v1().into_boxed_slice();
*len = binary.len() as u32;
Box::into_raw(binary) as *mut c_char
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_encode_state_from_snapshot_v1(
txn: *const Transaction,
snapshot: *const c_char,
snapshot_len: u32,
len: *mut u32,
) -> *mut c_char {
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let snapshot = {
let len = snapshot_len as usize;
let data = std::slice::from_raw_parts(snapshot as *mut u8, len);
Snapshot::decode_v1(&data).unwrap()
};
let mut encoder = EncoderV1::new();
match txn.encode_state_from_snapshot(&snapshot, &mut encoder) {
Err(_) => null_mut(),
Ok(_) => {
let binary = encoder.to_vec().into_boxed_slice();
*len = binary.len() as u32;
Box::into_raw(binary) as *mut c_char
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_encode_state_from_snapshot_v2(
txn: *const Transaction,
snapshot: *const c_char,
snapshot_len: u32,
len: *mut u32,
) -> *mut c_char {
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let snapshot = {
let len = snapshot_len as usize;
let data = std::slice::from_raw_parts(snapshot as *mut u8, len);
Snapshot::decode_v1(&data).unwrap()
};
let mut encoder = EncoderV2::new();
match txn.encode_state_from_snapshot(&snapshot, &mut encoder) {
Err(_) => null_mut(),
Ok(_) => {
let binary = encoder.to_vec().into_boxed_slice();
*len = binary.len() as u32;
Box::into_raw(binary) as *mut c_char
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_pending_ds(txn: *const Transaction) -> *mut YDeleteSet {
let txn = txn.as_ref().unwrap();
match txn.store().pending_ds() {
None => null_mut(),
Some(ds) => Box::into_raw(Box::new(YDeleteSet::new(ds))),
}
}
#[no_mangle]
pub unsafe extern "C" fn ydelete_set_destroy(ds: *mut YDeleteSet) {
if ds.is_null() {
return;
}
drop(Box::from_raw(ds))
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_pending_update(
txn: *const Transaction,
) -> *mut YPendingUpdate {
let txn = txn.as_ref().unwrap();
match txn.store().pending_update() {
None => null_mut(),
Some(u) => {
let binary = u.update.encode_v1().into_boxed_slice();
let update_len = binary.len() as u32;
let missing = YStateVector::new(&u.missing);
let update = YPendingUpdate {
missing,
update_len,
update_v1: Box::into_raw(binary) as *mut c_char,
};
Box::into_raw(Box::new(update))
}
}
}
#[repr(C)]
pub struct YPendingUpdate {
pub missing: YStateVector,
pub update_v1: *mut c_char,
pub update_len: u32,
}
#[no_mangle]
pub unsafe extern "C" fn ypending_update_destroy(update: *mut YPendingUpdate) {
if update.is_null() {
return;
}
let update = Box::from_raw(update);
drop(update.missing);
ybinary_destroy(update.update_v1, update.update_len);
}
#[no_mangle]
pub unsafe extern "C" fn yupdate_debug_v1(update: *const c_char, update_len: u32) -> *mut c_char {
assert!(!update.is_null());
let data = std::slice::from_raw_parts(update as *const u8, update_len as usize);
if let Ok(u) = Update::decode_v1(data) {
let str = format!("{:#?}", u);
CString::new(str).unwrap().into_raw()
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yupdate_debug_v2(update: *const c_char, update_len: u32) -> *mut c_char {
assert!(!update.is_null());
let data = std::slice::from_raw_parts(update as *const u8, update_len as usize);
if let Ok(u) = Update::decode_v2(data) {
let str = format!("{:#?}", u);
CString::new(str).unwrap().into_raw()
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_apply(
txn: *mut Transaction,
diff: *const c_char,
diff_len: u32,
) -> u8 {
assert!(!txn.is_null());
assert!(!diff.is_null());
let update = std::slice::from_raw_parts(diff as *const u8, diff_len as usize);
let mut decoder = DecoderV1::from(update);
match Update::decode(&mut decoder) {
Ok(update) => {
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
match txn.apply_update(update) {
Ok(_) => 0,
Err(e) => update_err_code(e),
}
}
Err(e) => err_code(e),
}
}
#[no_mangle]
pub unsafe extern "C" fn ytransaction_apply_v2(
txn: *mut Transaction,
diff: *const c_char,
diff_len: u32,
) -> u8 {
assert!(!txn.is_null());
assert!(!diff.is_null());
let mut update = std::slice::from_raw_parts(diff as *const u8, diff_len as usize);
match Update::decode_v2(&mut update) {
Ok(update) => {
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
match txn.apply_update(update) {
Ok(_) => 0,
Err(e) => update_err_code(e),
}
}
Err(e) => err_code(e),
}
}
pub const ERR_CODE_IO: u8 = 1;
pub const ERR_CODE_VAR_INT: u8 = 2;
pub const ERR_CODE_EOS: u8 = 3;
pub const ERR_CODE_UNEXPECTED_VALUE: u8 = 4;
pub const ERR_CODE_INVALID_JSON: u8 = 5;
pub const ERR_CODE_OTHER: u8 = 6;
pub const ERR_NOT_ENOUGH_MEMORY: u8 = 7;
pub const ERR_TYPE_MISMATCH: u8 = 8;
pub const ERR_CUSTOM: u8 = 9;
pub const ERR_INVALID_PARENT: u8 = 9;
fn err_code(e: Error) -> u8 {
match e {
Error::InvalidVarInt => ERR_CODE_VAR_INT,
Error::EndOfBuffer(_) => ERR_CODE_EOS,
Error::UnexpectedValue => ERR_CODE_UNEXPECTED_VALUE,
Error::InvalidJSON(_) => ERR_CODE_INVALID_JSON,
Error::NotEnoughMemory(_) => ERR_NOT_ENOUGH_MEMORY,
Error::TypeMismatch(_) => ERR_TYPE_MISMATCH,
Error::Custom(_) => ERR_CUSTOM,
}
}
fn update_err_code(e: UpdateError) -> u8 {
match e {
UpdateError::InvalidParent(_, _) => ERR_INVALID_PARENT,
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_len(txt: *const Branch, txn: *const Transaction) -> u32 {
assert!(!txt.is_null());
let txn = txn.as_ref().unwrap();
let txt = TextRef::from_raw_branch(txt);
txt.len(txn)
}
#[no_mangle]
pub unsafe extern "C" fn ytext_string(txt: *const Branch, txn: *const Transaction) -> *mut c_char {
assert!(!txt.is_null());
let txn = txn.as_ref().unwrap();
let txt = TextRef::from_raw_branch(txt);
let str = txt.get_string(txn);
CString::new(str).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn ytext_insert(
txt: *const Branch,
txn: *mut Transaction,
index: u32,
value: *const c_char,
attrs: *const YInput,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!value.is_null());
let chunk = CStr::from_ptr(value).to_str().unwrap();
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let txt = TextRef::from_raw_branch(txt);
let index = index as u32;
if attrs.is_null() {
txt.insert(txn, index, chunk)
} else {
if let Some(attrs) = map_attrs(attrs.read().into()) {
txt.insert_with_attributes(txn, index, chunk, attrs)
} else {
panic!("ytext_insert: passed attributes are not of map type")
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_format(
txt: *const Branch,
txn: *mut Transaction,
index: u32,
len: u32,
attrs: *const YInput,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!attrs.is_null());
if let Some(attrs) = map_attrs(attrs.read().into()) {
let txt = TextRef::from_raw_branch(txt);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let index = index as u32;
let len = len as u32;
txt.format(txn, index, len, attrs);
} else {
panic!("ytext_format: passed attributes are not of map type")
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_insert_embed(
txt: *const Branch,
txn: *mut Transaction,
index: u32,
content: *const YInput,
attrs: *const YInput,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!content.is_null());
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let txt = TextRef::from_raw_branch(txt);
let index = index as u32;
let content = content.read();
if attrs.is_null() {
txt.insert_embed(txn, index, content);
} else {
if let Some(attrs) = map_attrs(attrs.read().into()) {
txt.insert_embed_with_attributes(txn, index, content, attrs);
} else {
panic!("ytext_insert_embed: passed attributes are not of map type")
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_insert_delta(
txt: *const Branch,
txn: *mut Transaction,
delta: *mut YDeltaIn,
delta_len: u32,
) {
let txt = TextRef::from_raw_branch(txt);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let delta = std::slice::from_raw_parts(delta, delta_len as usize);
let mut insert = Vec::with_capacity(delta.len());
for chunk in delta {
let d = chunk.as_input();
insert.push(d);
}
txt.apply_delta(txn, insert);
}
#[no_mangle]
pub unsafe extern "C" fn ydelta_input_retain(len: u32, attrs: *const YInput) -> YDeltaIn {
YDeltaIn {
tag: Y_EVENT_CHANGE_RETAIN,
len,
attributes: attrs,
insert: null(),
}
}
#[no_mangle]
pub unsafe extern "C" fn ydelta_input_delete(len: u32) -> YDeltaIn {
YDeltaIn {
tag: Y_EVENT_CHANGE_DELETE,
len,
attributes: null(),
insert: null(),
}
}
#[no_mangle]
pub unsafe extern "C" fn ydelta_input_insert(
data: *const YInput,
attrs: *const YInput,
) -> YDeltaIn {
YDeltaIn {
tag: Y_EVENT_CHANGE_ADD,
len: 1,
attributes: attrs,
insert: data,
}
}
fn map_attrs(attrs: Any) -> Option<Attrs> {
if let Any::Map(attrs) = attrs {
let attrs = attrs
.iter()
.map(|(k, v)| (k.as_str().into(), v.clone()))
.collect();
Some(attrs)
} else {
None
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_remove_range(
txt: *const Branch,
txn: *mut Transaction,
index: u32,
length: u32,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let txt = TextRef::from_raw_branch(txt);
txt.remove_range(txn, index as u32, length as u32)
}
#[no_mangle]
pub unsafe extern "C" fn yarray_len(array: *const Branch) -> u32 {
assert!(!array.is_null());
let array = array.as_ref().unwrap();
array.len() as u32
}
#[no_mangle]
pub unsafe extern "C" fn yarray_get(
array: *const Branch,
txn: *const Transaction,
index: u32,
) -> *mut YOutput {
assert!(!array.is_null());
let array = ArrayRef::from_raw_branch(array);
let txn = txn.as_ref().unwrap();
if let Some(val) = array.get(txn, index as u32) {
Box::into_raw(Box::new(YOutput::from(val)))
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yarray_get_json(
array: *const Branch,
txn: *const Transaction,
index: u32,
) -> *mut c_char {
assert!(!array.is_null());
let array = ArrayRef::from_raw_branch(array);
let txn = txn.as_ref().unwrap();
if let Some(val) = array.get(txn, index as u32) {
let any = val.to_json(txn);
let json = match serde_json::to_string(&any) {
Ok(json) => json,
Err(_) => return std::ptr::null_mut(),
};
CString::new(json).unwrap().into_raw()
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yarray_insert_range(
array: *const Branch,
txn: *mut Transaction,
index: u32,
items: *const YInput,
items_len: u32,
) {
assert!(!array.is_null());
assert!(!txn.is_null());
assert!(!items.is_null());
let array = ArrayRef::from_raw_branch(array);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let ptr = items;
let mut i = 0;
let mut j = index as u32;
let len = items_len as isize;
while i < len {
let mut vec: Vec<Any> = Vec::default();
while i < len {
let val = ptr.offset(i).read();
if val.tag <= 0 {
let any = val.into();
vec.push(any);
} else {
break;
}
i += 1;
}
if !vec.is_empty() {
let len = vec.len() as u32;
array.insert_range(txn, j, vec);
j += len;
} else {
let val = ptr.offset(i).read();
array.insert(txn, j, val);
i += 1;
j += 1;
}
}
}
#[no_mangle]
pub unsafe extern "C" fn yarray_remove_range(
array: *const Branch,
txn: *mut Transaction,
index: u32,
len: u32,
) {
assert!(!array.is_null());
assert!(!txn.is_null());
let array = ArrayRef::from_raw_branch(array);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
array.remove_range(txn, index as u32, len as u32)
}
#[no_mangle]
pub unsafe extern "C" fn yarray_move(
array: *const Branch,
txn: *mut Transaction,
source: u32,
target: u32,
) {
assert!(!array.is_null());
assert!(!txn.is_null());
let array = ArrayRef::from_raw_branch(array);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
array.move_to(txn, source as u32, target as u32)
}
#[no_mangle]
pub unsafe extern "C" fn yarray_iter(
array: *const Branch,
txn: *mut Transaction,
) -> *mut ArrayIter {
assert!(!array.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let array = &ArrayRef::from_raw_branch(array) as *const ArrayRef;
Box::into_raw(Box::new(ArrayIter(array.as_ref().unwrap().iter(txn))))
}
#[no_mangle]
pub unsafe extern "C" fn yarray_iter_destroy(iter: *mut ArrayIter) {
if !iter.is_null() {
drop(Box::from_raw(iter))
}
}
#[no_mangle]
pub unsafe extern "C" fn yarray_iter_next(iterator: *mut ArrayIter) -> *mut YOutput {
assert!(!iterator.is_null());
let iter = iterator.as_mut().unwrap();
if let Some(v) = iter.0.next() {
let out = YOutput::from(v);
Box::into_raw(Box::new(out))
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_iter(map: *const Branch, txn: *const Transaction) -> *mut MapIter {
assert!(!map.is_null());
let txn = txn.as_ref().unwrap();
let map = &MapRef::from_raw_branch(map) as *const MapRef;
Box::into_raw(Box::new(MapIter(map.as_ref().unwrap().iter(txn))))
}
#[no_mangle]
pub unsafe extern "C" fn ymap_iter_destroy(iter: *mut MapIter) {
if !iter.is_null() {
drop(Box::from_raw(iter))
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_iter_next(iter: *mut MapIter) -> *mut YMapEntry {
assert!(!iter.is_null());
let iter = iter.as_mut().unwrap();
if let Some((key, value)) = iter.0.next() {
let output = YOutput::from(value);
Box::into_raw(Box::new(YMapEntry::new(key, Box::new(output))))
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_len(map: *const Branch, txn: *const Transaction) -> u32 {
assert!(!map.is_null());
let txn = txn.as_ref().unwrap();
let map = MapRef::from_raw_branch(map);
map.len(txn)
}
#[no_mangle]
pub unsafe extern "C" fn ymap_insert(
map: *const Branch,
txn: *mut Transaction,
key: *const c_char,
value: *const YInput,
) {
assert!(!map.is_null());
assert!(!txn.is_null());
assert!(!key.is_null());
assert!(!value.is_null());
let cstr = CStr::from_ptr(key);
let key = cstr.to_str().unwrap().to_string();
let map = MapRef::from_raw_branch(map);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
map.insert(txn, key, value.read());
}
#[no_mangle]
pub unsafe extern "C" fn ymap_remove(
map: *const Branch,
txn: *mut Transaction,
key: *const c_char,
) -> u8 {
assert!(!map.is_null());
assert!(!txn.is_null());
assert!(!key.is_null());
let key = CStr::from_ptr(key).to_str().unwrap();
let map = MapRef::from_raw_branch(map);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
if let Some(_) = map.remove(txn, key) {
Y_TRUE
} else {
Y_FALSE
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_get(
map: *const Branch,
txn: *const Transaction,
key: *const c_char,
) -> *mut YOutput {
assert!(!map.is_null());
assert!(!key.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let key = CStr::from_ptr(key).to_str().unwrap();
let map = MapRef::from_raw_branch(map);
if let Some(value) = map.get(txn, key) {
let output = YOutput::from(value);
Box::into_raw(Box::new(output))
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_get_json(
map: *const Branch,
txn: *const Transaction,
key: *const c_char,
) -> *mut c_char {
assert!(!map.is_null());
assert!(!key.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let key = CStr::from_ptr(key).to_str().unwrap();
let map = MapRef::from_raw_branch(map);
if let Some(value) = map.get(txn, key) {
let any = value.to_json(txn);
match serde_json::to_string(&any) {
Ok(json) => CString::new(json).unwrap().into_raw(),
Err(_) => std::ptr::null_mut(),
}
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_remove_all(map: *const Branch, txn: *mut Transaction) {
assert!(!map.is_null());
assert!(!txn.is_null());
let map = MapRef::from_raw_branch(map);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
map.clear(txn);
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_tag(xml: *const Branch) -> *mut c_char {
assert!(!xml.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
if let Some(tag) = xml.try_tag() {
CString::new(tag.deref()).unwrap().into_raw()
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_string(
xml: *const Branch,
txn: *const Transaction,
) -> *mut c_char {
assert!(!xml.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let xml = XmlElementRef::from_raw_branch(xml);
let str = xml.get_string(txn);
CString::new(str).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_insert_attr(
xml: *const Branch,
txn: *mut Transaction,
attr_name: *const c_char,
attr_value: *const c_char,
) {
assert!(!xml.is_null());
assert!(!txn.is_null());
assert!(!attr_name.is_null());
assert!(!attr_value.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let key = CStr::from_ptr(attr_name).to_str().unwrap();
let value = CStr::from_ptr(attr_value).to_str().unwrap();
xml.insert_attribute(txn, key, value);
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_remove_attr(
xml: *const Branch,
txn: *mut Transaction,
attr_name: *const c_char,
) {
assert!(!xml.is_null());
assert!(!txn.is_null());
assert!(!attr_name.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let key = CStr::from_ptr(attr_name).to_str().unwrap();
xml.remove_attribute(txn, &key);
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_get_attr(
xml: *const Branch,
txn: *const Transaction,
attr_name: *const c_char,
) -> *mut c_char {
assert!(!xml.is_null());
assert!(!attr_name.is_null());
assert!(!txn.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let key = CStr::from_ptr(attr_name).to_str().unwrap();
let txn = txn.as_ref().unwrap();
if let Some(value) = xml.get_attribute(txn, key) {
CString::new(value).unwrap().into_raw()
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_attr_iter(
xml: *const Branch,
txn: *const Transaction,
) -> *mut Attributes {
assert!(!xml.is_null());
assert!(!txn.is_null());
let xml = &XmlElementRef::from_raw_branch(xml) as *const XmlElementRef;
let txn = txn.as_ref().unwrap();
Box::into_raw(Box::new(Attributes(xml.as_ref().unwrap().attributes(txn))))
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_attr_iter(
xml: *const Branch,
txn: *const Transaction,
) -> *mut Attributes {
assert!(!xml.is_null());
assert!(!txn.is_null());
let xml = &XmlTextRef::from_raw_branch(xml) as *const XmlTextRef;
let txn = txn.as_ref().unwrap();
Box::into_raw(Box::new(Attributes(xml.as_ref().unwrap().attributes(txn))))
}
#[no_mangle]
pub unsafe extern "C" fn yxmlattr_iter_destroy(iterator: *mut Attributes) {
if !iterator.is_null() {
drop(Box::from_raw(iterator))
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlattr_iter_next(iterator: *mut Attributes) -> *mut YXmlAttr {
assert!(!iterator.is_null());
let iter = iterator.as_mut().unwrap();
if let Some((name, value)) = iter.0.next() {
Box::into_raw(Box::new(YXmlAttr {
name: CString::new(name).unwrap().into_raw(),
value: CString::new(value).unwrap().into_raw(),
}))
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxml_next_sibling(
xml: *const Branch,
txn: *const Transaction,
) -> *mut YOutput {
assert!(!xml.is_null());
assert!(!txn.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_ref().unwrap();
let mut siblings = xml.siblings(txn);
if let Some(next) = siblings.next() {
match next {
XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
}
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxml_prev_sibling(
xml: *const Branch,
txn: *const Transaction,
) -> *mut YOutput {
assert!(!xml.is_null());
assert!(!txn.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_ref().unwrap();
let mut siblings = xml.siblings(txn);
if let Some(next) = siblings.next_back() {
match next {
XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
}
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_parent(xml: *const Branch) -> *mut Branch {
assert!(!xml.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
if let Some(parent) = xml.parent() {
let branch = parent.as_ptr();
branch.deref() as *const Branch as *mut Branch
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_child_len(xml: *const Branch, txn: *const Transaction) -> u32 {
assert!(!xml.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let xml = XmlElementRef::from_raw_branch(xml);
xml.len(txn) as u32
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_first_child(xml: *const Branch) -> *mut YOutput {
assert!(!xml.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
if let Some(value) = xml.first_child() {
match value {
XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
}
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_tree_walker(
xml: *const Branch,
txn: *const Transaction,
) -> *mut TreeWalker {
assert!(!xml.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let xml = &XmlElementRef::from_raw_branch(xml) as *const XmlElementRef;
Box::into_raw(Box::new(TreeWalker(xml.as_ref().unwrap().successors(txn))))
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_tree_walker_destroy(iter: *mut TreeWalker) {
if !iter.is_null() {
drop(Box::from_raw(iter))
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_tree_walker_next(iterator: *mut TreeWalker) -> *mut YOutput {
assert!(!iterator.is_null());
let iter = iterator.as_mut().unwrap();
if let Some(next) = iter.0.next() {
match next {
XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
}
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_insert_elem(
xml: *const Branch,
txn: *mut Transaction,
index: u32,
name: *const c_char,
) -> *mut Branch {
assert!(!xml.is_null());
assert!(!txn.is_null());
assert!(!name.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let name = CStr::from_ptr(name).to_str().unwrap();
xml.insert(txn, index as u32, XmlElementPrelim::empty(name))
.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_insert_text(
xml: *const Branch,
txn: *mut Transaction,
index: u32,
) -> *mut Branch {
assert!(!xml.is_null());
assert!(!txn.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
xml.insert(txn, index as u32, XmlTextPrelim::new(""))
.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_remove_range(
xml: *const Branch,
txn: *mut Transaction,
index: u32,
len: u32,
) {
assert!(!xml.is_null());
assert!(!txn.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
xml.remove_range(txn, index as u32, len as u32)
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_get(
xml: *const Branch,
txn: *const Transaction,
index: u32,
) -> *const YOutput {
assert!(!xml.is_null());
assert!(!txn.is_null());
let xml = XmlElementRef::from_raw_branch(xml);
let txn = txn.as_ref().unwrap();
if let Some(child) = xml.get(txn, index as u32) {
match child {
XmlOut::Element(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlElement(v)))),
XmlOut::Text(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlText(v)))),
XmlOut::Fragment(v) => Box::into_raw(Box::new(YOutput::from(Out::YXmlFragment(v)))),
}
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_len(txt: *const Branch, txn: *const Transaction) -> u32 {
assert!(!txt.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let txt = XmlTextRef::from_raw_branch(txt);
txt.len(txn) as u32
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_string(
txt: *const Branch,
txn: *const Transaction,
) -> *mut c_char {
assert!(!txt.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let txt = XmlTextRef::from_raw_branch(txt);
let str = txt.get_string(txn);
CString::new(str).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_insert(
txt: *const Branch,
txn: *mut Transaction,
index: u32,
str: *const c_char,
attrs: *const YInput,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!str.is_null());
let txt = XmlTextRef::from_raw_branch(txt);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let chunk = CStr::from_ptr(str).to_str().unwrap();
if attrs.is_null() {
txt.insert(txn, index as u32, chunk)
} else {
if let Some(attrs) = map_attrs(attrs.read().into()) {
txt.insert_with_attributes(txn, index as u32, chunk, attrs)
} else {
panic!("yxmltext_insert: passed attributes are not of map type")
}
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_insert_embed(
txt: *const Branch,
txn: *mut Transaction,
index: u32,
content: *const YInput,
attrs: *const YInput,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!content.is_null());
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let txt = XmlTextRef::from_raw_branch(txt);
let index = index as u32;
let content = content.read();
if attrs.is_null() {
txt.insert_embed(txn, index, content);
} else {
if let Some(attrs) = map_attrs(attrs.read().into()) {
txt.insert_embed_with_attributes(txn, index, content, attrs);
} else {
panic!("yxmltext_insert_embed: passed attributes are not of map type")
}
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_format(
txt: *const Branch,
txn: *mut Transaction,
index: u32,
len: u32,
attrs: *const YInput,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!attrs.is_null());
if let Some(attrs) = map_attrs(attrs.read().into()) {
let txt = XmlTextRef::from_raw_branch(txt);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let index = index as u32;
let len = len as u32;
txt.format(txn, index, len, attrs);
} else {
panic!("yxmltext_format: passed attributes are not of map type")
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_remove_range(
txt: *const Branch,
txn: *mut Transaction,
idx: u32,
len: u32,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
let txt = XmlTextRef::from_raw_branch(txt);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
txt.remove_range(txn, idx as u32, len as u32)
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_insert_attr(
txt: *const Branch,
txn: *mut Transaction,
attr_name: *const c_char,
attr_value: *const c_char,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!attr_name.is_null());
assert!(!attr_value.is_null());
let txt = XmlTextRef::from_raw_branch(txt);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let name = CStr::from_ptr(attr_name).to_str().unwrap();
let value = CStr::from_ptr(attr_value).to_str().unwrap();
txt.insert_attribute(txn, name, value)
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_remove_attr(
txt: *const Branch,
txn: *mut Transaction,
attr_name: *const c_char,
) {
assert!(!txt.is_null());
assert!(!txn.is_null());
assert!(!attr_name.is_null());
let txt = XmlTextRef::from_raw_branch(txt);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let name = CStr::from_ptr(attr_name).to_str().unwrap();
txt.remove_attribute(txn, &name)
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_get_attr(
txt: *const Branch,
txn: *const Transaction,
attr_name: *const c_char,
) -> *mut c_char {
assert!(!txt.is_null());
assert!(!attr_name.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let txt = XmlTextRef::from_raw_branch(txt);
let name = CStr::from_ptr(attr_name).to_str().unwrap();
if let Some(value) = txt.get_attribute(txn, name) {
CString::new(value).unwrap().into_raw()
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_chunks(
txt: *const Branch,
txn: *const Transaction,
chunks_len: *mut u32,
) -> *mut YChunk {
assert!(!txt.is_null());
assert!(!txn.is_null());
let txt = TextRef::from_raw_branch(txt);
let txn = txn.as_ref().unwrap();
let diffs = txt.diff(txn, YChange::identity);
let chunks: Vec<_> = diffs.into_iter().map(YChunk::from).collect();
let out = chunks.into_boxed_slice();
*chunks_len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn ychunks_destroy(chunks: *mut YChunk, len: u32) {
drop(Vec::from_raw_parts(chunks, len as usize, len as usize));
}
pub const YCHANGE_ADD: i8 = 1;
pub const YCHANGE_RETAIN: i8 = 0;
pub const YCHANGE_REMOVE: i8 = -1;
#[repr(C)]
pub struct YChunk {
pub data: YOutput,
pub fmt_len: u32,
pub fmt: *mut YMapEntry,
}
impl From<Diff<YChange>> for YChunk {
fn from(diff: Diff<YChange>) -> Self {
let data = YOutput::from(diff.insert);
let mut fmt_len = 0;
let fmt = if let Some(attrs) = diff.attributes {
fmt_len = attrs.len() as u32;
let mut fmt = Vec::with_capacity(attrs.len());
for (k, v) in attrs.into_iter() {
let output = YOutput::from(&v); let e = YMapEntry::new(k.as_ref(), Box::new(output));
fmt.push(e);
}
Box::into_raw(fmt.into_boxed_slice()) as *mut _
} else {
null_mut()
};
YChunk { data, fmt_len, fmt }
}
}
impl Drop for YChunk {
fn drop(&mut self) {
if !self.fmt.is_null() {
drop(unsafe {
Vec::from_raw_parts(self.fmt, self.fmt_len as usize, self.fmt_len as usize)
});
}
}
}
#[repr(C)]
pub struct YInput {
pub tag: i8,
pub len: u32,
value: YInputContent,
}
impl YInput {
fn into(self) -> Any {
let tag = self.tag;
unsafe {
match tag {
Y_JSON_STR => {
let str = CStr::from_ptr(self.value.str).to_str().unwrap().into();
Any::String(str)
}
Y_JSON => {
let json_str = CStr::from_ptr(self.value.str).to_str().unwrap();
serde_json::from_str(json_str).unwrap()
}
Y_JSON_NULL => Any::Null,
Y_JSON_UNDEF => Any::Undefined,
Y_JSON_INT => Any::BigInt(self.value.integer),
Y_JSON_NUM => Any::Number(self.value.num),
Y_JSON_BOOL => Any::Bool(if self.value.flag == 0 { false } else { true }),
Y_JSON_BUF => Any::from(std::slice::from_raw_parts(
self.value.buf as *mut u8,
self.len as usize,
)),
Y_JSON_ARR => {
let ptr = self.value.values;
let mut dst: Vec<Any> = Vec::with_capacity(self.len as usize);
let mut i = 0;
while i < self.len as isize {
let value = ptr.offset(i).read();
let any = value.into();
dst.push(any);
i += 1;
}
Any::from(dst)
}
Y_JSON_MAP => {
let mut dst = HashMap::with_capacity(self.len as usize);
let keys = self.value.map.keys;
let values = self.value.map.values;
let mut i = 0;
while i < self.len as isize {
let key = CStr::from_ptr(keys.offset(i).read())
.to_str()
.unwrap()
.to_owned();
let value = values.offset(i).read().into();
dst.insert(key, value);
i += 1;
}
Any::from(dst)
}
Y_DOC => Any::Undefined,
other => panic!("Cannot convert input - unknown tag: {}", other),
}
}
}
}
impl Into<EmbedPrelim<YInput>> for YInput {
fn into(self) -> EmbedPrelim<YInput> {
if self.tag <= 0 {
EmbedPrelim::Primitive(self.into())
} else {
EmbedPrelim::Shared(self)
}
}
}
#[repr(C)]
union YInputContent {
flag: u8,
num: f64,
integer: i64,
str: *mut c_char,
buf: *mut c_char,
values: *mut YInput,
map: ManuallyDrop<YMapInputData>,
doc: *mut Doc,
weak: *const Weak,
}
#[repr(C)]
struct YMapInputData {
keys: *mut *mut c_char,
values: *mut YInput,
}
impl Drop for YInput {
fn drop(&mut self) {}
}
impl Prelim for YInput {
type Return = Unused;
fn into_content<'doc>(self, _: &mut yrs::TransactionMut<'doc>) -> (ItemContent, Option<Self>) {
unsafe {
if self.tag <= 0 {
(ItemContent::Any(vec![self.into()]), None)
} else if self.tag == Y_DOC {
let doc = self.value.doc.as_ref().unwrap();
(ItemContent::Doc(None, doc.clone()), None)
} else {
let type_ref = match self.tag {
Y_MAP => TypeRef::Map,
Y_ARRAY => TypeRef::Array,
Y_TEXT => TypeRef::Text,
Y_XML_TEXT => TypeRef::XmlText,
Y_XML_ELEM => {
let name: Arc<str> =
CStr::from_ptr(self.value.str).to_str().unwrap().into();
TypeRef::XmlElement(name)
}
Y_WEAK_LINK => {
let source = Arc::from_raw(self.value.weak);
TypeRef::WeakLink(source)
}
Y_XML_FRAG => TypeRef::XmlFragment,
other => panic!("unrecognized YInput tag: {}", other),
};
let inner = Branch::new(type_ref);
(ItemContent::Type(inner), Some(self))
}
}
}
fn integrate(self, txn: &mut yrs::TransactionMut, inner_ref: BranchPtr) {
unsafe {
match self.tag {
Y_MAP => {
let map = MapRef::from(inner_ref);
let keys = self.value.map.keys;
let values = self.value.map.values;
let mut i = 0;
while i < self.len as isize {
let key = CStr::from_ptr(keys.offset(i).read())
.to_str()
.unwrap()
.to_owned();
let value = values.offset(i).read();
map.insert(txn, key, value);
i += 1;
}
}
Y_ARRAY => {
let array = ArrayRef::from(inner_ref);
let ptr = self.value.values;
let len = self.len as isize;
let mut i = 0;
while i < len {
let value = ptr.offset(i).read();
array.push_back(txn, value);
i += 1;
}
}
Y_TEXT => {
let text = TextRef::from(inner_ref);
let init = CStr::from_ptr(self.value.str).to_str().unwrap();
text.push(txn, init);
}
Y_XML_TEXT => {
let text = XmlTextRef::from(inner_ref);
let init = CStr::from_ptr(self.value.str).to_str().unwrap();
text.push(txn, init);
}
_ => { }
}
}
}
}
#[repr(C)]
pub struct YOutput {
pub tag: i8,
pub len: u32,
value: YOutputContent,
}
impl YOutput {
#[inline]
unsafe fn null() -> YOutput {
YOutput {
tag: Y_JSON_NULL,
len: 0,
value: MaybeUninit::uninit().assume_init(),
}
}
#[inline]
unsafe fn undefined() -> YOutput {
YOutput {
tag: Y_JSON_UNDEF,
len: 0,
value: MaybeUninit::uninit().assume_init(),
}
}
}
impl std::fmt::Display for YOutput {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let tag = self.tag;
unsafe {
if tag == Y_JSON_INT {
write!(f, "{}", self.value.integer)
} else if tag == Y_JSON_NUM {
write!(f, "{}", self.value.num)
} else if tag == Y_JSON_BOOL {
write!(
f,
"{}",
if self.value.flag == 0 {
"false"
} else {
"true"
}
)
} else if tag == Y_JSON_UNDEF {
write!(f, "undefined")
} else if tag == Y_JSON_NULL {
write!(f, "null")
} else if tag == Y_JSON_STR {
write!(f, "{}", CString::from_raw(self.value.str).to_str().unwrap())
} else if tag == Y_MAP {
write!(f, "YMap")
} else if tag == Y_ARRAY {
write!(f, "YArray")
} else if tag == Y_JSON_ARR {
write!(f, "[")?;
let slice = std::slice::from_raw_parts(self.value.array, self.len as usize);
for o in slice {
write!(f, ", {}", o)?;
}
write!(f, "]")
} else if tag == Y_JSON_MAP {
write!(f, "{{")?;
let slice = std::slice::from_raw_parts(self.value.map, self.len as usize);
for e in slice {
let key = CStr::from_ptr(e.key).to_str().unwrap();
let value = e.value.as_ref().unwrap();
write!(f, ", '{}' => {}", key, value)?;
}
write!(f, "}}")
} else if tag == Y_TEXT {
write!(f, "YText")
} else if tag == Y_XML_TEXT {
write!(f, "YXmlText")
} else if tag == Y_XML_ELEM {
write!(f, "YXmlElement",)
} else if tag == Y_JSON_BUF {
write!(f, "YBinary(len: {})", self.len)
} else {
Ok(())
}
}
}
}
impl Drop for YOutput {
fn drop(&mut self) {
let tag = self.tag;
unsafe {
match tag {
Y_JSON_STR => drop(CString::from_raw(self.value.str)),
Y_JSON_ARR => drop(Vec::from_raw_parts(
self.value.array,
self.len as usize,
self.len as usize,
)),
Y_JSON_MAP => drop(Vec::from_raw_parts(
self.value.map,
self.len as usize,
self.len as usize,
)),
Y_JSON_BUF => drop(Vec::from_raw_parts(
self.value.buf as *mut u8,
self.len as usize,
self.len as usize,
)),
Y_DOC => drop(Box::from_raw(self.value.y_doc)),
_ => { }
}
}
}
}
impl From<Out> for YOutput {
fn from(v: Out) -> Self {
match v {
Out::Any(v) => Self::from(v),
Out::YText(v) => Self::from(v),
Out::YArray(v) => Self::from(v),
Out::YMap(v) => Self::from(v),
Out::YXmlElement(v) => Self::from(v),
Out::YXmlFragment(v) => Self::from(v),
Out::YXmlText(v) => Self::from(v),
Out::YDoc(v) => Self::from(v),
Out::YWeakLink(v) => Self::from(v),
Out::UndefinedRef(v) => Self::from(v),
}
}
}
impl From<bool> for YOutput {
#[inline]
fn from(value: bool) -> Self {
YOutput {
tag: Y_JSON_BOOL,
len: 1,
value: YOutputContent {
flag: if value { Y_TRUE } else { Y_FALSE },
},
}
}
}
impl From<f64> for YOutput {
#[inline]
fn from(value: f64) -> Self {
YOutput {
tag: Y_JSON_NUM,
len: 1,
value: YOutputContent { num: value },
}
}
}
impl From<i64> for YOutput {
#[inline]
fn from(value: i64) -> Self {
YOutput {
tag: Y_JSON_INT,
len: 1,
value: YOutputContent { integer: value },
}
}
}
impl<'a> From<&'a str> for YOutput {
fn from(value: &'a str) -> Self {
YOutput {
tag: Y_JSON_STR,
len: value.len() as u32,
value: YOutputContent {
str: CString::new(value).unwrap().into_raw(),
},
}
}
}
impl<'a> From<&'a [u8]> for YOutput {
fn from(value: &'a [u8]) -> Self {
let value: Box<[u8]> = value.into();
YOutput {
tag: Y_JSON_BUF,
len: value.len() as u32,
value: YOutputContent {
buf: Box::into_raw(value) as *const u8 as *mut c_char,
},
}
}
}
impl<'a> From<&'a [Any]> for YOutput {
fn from(values: &'a [Any]) -> Self {
let len = values.len() as u32;
let mut array = Vec::with_capacity(values.len());
for v in values.iter() {
let output = YOutput::from(v);
array.push(output);
}
let ptr = array.as_mut_ptr();
forget(array);
YOutput {
tag: Y_JSON_ARR,
len,
value: YOutputContent { array: ptr },
}
}
}
impl<'a> From<&'a HashMap<String, Any>> for YOutput {
fn from(value: &'a HashMap<String, Any>) -> Self {
let len = value.len() as u32;
let mut array = Vec::with_capacity(len as usize);
for (k, v) in value.iter() {
let entry = YMapEntry::new(k.as_str(), Box::new(YOutput::from(v)));
array.push(entry);
}
let ptr = array.as_mut_ptr();
forget(array);
YOutput {
tag: Y_JSON_MAP,
len,
value: YOutputContent { map: ptr },
}
}
}
impl<'a> From<&'a Any> for YOutput {
fn from(v: &'a Any) -> Self {
unsafe {
match v {
Any::Null => YOutput::null(),
Any::Undefined => YOutput::undefined(),
Any::Bool(v) => YOutput::from(*v),
Any::Number(v) => YOutput::from(*v),
Any::BigInt(v) => YOutput::from(*v),
Any::String(v) => YOutput::from(v.as_ref()),
Any::Buffer(v) => YOutput::from(v.as_ref()),
Any::Array(v) => YOutput::from(v.as_ref()),
Any::Map(v) => YOutput::from(v.as_ref()),
}
}
}
}
impl From<Any> for YOutput {
fn from(v: Any) -> Self {
unsafe {
match v {
Any::Null => YOutput::null(),
Any::Undefined => YOutput::undefined(),
Any::Bool(v) => YOutput::from(v),
Any::Number(v) => YOutput::from(v),
Any::BigInt(v) => YOutput::from(v),
Any::String(v) => YOutput::from(v.as_ref()),
Any::Buffer(v) => YOutput::from(v.as_ref()),
Any::Array(v) => YOutput::from(v.as_ref()),
Any::Map(v) => YOutput::from(v.as_ref()),
}
}
}
}
impl From<TextRef> for YOutput {
fn from(v: TextRef) -> Self {
YOutput {
tag: Y_TEXT,
len: 1,
value: YOutputContent {
y_type: v.into_raw_branch(),
},
}
}
}
impl From<ArrayRef> for YOutput {
fn from(v: ArrayRef) -> Self {
YOutput {
tag: Y_ARRAY,
len: 1,
value: YOutputContent {
y_type: v.into_raw_branch(),
},
}
}
}
impl From<WeakRef<BranchPtr>> for YOutput {
fn from(v: WeakRef<BranchPtr>) -> Self {
YOutput {
tag: Y_WEAK_LINK,
len: 1,
value: YOutputContent {
y_type: v.into_raw_branch(),
},
}
}
}
impl From<MapRef> for YOutput {
fn from(v: MapRef) -> Self {
YOutput {
tag: Y_MAP,
len: 1,
value: YOutputContent {
y_type: v.into_raw_branch(),
},
}
}
}
impl From<BranchPtr> for YOutput {
fn from(v: BranchPtr) -> Self {
let branch_ref = v.as_ref();
YOutput {
tag: Y_UNDEFINED,
len: 1,
value: YOutputContent {
y_type: branch_ref as *const Branch as *mut Branch,
},
}
}
}
impl From<XmlElementRef> for YOutput {
fn from(v: XmlElementRef) -> Self {
YOutput {
tag: Y_XML_ELEM,
len: 1,
value: YOutputContent {
y_type: v.into_raw_branch(),
},
}
}
}
impl From<XmlTextRef> for YOutput {
fn from(v: XmlTextRef) -> Self {
YOutput {
tag: Y_XML_TEXT,
len: 1,
value: YOutputContent {
y_type: v.into_raw_branch(),
},
}
}
}
impl From<XmlFragmentRef> for YOutput {
fn from(v: XmlFragmentRef) -> Self {
YOutput {
tag: Y_XML_FRAG,
len: 1,
value: YOutputContent {
y_type: v.into_raw_branch(),
},
}
}
}
impl From<Doc> for YOutput {
fn from(v: Doc) -> Self {
YOutput {
tag: Y_DOC,
len: 1,
value: YOutputContent {
y_doc: Box::into_raw(Box::new(v.clone())),
},
}
}
}
#[repr(C)]
union YOutputContent {
flag: u8,
num: f64,
integer: i64,
str: *mut c_char,
buf: *const c_char,
array: *mut YOutput,
map: *mut YMapEntry,
y_type: *mut Branch,
y_doc: *mut Doc,
}
#[no_mangle]
pub unsafe extern "C" fn youtput_destroy(val: *mut YOutput) {
if !val.is_null() {
drop(Box::from_raw(val))
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_null() -> YInput {
YInput {
tag: Y_JSON_NULL,
len: 0,
value: MaybeUninit::uninit().assume_init(),
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_undefined() -> YInput {
YInput {
tag: Y_JSON_UNDEF,
len: 0,
value: MaybeUninit::uninit().assume_init(),
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_bool(flag: u8) -> YInput {
YInput {
tag: Y_JSON_BOOL,
len: 1,
value: YInputContent { flag },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_float(num: f64) -> YInput {
YInput {
tag: Y_JSON_NUM,
len: 1,
value: YInputContent { num },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_long(integer: i64) -> YInput {
YInput {
tag: Y_JSON_INT,
len: 1,
value: YInputContent { integer },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_string(str: *const c_char) -> YInput {
YInput {
tag: Y_JSON_STR,
len: 1,
value: YInputContent {
str: str as *mut c_char,
},
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_json(str: *const c_char) -> YInput {
YInput {
tag: Y_JSON,
len: 1,
value: YInputContent {
str: str as *mut c_char,
},
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_binary(buf: *const c_char, len: u32) -> YInput {
YInput {
tag: Y_JSON_BUF,
len,
value: YInputContent {
buf: buf as *mut c_char,
},
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_json_array(values: *mut YInput, len: u32) -> YInput {
YInput {
tag: Y_JSON_ARR,
len,
value: YInputContent { values },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_json_map(
keys: *mut *mut c_char,
values: *mut YInput,
len: u32,
) -> YInput {
YInput {
tag: Y_JSON_MAP,
len,
value: YInputContent {
map: ManuallyDrop::new(YMapInputData { keys, values }),
},
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_yarray(values: *mut YInput, len: u32) -> YInput {
YInput {
tag: Y_ARRAY,
len,
value: YInputContent { values },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_ymap(
keys: *mut *mut c_char,
values: *mut YInput,
len: u32,
) -> YInput {
YInput {
tag: Y_MAP,
len,
value: YInputContent {
map: ManuallyDrop::new(YMapInputData { keys, values }),
},
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_ytext(str: *mut c_char) -> YInput {
YInput {
tag: Y_TEXT,
len: 1,
value: YInputContent { str },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_yxmlelem(name: *mut c_char) -> YInput {
YInput {
tag: Y_XML_ELEM,
len: 1,
value: YInputContent { str: name },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_yxmltext(str: *mut c_char) -> YInput {
YInput {
tag: Y_XML_TEXT,
len: 1,
value: YInputContent { str },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_ydoc(doc: *mut Doc) -> YInput {
YInput {
tag: Y_DOC,
len: 1,
value: YInputContent { doc },
}
}
#[no_mangle]
pub unsafe extern "C" fn yinput_weak(weak: *const Weak) -> YInput {
YInput {
tag: Y_WEAK_LINK,
len: 1,
value: YInputContent { weak },
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_ydoc(val: *const YOutput) -> *mut Doc {
let v = val.as_ref().unwrap();
if v.tag == Y_DOC {
v.value.y_doc
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_bool(val: *const YOutput) -> *const u8 {
let v = val.as_ref().unwrap();
if v.tag == Y_JSON_BOOL {
&v.value.flag
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_float(val: *const YOutput) -> *const f64 {
let v = val.as_ref().unwrap();
if v.tag == Y_JSON_NUM {
&v.value.num
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_long(val: *const YOutput) -> *const i64 {
let v = val.as_ref().unwrap();
if v.tag == Y_JSON_INT {
&v.value.integer
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_string(val: *const YOutput) -> *mut c_char {
let v = val.as_ref().unwrap();
if v.tag == Y_JSON_STR {
v.value.str
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_binary(val: *const YOutput) -> *const c_char {
let v = val.as_ref().unwrap();
if v.tag == Y_JSON_BUF {
v.value.buf
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_json_array(val: *const YOutput) -> *mut YOutput {
let v = val.as_ref().unwrap();
if v.tag == Y_JSON_ARR {
v.value.array
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_json_map(val: *const YOutput) -> *mut YMapEntry {
let v = val.as_ref().unwrap();
if v.tag == Y_JSON_MAP {
v.value.map
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_yarray(val: *const YOutput) -> *mut Branch {
let v = val.as_ref().unwrap();
if v.tag == Y_ARRAY {
v.value.y_type
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_yxmlelem(val: *const YOutput) -> *mut Branch {
let v = val.as_ref().unwrap();
if v.tag == Y_XML_ELEM {
v.value.y_type
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_ymap(val: *const YOutput) -> *mut Branch {
let v = val.as_ref().unwrap();
if v.tag == Y_MAP {
v.value.y_type
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_ytext(val: *const YOutput) -> *mut Branch {
let v = val.as_ref().unwrap();
if v.tag == Y_TEXT {
v.value.y_type
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_yxmltext(val: *const YOutput) -> *mut Branch {
let v = val.as_ref().unwrap();
if v.tag == Y_XML_TEXT {
v.value.y_type
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn youtput_read_yweak(val: *const YOutput) -> *mut Branch {
let v = val.as_ref().unwrap();
if v.tag == Y_WEAK_LINK {
v.value.y_type
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yunobserve(subscription: *mut Subscription) {
drop(unsafe { Box::from_raw(subscription) })
}
#[no_mangle]
pub unsafe extern "C" fn ytext_observe(
txt: *const Branch,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *const YTextEvent),
) -> *mut Subscription {
assert!(!txt.is_null());
let state = CallbackState::new(state);
let txt = TextRef::from_raw_branch(txt);
let subscription = txt.observe(move |txn, e| {
let e = YTextEvent::new(e, txn);
cb(state.0, &e as *const YTextEvent);
});
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn ymap_observe(
map: *const Branch,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *const YMapEvent),
) -> *mut Subscription {
assert!(!map.is_null());
let state = CallbackState::new(state);
let map = MapRef::from_raw_branch(map);
let subscription = map.observe(move |txn, e| {
let e = YMapEvent::new(e, txn);
cb(state.0, &e as *const YMapEvent);
});
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn yarray_observe(
array: *const Branch,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *const YArrayEvent),
) -> *mut Subscription {
assert!(!array.is_null());
let state = CallbackState::new(state);
let array = ArrayRef::from_raw_branch(array);
let subscription = array.observe(move |txn, e| {
let e = YArrayEvent::new(e, txn);
cb(state.0, &e as *const YArrayEvent);
});
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_observe(
xml: *const Branch,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *const YXmlEvent),
) -> *mut Subscription {
assert!(!xml.is_null());
let state = CallbackState::new(state);
let xml = XmlElementRef::from_raw_branch(xml);
let subscription = xml.observe(move |txn, e| {
let e = YXmlEvent::new(e, txn);
cb(state.0, &e as *const YXmlEvent);
});
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_observe(
xml: *const Branch,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *const YXmlTextEvent),
) -> *mut Subscription {
assert!(!xml.is_null());
let state = CallbackState::new(state);
let xml = XmlTextRef::from_raw_branch(xml);
let subscription = xml.observe(move |txn, e| {
let e = YXmlTextEvent::new(e, txn);
cb(state.0, &e as *const YXmlTextEvent);
});
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn yobserve_deep(
ytype: *mut Branch,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, u32, *const YEvent),
) -> *mut Subscription {
assert!(!ytype.is_null());
let state = CallbackState::new(state);
let branch = ytype.as_mut().unwrap();
let subscription = branch.observe_deep(move |txn, events| {
let events: Vec<_> = events.iter().map(|e| YEvent::new(txn, e)).collect();
let len = events.len() as u32;
cb(state.0, len, events.as_ptr());
});
Box::into_raw(Box::new(subscription))
}
#[repr(C)]
pub struct YAfterTransactionEvent {
pub before_state: YStateVector,
pub after_state: YStateVector,
pub delete_set: YDeleteSet,
}
impl YAfterTransactionEvent {
unsafe fn new(e: &TransactionCleanupEvent) -> Self {
YAfterTransactionEvent {
before_state: YStateVector::new(&e.before_state),
after_state: YStateVector::new(&e.after_state),
delete_set: YDeleteSet::new(&e.delete_set),
}
}
}
#[repr(C)]
pub struct YSubdocsEvent {
added_len: u32,
removed_len: u32,
loaded_len: u32,
added: *mut *mut Doc,
removed: *mut *mut Doc,
loaded: *mut *mut Doc,
}
impl YSubdocsEvent {
unsafe fn new(e: &SubdocsEvent) -> Self {
fn into_ptr(v: SubdocsEventIter) -> *mut *mut Doc {
let array: Vec<_> = v.map(|doc| Box::into_raw(Box::new(doc.clone()))).collect();
let mut boxed = array.into_boxed_slice();
let ptr = boxed.as_mut_ptr();
forget(boxed);
ptr
}
let added = e.added();
let removed = e.removed();
let loaded = e.loaded();
YSubdocsEvent {
added_len: added.len() as u32,
removed_len: removed.len() as u32,
loaded_len: loaded.len() as u32,
added: into_ptr(added),
removed: into_ptr(removed),
loaded: into_ptr(loaded),
}
}
}
impl Drop for YSubdocsEvent {
fn drop(&mut self) {
fn release(len: u32, buf: *mut *mut Doc) {
unsafe {
let docs = Vec::from_raw_parts(buf, len as usize, len as usize);
for d in docs {
drop(Box::from_raw(d));
}
}
}
release(self.added_len, self.added);
release(self.removed_len, self.removed);
release(self.loaded_len, self.loaded);
}
}
#[repr(C)]
pub struct YStateVector {
pub entries_count: u32,
pub client_ids: *mut u64,
pub clocks: *mut u32,
}
impl YStateVector {
unsafe fn new(sv: &StateVector) -> Self {
let entries_count = sv.len() as u32;
let mut client_ids = Vec::with_capacity(sv.len());
let mut clocks = Vec::with_capacity(sv.len());
for (&client, &clock) in sv.iter() {
client_ids.push(client as u64);
clocks.push(clock as u32);
}
YStateVector {
entries_count,
client_ids: Box::into_raw(client_ids.into_boxed_slice()) as *mut _,
clocks: Box::into_raw(clocks.into_boxed_slice()) as *mut _,
}
}
}
impl Drop for YStateVector {
fn drop(&mut self) {
let len = self.entries_count as usize;
drop(unsafe { Vec::from_raw_parts(self.client_ids, len, len) });
drop(unsafe { Vec::from_raw_parts(self.clocks, len, len) });
}
}
#[repr(C)]
pub struct YDeleteSet {
pub entries_count: u32,
pub client_ids: *mut u64,
pub ranges: *mut YIdRangeSeq,
}
impl YDeleteSet {
unsafe fn new(ds: &DeleteSet) -> Self {
let len = ds.len();
let mut client_ids = Vec::with_capacity(len);
let mut ranges = Vec::with_capacity(len);
for (&client, range) in ds.iter() {
client_ids.push(client);
let seq: Vec<_> = range
.iter()
.map(|r| YIdRange {
start: r.start as u32,
end: r.end as u32,
})
.collect();
ranges.push(YIdRangeSeq {
len: seq.len() as u32,
seq: Box::into_raw(seq.into_boxed_slice()) as *mut _,
})
}
YDeleteSet {
entries_count: len as u32,
client_ids: Box::into_raw(client_ids.into_boxed_slice()) as *mut _,
ranges: Box::into_raw(ranges.into_boxed_slice()) as *mut _,
}
}
}
impl Drop for YDeleteSet {
fn drop(&mut self) {
let len = self.entries_count as usize;
drop(unsafe { Vec::from_raw_parts(self.client_ids, len, len) });
drop(unsafe { Vec::from_raw_parts(self.ranges, len, len) });
}
}
#[repr(C)]
pub struct YIdRangeSeq {
pub len: u32,
pub seq: *mut YIdRange,
}
impl Drop for YIdRangeSeq {
fn drop(&mut self) {
let len = self.len as usize;
drop(unsafe { Vec::from_raw_parts(self.seq, len, len) })
}
}
#[repr(C)]
pub struct YIdRange {
pub start: u32,
pub end: u32,
}
#[repr(C)]
pub struct YEvent {
pub tag: i8,
pub content: YEventContent,
}
impl YEvent {
fn new<'doc>(txn: &yrs::TransactionMut<'doc>, e: &Event) -> YEvent {
match e {
Event::Text(e) => YEvent {
tag: Y_TEXT,
content: YEventContent {
text: YTextEvent::new(e, txn),
},
},
Event::Array(e) => YEvent {
tag: Y_ARRAY,
content: YEventContent {
array: YArrayEvent::new(e, txn),
},
},
Event::Map(e) => YEvent {
tag: Y_MAP,
content: YEventContent {
map: YMapEvent::new(e, txn),
},
},
Event::XmlFragment(e) => YEvent {
tag: if let XmlOut::Fragment(_) = e.target() {
Y_XML_FRAG
} else {
Y_XML_ELEM
},
content: YEventContent {
xml_elem: YXmlEvent::new(e, txn),
},
},
Event::XmlText(e) => YEvent {
tag: Y_XML_TEXT,
content: YEventContent {
xml_text: YXmlTextEvent::new(e, txn),
},
},
Event::Weak(e) => YEvent {
tag: Y_WEAK_LINK,
content: YEventContent {
weak: YWeakLinkEvent::new(e, txn),
},
},
}
}
}
#[repr(C)]
pub union YEventContent {
pub text: YTextEvent,
pub map: YMapEvent,
pub array: YArrayEvent,
pub xml_elem: YXmlEvent,
pub xml_text: YXmlTextEvent,
pub weak: YWeakLinkEvent,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct YTextEvent {
inner: *const c_void,
txn: *const yrs::TransactionMut<'static>,
}
impl YTextEvent {
fn new<'dev>(inner: &TextEvent, txn: &yrs::TransactionMut<'dev>) -> Self {
let inner = inner as *const TextEvent as *const _;
let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
let txn = txn as *const _;
YTextEvent { inner, txn }
}
fn txn(&self) -> &yrs::TransactionMut {
unsafe { self.txn.as_ref().unwrap() }
}
}
impl Deref for YTextEvent {
type Target = TextEvent;
fn deref(&self) -> &Self::Target {
unsafe { (self.inner as *const TextEvent).as_ref().unwrap() }
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct YArrayEvent {
inner: *const c_void,
txn: *const yrs::TransactionMut<'static>,
}
impl YArrayEvent {
fn new<'doc>(inner: &ArrayEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
let inner = inner as *const ArrayEvent as *const _;
let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
let txn = txn as *const _;
YArrayEvent { inner, txn }
}
fn txn(&self) -> &yrs::TransactionMut {
unsafe { self.txn.as_ref().unwrap() }
}
}
impl Deref for YArrayEvent {
type Target = ArrayEvent;
fn deref(&self) -> &Self::Target {
unsafe { (self.inner as *const ArrayEvent).as_ref().unwrap() }
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct YMapEvent {
inner: *const c_void,
txn: *const yrs::TransactionMut<'static>,
}
impl YMapEvent {
fn new<'doc>(inner: &MapEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
let inner = inner as *const MapEvent as *const _;
let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
let txn = txn as *const _;
YMapEvent { inner, txn }
}
fn txn(&self) -> &yrs::TransactionMut<'static> {
unsafe { self.txn.as_ref().unwrap() }
}
}
impl Deref for YMapEvent {
type Target = MapEvent;
fn deref(&self) -> &Self::Target {
unsafe { (self.inner as *const MapEvent).as_ref().unwrap() }
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct YXmlEvent {
inner: *const c_void,
txn: *const yrs::TransactionMut<'static>,
}
impl YXmlEvent {
fn new<'doc>(inner: &XmlEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
let inner = inner as *const XmlEvent as *const _;
let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
let txn = txn as *const _;
YXmlEvent { inner, txn }
}
fn txn(&self) -> &yrs::TransactionMut<'static> {
unsafe { self.txn.as_ref().unwrap() }
}
}
impl Deref for YXmlEvent {
type Target = XmlEvent;
fn deref(&self) -> &Self::Target {
unsafe { (self.inner as *const XmlEvent).as_ref().unwrap() }
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct YXmlTextEvent {
inner: *const c_void,
txn: *const yrs::TransactionMut<'static>,
}
impl YXmlTextEvent {
fn new<'doc>(inner: &XmlTextEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
let inner = inner as *const XmlTextEvent as *const _;
let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
let txn = txn as *const _;
YXmlTextEvent { inner, txn }
}
fn txn(&self) -> &yrs::TransactionMut<'static> {
unsafe { self.txn.as_ref().unwrap() }
}
}
impl Deref for YXmlTextEvent {
type Target = XmlTextEvent;
fn deref(&self) -> &Self::Target {
unsafe { (self.inner as *const XmlTextEvent).as_ref().unwrap() }
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct YWeakLinkEvent {
inner: *const c_void,
txn: *const yrs::TransactionMut<'static>,
}
impl YWeakLinkEvent {
fn new<'doc>(inner: &WeakEvent, txn: &yrs::TransactionMut<'doc>) -> Self {
let inner = inner as *const WeakEvent as *const _;
let txn: &yrs::TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
let txn = txn as *const _;
YWeakLinkEvent { inner, txn }
}
}
impl Deref for YWeakLinkEvent {
type Target = WeakEvent;
fn deref(&self) -> &Self::Target {
unsafe { (self.inner as *const WeakEvent).as_ref().unwrap() }
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_event_target(e: *const YTextEvent) -> *mut Branch {
assert!(!e.is_null());
let out = (&*e).target().clone();
out.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn yarray_event_target(e: *const YArrayEvent) -> *mut Branch {
assert!(!e.is_null());
let out = (&*e).target().clone();
out.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn ymap_event_target(e: *const YMapEvent) -> *mut Branch {
assert!(!e.is_null());
let out = (&*e).target().clone();
out.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_event_target(e: *const YXmlEvent) -> *mut Branch {
assert!(!e.is_null());
let out = (&*e).target().clone();
match out {
XmlOut::Element(e) => e.into_raw_branch(),
XmlOut::Fragment(e) => e.into_raw_branch(),
XmlOut::Text(e) => e.into_raw_branch(),
}
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_event_target(e: *const YXmlTextEvent) -> *mut Branch {
assert!(!e.is_null());
let out = (&*e).target().clone();
out.into_raw_branch()
}
#[no_mangle]
pub unsafe extern "C" fn ytext_event_path(
e: *const YTextEvent,
len: *mut u32,
) -> *mut YPathSegment {
assert!(!e.is_null());
let e = &*e;
let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
let out = path.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn ymap_event_path(e: *const YMapEvent, len: *mut u32) -> *mut YPathSegment {
assert!(!e.is_null());
let e = &*e;
let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
let out = path.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_event_path(
e: *const YXmlEvent,
len: *mut u32,
) -> *mut YPathSegment {
assert!(!e.is_null());
let e = &*e;
let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
let out = path.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_event_path(
e: *const YXmlTextEvent,
len: *mut u32,
) -> *mut YPathSegment {
assert!(!e.is_null());
let e = &*e;
let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
let out = path.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yarray_event_path(
e: *const YArrayEvent,
len: *mut u32,
) -> *mut YPathSegment {
assert!(!e.is_null());
let e = &*e;
let path: Vec<_> = e.path().into_iter().map(YPathSegment::from).collect();
let out = path.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn ypath_destroy(path: *mut YPathSegment, len: u32) {
if !path.is_null() {
drop(Vec::from_raw_parts(path, len as usize, len as usize));
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_event_delta(e: *const YTextEvent, len: *mut u32) -> *mut YDeltaOut {
assert!(!e.is_null());
let e = &*e;
let delta: Vec<_> = e.delta(e.txn()).into_iter().map(YDeltaOut::from).collect();
let out = delta.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_event_delta(
e: *const YXmlTextEvent,
len: *mut u32,
) -> *mut YDeltaOut {
assert!(!e.is_null());
let e = &*e;
let delta: Vec<_> = e.delta(e.txn()).into_iter().map(YDeltaOut::from).collect();
let out = delta.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yarray_event_delta(
e: *const YArrayEvent,
len: *mut u32,
) -> *mut YEventChange {
assert!(!e.is_null());
let e = &*e;
let delta: Vec<_> = e
.delta(e.txn())
.into_iter()
.map(YEventChange::from)
.collect();
let out = delta.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_event_delta(
e: *const YXmlEvent,
len: *mut u32,
) -> *mut YEventChange {
assert!(!e.is_null());
let e = &*e;
let delta: Vec<_> = e
.delta(e.txn())
.into_iter()
.map(YEventChange::from)
.collect();
let out = delta.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn ytext_delta_destroy(delta: *mut YDeltaOut, len: u32) {
if !delta.is_null() {
let delta = Vec::from_raw_parts(delta, len as usize, len as usize);
drop(delta);
}
}
#[no_mangle]
pub unsafe extern "C" fn yevent_delta_destroy(delta: *mut YEventChange, len: u32) {
if !delta.is_null() {
let delta = Vec::from_raw_parts(delta, len as usize, len as usize);
drop(delta);
}
}
#[no_mangle]
pub unsafe extern "C" fn ymap_event_keys(
e: *const YMapEvent,
len: *mut u32,
) -> *mut YEventKeyChange {
assert!(!e.is_null());
let e = &*e;
let delta: Vec<_> = e
.keys(e.txn())
.into_iter()
.map(|(k, v)| YEventKeyChange::new(k.as_ref(), v))
.collect();
let out = delta.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yxmlelem_event_keys(
e: *const YXmlEvent,
len: *mut u32,
) -> *mut YEventKeyChange {
assert!(!e.is_null());
let e = &*e;
let delta: Vec<_> = e
.keys(e.txn())
.into_iter()
.map(|(k, v)| YEventKeyChange::new(k.as_ref(), v))
.collect();
let out = delta.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yxmltext_event_keys(
e: *const YXmlTextEvent,
len: *mut u32,
) -> *mut YEventKeyChange {
assert!(!e.is_null());
let e = &*e;
let delta: Vec<_> = e
.keys(e.txn())
.into_iter()
.map(|(k, v)| YEventKeyChange::new(k.as_ref(), v))
.collect();
let out = delta.into_boxed_slice();
*len = out.len() as u32;
Box::into_raw(out) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn yevent_keys_destroy(keys: *mut YEventKeyChange, len: u32) {
if !keys.is_null() {
drop(Vec::from_raw_parts(keys, len as usize, len as usize));
}
}
pub type YUndoManager = yrs::undo::UndoManager<AtomicPtr<c_void>>;
#[repr(C)]
pub struct YUndoManagerOptions {
pub capture_timeout_millis: i32,
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager(
doc: *const Doc,
options: *const YUndoManagerOptions,
) -> *mut YUndoManager {
let doc = doc.as_ref().unwrap();
let mut o = yrs::undo::Options::default();
if let Some(options) = options.as_ref() {
if options.capture_timeout_millis >= 0 {
o.capture_timeout_millis = options.capture_timeout_millis as u64;
}
};
let boxed = Box::new(yrs::undo::UndoManager::with_options(doc, o));
Box::into_raw(boxed)
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_destroy(mgr: *mut YUndoManager) {
drop(Box::from_raw(mgr));
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_add_origin(
mgr: *mut YUndoManager,
origin_len: u32,
origin: *const c_char,
) {
let mgr = mgr.as_mut().unwrap();
let bytes = std::slice::from_raw_parts(origin as *const u8, origin_len as usize);
mgr.include_origin(Origin::from(bytes));
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_remove_origin(
mgr: *mut YUndoManager,
origin_len: u32,
origin: *const c_char,
) {
let mgr = mgr.as_mut().unwrap();
let bytes = std::slice::from_raw_parts(origin as *const u8, origin_len as usize);
mgr.exclude_origin(Origin::from(bytes));
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_add_scope(mgr: *mut YUndoManager, ytype: *const Branch) {
let mgr = mgr.as_mut().unwrap();
let branch = ytype.as_ref().unwrap();
mgr.expand_scope(&BranchPtr::from(branch));
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_clear(mgr: *mut YUndoManager) {
let mgr = mgr.as_mut().unwrap();
mgr.clear();
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_stop(mgr: *mut YUndoManager) {
let mgr = mgr.as_mut().unwrap();
mgr.reset();
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_undo(mgr: *mut YUndoManager) -> u8 {
let mgr = mgr.as_mut().unwrap();
match mgr.try_undo() {
Ok(true) => Y_TRUE,
Ok(false) => Y_FALSE,
Err(_) => Y_FALSE,
}
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_redo(mgr: *mut YUndoManager) -> u8 {
let mgr = mgr.as_mut().unwrap();
match mgr.try_redo() {
Ok(true) => Y_TRUE,
Ok(false) => Y_FALSE,
Err(_) => Y_FALSE,
}
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_undo_stack_len(mgr: *mut YUndoManager) -> u32 {
let mgr = mgr.as_mut().unwrap();
mgr.undo_stack().len() as u32
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_redo_stack_len(mgr: *mut YUndoManager) -> u32 {
let mgr = mgr.as_mut().unwrap();
mgr.redo_stack().len() as u32
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_observe_added(
mgr: *mut YUndoManager,
state: *mut c_void,
callback: extern "C" fn(*mut c_void, *const YUndoEvent),
) -> *mut Subscription {
let state = CallbackState::new(state);
let mgr = mgr.as_mut().unwrap();
let subscription = mgr.observe_item_added(move |_, e| {
let meta_ptr = {
let event = YUndoEvent::new(e);
callback(state.0, &event as *const YUndoEvent);
event.meta
};
e.meta().store(meta_ptr, Ordering::Release);
});
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn yundo_manager_observe_popped(
mgr: *mut YUndoManager,
state: *mut c_void,
callback: extern "C" fn(*mut c_void, *const YUndoEvent),
) -> *mut Subscription {
let mgr = mgr.as_mut().unwrap();
let state = CallbackState::new(state);
let subscription = mgr
.observe_item_popped(move |_, e| {
let meta_ptr = {
let event = YUndoEvent::new(e);
callback(state.0, &event as *const YUndoEvent);
event.meta
};
e.meta().store(meta_ptr, Ordering::Release);
})
.into();
Box::into_raw(Box::new(subscription))
}
pub const Y_KIND_UNDO: c_char = 0;
pub const Y_KIND_REDO: c_char = 1;
#[repr(C)]
pub struct YUndoEvent {
pub kind: c_char,
pub origin: *const c_char,
pub origin_len: u32,
pub meta: *mut c_void,
}
impl YUndoEvent {
unsafe fn new(e: &yrs::undo::Event<AtomicPtr<c_void>>) -> Self {
let (origin, origin_len) = if let Some(origin) = e.origin() {
let bytes = origin.as_ref();
let origin_len = bytes.len() as u32;
let origin = bytes.as_ptr() as *const c_char;
(origin, origin_len)
} else {
(null(), 0)
};
YUndoEvent {
kind: match e.kind() {
EventKind::Undo => Y_KIND_UNDO,
EventKind::Redo => Y_KIND_REDO,
},
origin,
origin_len,
meta: e.meta().load(Ordering::Acquire),
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ytype_kind(branch: *const Branch) -> i8 {
if let Some(branch) = branch.as_ref() {
match branch.type_ref() {
TypeRef::Array => Y_ARRAY,
TypeRef::Map => Y_MAP,
TypeRef::Text => Y_TEXT,
TypeRef::XmlElement(_) => Y_XML_ELEM,
TypeRef::XmlText => Y_XML_TEXT,
TypeRef::XmlFragment => Y_XML_FRAG,
TypeRef::SubDoc => Y_DOC,
TypeRef::WeakLink(_) => Y_WEAK_LINK,
TypeRef::XmlHook => 0,
TypeRef::Undefined => 0,
}
} else {
0
}
}
pub const Y_EVENT_PATH_KEY: c_char = 1;
pub const Y_EVENT_PATH_INDEX: c_char = 2;
#[repr(C)]
pub struct YPathSegment {
pub tag: c_char,
pub value: YPathSegmentCase,
}
impl From<PathSegment> for YPathSegment {
fn from(ps: PathSegment) -> Self {
match ps {
PathSegment::Key(key) => {
let key = CString::new(key.as_ref()).unwrap().into_raw() as *const _;
YPathSegment {
tag: Y_EVENT_PATH_KEY,
value: YPathSegmentCase { key },
}
}
PathSegment::Index(index) => YPathSegment {
tag: Y_EVENT_PATH_INDEX,
value: YPathSegmentCase {
index: index as u32,
},
},
}
}
}
impl Drop for YPathSegment {
fn drop(&mut self) {
if self.tag == Y_EVENT_PATH_KEY {
unsafe {
ystring_destroy(self.value.key as *mut _);
}
}
}
}
#[repr(C)]
pub union YPathSegmentCase {
pub key: *const c_char,
pub index: u32,
}
pub const Y_EVENT_CHANGE_ADD: u8 = 1;
pub const Y_EVENT_CHANGE_DELETE: u8 = 2;
pub const Y_EVENT_CHANGE_RETAIN: u8 = 3;
#[repr(C)]
pub struct YEventChange {
pub tag: u8,
pub len: u32,
pub values: *const YOutput,
}
impl<'a> From<&'a Change> for YEventChange {
fn from(change: &'a Change) -> Self {
match change {
Change::Added(values) => {
let out: Vec<_> = values
.into_iter()
.map(|v| YOutput::from(v.clone()))
.collect();
let len = out.len() as u32;
let out = out.into_boxed_slice();
let values = Box::into_raw(out) as *mut _;
YEventChange {
tag: Y_EVENT_CHANGE_ADD,
len,
values,
}
}
Change::Removed(len) => YEventChange {
tag: Y_EVENT_CHANGE_DELETE,
len: *len as u32,
values: null(),
},
Change::Retain(len) => YEventChange {
tag: Y_EVENT_CHANGE_RETAIN,
len: *len as u32,
values: null(),
},
}
}
}
impl Drop for YEventChange {
fn drop(&mut self) {
if self.tag == Y_EVENT_CHANGE_ADD {
unsafe {
let len = self.len as usize;
let values = Vec::from_raw_parts(self.values as *mut YOutput, len, len);
drop(values);
}
}
}
}
#[repr(C)]
pub struct YDeltaOut {
pub tag: u8,
pub len: u32,
pub attributes_len: u32,
pub attributes: *mut YDeltaAttr,
pub insert: *mut YOutput,
}
impl YDeltaOut {
fn insert(value: &Out, attrs: &Option<Box<Attrs>>) -> Self {
let insert = Box::into_raw(Box::new(YOutput::from(value.clone())));
let (attributes_len, attributes) = if let Some(attrs) = attrs {
let len = attrs.len() as u32;
let attrs: Vec<_> = attrs.iter().map(|(k, v)| YDeltaAttr::new(k, v)).collect();
let attrs = Box::into_raw(attrs.into_boxed_slice()) as *mut _;
(len, attrs)
} else {
(0, null_mut())
};
YDeltaOut {
tag: Y_EVENT_CHANGE_ADD,
len: 1,
insert,
attributes_len,
attributes,
}
}
fn retain(len: u32, attrs: &Option<Box<Attrs>>) -> Self {
let (attributes_len, attributes) = if let Some(attrs) = attrs {
let len = attrs.len() as u32;
let attrs: Vec<_> = attrs.iter().map(|(k, v)| YDeltaAttr::new(k, v)).collect();
let attrs = Box::into_raw(attrs.into_boxed_slice()) as *mut _;
(len, attrs)
} else {
(0, null_mut())
};
YDeltaOut {
tag: Y_EVENT_CHANGE_RETAIN,
len,
insert: null_mut(),
attributes_len,
attributes,
}
}
fn delete(len: u32) -> Self {
YDeltaOut {
tag: Y_EVENT_CHANGE_DELETE,
len,
insert: null_mut(),
attributes_len: 0,
attributes: null_mut(),
}
}
}
impl<'a> From<&'a Delta> for YDeltaOut {
fn from(d: &Delta) -> Self {
match d {
Delta::Inserted(value, attrs) => YDeltaOut::insert(value, attrs),
Delta::Retain(len, attrs) => YDeltaOut::retain(*len, attrs),
Delta::Deleted(len) => YDeltaOut::delete(*len),
}
}
}
impl Drop for YDeltaOut {
fn drop(&mut self) {
unsafe {
if !self.attributes.is_null() {
let len = self.attributes_len as usize;
drop(Vec::from_raw_parts(self.attributes, len, len));
}
if !self.insert.is_null() {
drop(Box::from_raw(self.insert));
}
}
}
}
#[repr(C)]
pub struct YDeltaAttr {
pub key: *const c_char,
pub value: YOutput,
}
impl YDeltaAttr {
fn new(k: &Arc<str>, v: &Any) -> Self {
let key = CString::new(k.as_ref()).unwrap().into_raw() as *const _;
let value = YOutput::from(v);
YDeltaAttr { key, value }
}
}
impl Drop for YDeltaAttr {
fn drop(&mut self) {
unsafe { ystring_destroy(self.key as *mut _) }
}
}
#[repr(C)]
pub struct YDeltaIn {
pub tag: u8,
pub len: u32,
pub attributes: *const YInput,
pub insert: *const YInput,
}
impl YDeltaIn {
fn as_input(&self) -> Delta<YInput> {
match self.tag {
Y_EVENT_CHANGE_RETAIN => {
let attrs = if self.attributes.is_null() {
None
} else {
let attrs = unsafe { self.attributes.read() };
map_attrs(attrs.into()).map(Box::new)
};
Delta::Retain(self.len, attrs)
}
Y_EVENT_CHANGE_DELETE => Delta::Deleted(self.len),
Y_EVENT_CHANGE_ADD => {
let attrs = if self.attributes.is_null() {
None
} else {
let attrs = unsafe { self.attributes.read() };
map_attrs(attrs.into()).map(Box::new)
};
let input = unsafe { self.insert.read() };
Delta::Inserted(input, attrs)
}
tag => panic!("YDelta tag identifier is of unknown type: {}", tag),
}
}
}
pub const Y_EVENT_KEY_CHANGE_ADD: c_char = 4;
pub const Y_EVENT_KEY_CHANGE_DELETE: c_char = 5;
pub const Y_EVENT_KEY_CHANGE_UPDATE: c_char = 6;
#[repr(C)]
pub struct YEventKeyChange {
pub key: *const c_char,
pub tag: c_char,
pub old_value: *const YOutput,
pub new_value: *const YOutput,
}
impl YEventKeyChange {
fn new(key: &str, change: &EntryChange) -> Self {
let key = CString::new(key).unwrap().into_raw() as *const _;
match change {
EntryChange::Inserted(new) => YEventKeyChange {
key,
tag: Y_EVENT_KEY_CHANGE_ADD,
old_value: null(),
new_value: Box::into_raw(Box::new(YOutput::from(new.clone()))),
},
EntryChange::Updated(old, new) => YEventKeyChange {
key,
tag: Y_EVENT_KEY_CHANGE_UPDATE,
old_value: Box::into_raw(Box::new(YOutput::from(old.clone()))),
new_value: Box::into_raw(Box::new(YOutput::from(new.clone()))),
},
EntryChange::Removed(old) => YEventKeyChange {
key,
tag: Y_EVENT_KEY_CHANGE_DELETE,
old_value: Box::into_raw(Box::new(YOutput::from(old.clone()))),
new_value: null(),
},
}
}
}
impl Drop for YEventKeyChange {
fn drop(&mut self) {
unsafe {
ystring_destroy(self.key as *mut _);
youtput_destroy(self.old_value as *mut _);
youtput_destroy(self.new_value as *mut _);
}
}
}
trait BranchPointable {
fn into_raw_branch(self) -> *mut Branch;
fn from_raw_branch(branch: *const Branch) -> Self;
}
impl<T> BranchPointable for T
where
T: AsRef<Branch> + From<BranchPtr>,
{
fn into_raw_branch(self) -> *mut Branch {
let branch_ref = self.as_ref();
branch_ref as *const Branch as *mut Branch
}
fn from_raw_branch(branch: *const Branch) -> Self {
let b = unsafe { branch.as_ref().unwrap() };
let branch_ref = BranchPtr::from(b);
T::from(branch_ref)
}
}
#[repr(transparent)]
pub struct YStickyIndex(StickyIndex);
impl From<StickyIndex> for YStickyIndex {
#[inline(always)]
fn from(value: StickyIndex) -> Self {
YStickyIndex(value)
}
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_destroy(pos: *mut YStickyIndex) {
drop(Box::from_raw(pos))
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_assoc(pos: *const YStickyIndex) -> i8 {
let pos = pos.as_ref().unwrap();
match pos.0.assoc {
Assoc::After => 0,
Assoc::Before => -1,
}
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_from_index(
branch: *const Branch,
txn: *mut Transaction,
index: u32,
assoc: i8,
) -> *mut YStickyIndex {
assert!(!branch.is_null());
assert!(!txn.is_null());
let branch = BranchPtr::from_raw_branch(branch);
let txn = txn.as_mut().unwrap();
let index = index as u32;
let assoc = if assoc >= 0 {
Assoc::After
} else {
Assoc::Before
};
if let Some(txn) = txn.as_mut() {
if let Some(pos) = StickyIndex::at(txn, branch, index, assoc) {
Box::into_raw(Box::new(YStickyIndex(pos)))
} else {
null_mut()
}
} else {
panic!("ysticky_index_from_index requires a read-write transaction");
}
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_encode(
pos: *const YStickyIndex,
len: *mut u32,
) -> *mut c_char {
let pos = pos.as_ref().unwrap();
let binary = pos.0.encode_v1().into_boxed_slice();
*len = binary.len() as u32;
Box::into_raw(binary) as *mut c_char
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_decode(
binary: *const c_char,
len: u32,
) -> *mut YStickyIndex {
let slice = std::slice::from_raw_parts(binary as *const u8, len as usize);
if let Ok(pos) = StickyIndex::decode_v1(slice) {
Box::into_raw(Box::new(YStickyIndex(pos)))
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_to_json(pos: *const YStickyIndex) -> *mut c_char {
let pos = pos.as_ref().unwrap();
let json = match serde_json::to_string(&pos.0) {
Ok(json) => json,
Err(_) => return null_mut(),
};
CString::new(json).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_from_json(json: *const c_char) -> *mut YStickyIndex {
let cstr = CStr::from_ptr(json);
let json = match cstr.to_str() {
Ok(json) => json,
Err(_) => return null_mut(),
};
match serde_json::from_str(json) {
Ok(pos) => Box::into_raw(Box::new(YStickyIndex(pos))),
Err(_) => null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn ysticky_index_read(
pos: *const YStickyIndex,
txn: *const Transaction,
out_branch: *mut *mut Branch,
out_index: *mut u32,
) {
let pos = pos.as_ref().unwrap();
let txn = txn.as_ref().unwrap();
if let Some(abs) = pos.0.get_offset(txn) {
*out_branch = abs.branch.as_ref() as *const Branch as *mut Branch;
*out_index = abs.index as u32;
}
}
pub type Weak = LinkSource;
#[no_mangle]
pub unsafe extern "C" fn yweak_destroy(weak: *const Weak) {
drop(Arc::from_raw(weak));
}
#[no_mangle]
pub unsafe extern "C" fn yweak_deref(
map_link: *const Branch,
txn: *const Transaction,
) -> *mut YOutput {
assert!(!map_link.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let weak: WeakRef<MapRef> = WeakRef::from_raw_branch(map_link);
if let Some(value) = weak.try_deref_value(txn) {
Box::into_raw(Box::new(YOutput::from(value)))
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yweak_read(text_link: *const Branch,
txn: *const Transaction,
out_branch: *mut *mut Branch,
out_start_index: *mut u32,
out_end_index: *mut u32,
) {
assert!(!text_link.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let weak: WeakRef<BranchPtr> = WeakRef::from_raw_branch(text_link);
if let Some(id) = weak.start_id() {
let start = StickyIndex::from_id(*id, Assoc::After);
assert!(weak.end_id() != None);
let end = StickyIndex::from_id(*weak.end_id().unwrap(), Assoc::After);
if let Some(start_pos) = start.get_offset(txn) {
*out_branch = start_pos.branch.as_ref() as *const Branch as *mut Branch;
*out_start_index = start_pos.index as u32;
if let Some(end_pos) = end.get_offset(txn) {
assert!(*out_branch == end_pos.branch.as_ref() as *const Branch as *mut Branch);
*out_end_index = end_pos.index as u32;
}
}
} else {
assert!(weak.end_id() == None); *out_start_index = 0; *out_end_index = 0; }
}
#[no_mangle]
pub unsafe extern "C" fn yweak_iter(
array_link: *const Branch,
txn: *const Transaction,
) -> *mut WeakIter {
assert!(!array_link.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let weak: WeakRef<ArrayRef> = WeakRef::from_raw_branch(array_link);
let iter: NativeUnquote<'static, Transaction> = std::mem::transmute(weak.unquote(txn));
Box::into_raw(Box::new(WeakIter(iter)))
}
#[no_mangle]
pub unsafe extern "C" fn yweak_iter_destroy(iter: *mut WeakIter) {
drop(Box::from_raw(iter))
}
#[no_mangle]
pub unsafe extern "C" fn yweak_iter_next(iter: *mut WeakIter) -> *mut YOutput {
assert!(!iter.is_null());
let iter = iter.as_mut().unwrap();
if let Some(value) = iter.0.next() {
Box::into_raw(Box::new(YOutput::from(value)))
} else {
null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn yweak_string(
text_link: *const Branch,
txn: *const Transaction,
) -> *mut c_char {
assert!(!text_link.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let weak: WeakRef<TextRef> = WeakRef::from_raw_branch(text_link);
let str = weak.get_string(txn);
CString::new(str).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn yweak_xml_string(
xml_text_link: *const Branch,
txn: *const Transaction,
) -> *mut c_char {
assert!(!xml_text_link.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let weak: WeakRef<XmlTextRef> = WeakRef::from_raw_branch(xml_text_link);
let str = weak.get_string(txn);
CString::new(str).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn yweak_observe(
weak: *const Branch,
state: *mut c_void,
cb: extern "C" fn(*mut c_void, *const YWeakLinkEvent),
) -> *mut Subscription {
assert!(!weak.is_null());
let state = CallbackState::new(state);
let txt: WeakRef<BranchPtr> = WeakRef::from_raw_branch(weak);
let subscription = txt.observe(move |txn, e| {
let e = YWeakLinkEvent::new(e, txn);
cb(state.0, &e as *const YWeakLinkEvent);
});
Box::into_raw(Box::new(subscription))
}
#[no_mangle]
pub unsafe extern "C" fn ymap_link(
map: *const Branch,
txn: *const Transaction,
key: *const c_char,
) -> *const Weak {
assert!(!map.is_null());
assert!(!txn.is_null());
let txn = txn.as_ref().unwrap();
let map = MapRef::from_raw_branch(map);
let key = CStr::from_ptr(key).to_str().unwrap();
if let Some(weak) = map.link(txn, key) {
let source = weak.source();
Arc::into_raw(source.clone())
} else {
null()
}
}
#[no_mangle]
pub unsafe extern "C" fn ytext_quote(
text: *const Branch,
txn: *mut Transaction,
start_index: u32,
end_index: u32,
start_exclusive: i8,
end_exclusive: i8,
) -> *const Weak {
assert!(!text.is_null());
assert!(!txn.is_null());
let text = TextRef::from_raw_branch(text);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let range = ExplicitRange {
start_index,
end_index,
start_exclusive,
end_exclusive,
};
if let Ok(weak) = text.quote(txn, range) {
let source = weak.source();
Arc::into_raw(source.clone())
} else {
null()
}
}
#[no_mangle]
pub unsafe extern "C" fn yarray_quote(
array: *const Branch,
txn: *mut Transaction,
start_index: u32,
end_index: u32,
start_exclusive: i8,
end_exclusive: i8,
) -> *const Weak {
assert!(!array.is_null());
assert!(!txn.is_null());
let array = ArrayRef::from_raw_branch(array);
let txn = txn.as_mut().unwrap();
let txn = txn
.as_mut()
.expect("provided transaction was not writeable");
let range = ExplicitRange {
start_index,
end_index,
start_exclusive,
end_exclusive,
};
if let Ok(weak) = array.quote(txn, range) {
let source = weak.source();
Arc::into_raw(source.clone())
} else {
null()
}
}
struct ExplicitRange {
start_index: u32,
end_index: u32,
start_exclusive: i8,
end_exclusive: i8,
}
impl RangeBounds<u32> for ExplicitRange {
fn start_bound(&self) -> Bound<&u32> {
if self.start_exclusive == 0 {
Bound::Included(&self.start_index)
} else {
Bound::Excluded(&self.start_index)
}
}
fn end_bound(&self) -> Bound<&u32> {
if self.end_exclusive == 0 {
Bound::Included(&self.end_index)
} else {
Bound::Excluded(&self.end_index)
}
}
}
#[repr(C)]
pub struct YBranchId {
pub client_or_len: i64,
pub variant: YBranchIdVariant,
}
#[repr(C)]
pub union YBranchIdVariant {
pub clock: u32,
pub name: *const u8,
}
#[no_mangle]
pub unsafe extern "C" fn ybranch_id(branch: *const Branch) -> YBranchId {
let branch = branch.as_ref().unwrap();
match branch.id() {
BranchID::Nested(id) => YBranchId {
client_or_len: id.client as i64,
variant: YBranchIdVariant { clock: id.clock },
},
BranchID::Root(name) => {
let len = -(name.len() as i64);
YBranchId {
client_or_len: len,
variant: YBranchIdVariant {
name: name.as_ptr(),
},
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ybranch_get(
branch_id: *const YBranchId,
txn: *mut Transaction,
) -> *mut Branch {
let txn = txn.as_ref().unwrap();
let branch_id = branch_id.as_ref().unwrap();
let client_or_len = branch_id.client_or_len;
let ptr = if client_or_len >= 0 {
BranchID::get_nested(txn, &ID::new(client_or_len as u64, branch_id.variant.clock))
} else {
let name = std::slice::from_raw_parts(branch_id.variant.name, (-client_or_len) as usize);
BranchID::get_root(txn, std::str::from_utf8_unchecked(name))
};
match ptr {
None => null_mut(),
Some(branch_ptr) => branch_ptr.into_raw_branch(),
}
}
#[no_mangle]
pub unsafe extern "C" fn ybranch_alive(branch: *mut Branch) -> u8 {
if branch.is_null() {
Y_FALSE
} else {
let branch = BranchPtr::from_raw_branch(branch);
if branch.is_deleted() {
Y_FALSE
} else {
Y_TRUE
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ybranch_json(branch: *mut Branch, txn: *mut Transaction) -> *mut c_char {
if branch.is_null() {
std::ptr::null_mut()
} else {
let txn = txn.as_ref().unwrap();
let branch_ref = BranchPtr::from_raw_branch(branch);
let any = match branch_ref.type_ref() {
TypeRef::Array => ArrayRef::from_raw_branch(branch).to_json(txn),
TypeRef::Map => MapRef::from_raw_branch(branch).to_json(txn),
TypeRef::Text => TextRef::from_raw_branch(branch).get_string(txn).into(),
TypeRef::XmlElement(_) => XmlElementRef::from_raw_branch(branch)
.get_string(txn)
.into(),
TypeRef::XmlFragment => XmlFragmentRef::from_raw_branch(branch)
.get_string(txn)
.into(),
TypeRef::XmlText => XmlTextRef::from_raw_branch(branch).get_string(txn).into(),
TypeRef::SubDoc | TypeRef::XmlHook | TypeRef::WeakLink(_) | TypeRef::Undefined => {
return std::ptr::null_mut()
}
};
let json = match serde_json::to_string(&any) {
Ok(json) => json,
Err(_) => return std::ptr::null_mut(),
};
CString::new(json).unwrap().into_raw()
}
}