diff --git a/Cargo.lock b/Cargo.lock index 90bbe7906..4f09ff3f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1863,6 +1863,15 @@ dependencies = [ "wasmparser 0.215.0", ] +[[package]] +name = "loro-wit" +version = "0.1.0" +dependencies = [ + "loro 1.10.0", + "serde_json", + "wit-bindgen-rt", +] + [[package]] name = "loro_fractional_index" version = "0.16.12" @@ -3637,6 +3646,12 @@ version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +[[package]] +name = "wit-bindgen-rt" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7947d0131c7c9da3f01dfde0ab8bd4c4cf3c5bd49b6dba0ae640f1fa752572ea" + [[package]] name = "writeable" version = "0.6.1" diff --git a/Cargo.toml b/Cargo.toml index 51abe7d37..6fee9e69b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "crates/loro-common", "crates/loro-internal", "crates/loro-wasm", + "crates/loro-wit", "crates/fuzz", "crates/fractional_index", "crates/dev-utils", diff --git a/crates/loro-wit/Cargo.toml b/crates/loro-wit/Cargo.toml new file mode 100644 index 000000000..a63ad44f5 --- /dev/null +++ b/crates/loro-wit/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "loro-wit" +version = "0.1.0" +edition = "2021" +description = "WebAssembly Component Model (WIT) bindings for Loro CRDT" +license = "MIT" +repository = "https://github.com/loro-dev/loro" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +loro = { path = "../loro" } +wit-bindgen-rt = "0.36" +serde_json = { workspace = true } + +[package.metadata.component] +package = "loro:crdt" + +[package.metadata.component.target] +path = "wit" diff --git a/crates/loro-wit/src/bindings.rs b/crates/loro-wit/src/bindings.rs new file mode 100644 index 000000000..86d223e85 --- /dev/null +++ b/crates/loro-wit/src/bindings.rs @@ -0,0 +1,2413 @@ +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! +// Options used: +// * runtime_path: "wit_bindgen_rt" +#[rustfmt::skip] +#[allow(dead_code, clippy::all)] +pub mod exports { + pub mod loro { + pub mod crdt { + /// The main document interface for Loro CRDT + #[allow(dead_code, async_fn_in_trait, unused_imports, clippy::all)] + pub mod loro_doc { + #[used] + #[doc(hidden)] + static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + /// A handle to a Loro document + #[derive(Debug)] + #[repr(transparent)] + pub struct Doc { + handle: _rt::Resource, + } + type _DocRep = Option; + impl Doc { + /// Creates a new resource from the specified representation. + /// + /// This function will create a new resource handle by moving `val` onto + /// the heap and then passing that heap pointer to the component model to + /// create a handle. The owned handle is then returned as `Doc`. + pub fn new(val: T) -> Self { + Self::type_guard::(); + let val: _DocRep = Some(val); + let ptr: *mut _DocRep = _rt::Box::into_raw( + _rt::Box::new(val), + ); + unsafe { Self::from_handle(T::_resource_new(ptr.cast())) } + } + /// Gets access to the underlying `T` which represents this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &*self.as_ptr::() }; + ptr.as_ref().unwrap() + } + /// Gets mutable access to the underlying `T` which represents this + /// resource. + pub fn get_mut(&mut self) -> &mut T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_mut().unwrap() + } + /// Consumes this resource and returns the underlying `T`. + pub fn into_inner(self) -> T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.take().unwrap() + } + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: unsafe { _rt::Resource::from_handle(handle) }, + } + } + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + #[doc(hidden)] + fn type_guard() { + use core::any::TypeId; + static mut LAST_TYPE: Option = None; + unsafe { + assert!(! cfg!(target_feature = "atomics")); + let id = TypeId::of::(); + match LAST_TYPE { + Some(ty) => { + assert!( + ty == id, "cannot use two types with this resource type" + ) + } + None => LAST_TYPE = Some(id), + } + } + } + #[doc(hidden)] + pub unsafe fn dtor(handle: *mut u8) { + Self::type_guard::(); + let _ = unsafe { _rt::Box::from_raw(handle as *mut _DocRep) }; + } + fn as_ptr(&self) -> *mut _DocRep { + Doc::type_guard::(); + T::_resource_rep(self.handle()).cast() + } + } + /// A borrowed version of [`Doc`] which represents a borrowed value + /// with the lifetime `'a`. + #[derive(Debug)] + #[repr(transparent)] + pub struct DocBorrow<'a> { + rep: *mut u8, + _marker: core::marker::PhantomData<&'a Doc>, + } + impl<'a> DocBorrow<'a> { + #[doc(hidden)] + pub unsafe fn lift(rep: usize) -> Self { + Self { + rep: rep as *mut u8, + _marker: core::marker::PhantomData, + } + } + /// Gets access to the underlying `T` in this resource. + pub fn get(&self) -> &T { + let ptr = unsafe { &mut *self.as_ptr::() }; + ptr.as_ref().unwrap() + } + fn as_ptr(&self) -> *mut _DocRep { + Doc::type_guard::(); + self.rep.cast() + } + } + unsafe impl _rt::WasmResource for Doc { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]loro:crdt/loro-doc@0.1.0" + )] + unsafe extern "C" { + #[link_name = "[resource-drop]doc"] + fn drop(_: u32); + } + unsafe { drop(_handle) }; + } + } + } + /// Handle to a text container + #[repr(C)] + #[derive(Clone, Copy)] + pub struct TextHandle { + pub id: u64, + } + impl ::core::fmt::Debug for TextHandle { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_struct("TextHandle").field("id", &self.id).finish() + } + } + /// Handle to a map container + #[repr(C)] + #[derive(Clone, Copy)] + pub struct MapHandle { + pub id: u64, + } + impl ::core::fmt::Debug for MapHandle { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_struct("MapHandle").field("id", &self.id).finish() + } + } + /// Handle to a list container + #[repr(C)] + #[derive(Clone, Copy)] + pub struct ListHandle { + pub id: u64, + } + impl ::core::fmt::Debug for ListHandle { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_struct("ListHandle").field("id", &self.id).finish() + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_constructor_doc_cabi() -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = Doc::new(T::new()); + (result0).take_handle() as i32 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_static_doc_new_with_peer_id_cabi( + arg0: i64, + ) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::new_with_peer_id(arg0 as u64); + (result0).take_handle() as i32 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_peer_id_cabi( + arg0: *mut u8, + ) -> i64 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::peer_id( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + ); + _rt::as_i64(result0) + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_get_text_cabi( + arg0: *mut u8, + arg1: *mut u8, + arg2: usize, + ) -> i64 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg2; + let bytes0 = _rt::Vec::from_raw_parts(arg1.cast(), len0, len0); + let result1 = T::get_text( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + _rt::string_lift(bytes0), + ); + let TextHandle { id: id2 } = result1; + _rt::as_i64(id2) + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_get_map_cabi( + arg0: *mut u8, + arg1: *mut u8, + arg2: usize, + ) -> i64 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg2; + let bytes0 = _rt::Vec::from_raw_parts(arg1.cast(), len0, len0); + let result1 = T::get_map( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + _rt::string_lift(bytes0), + ); + let MapHandle { id: id2 } = result1; + _rt::as_i64(id2) + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_get_list_cabi( + arg0: *mut u8, + arg1: *mut u8, + arg2: usize, + ) -> i64 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg2; + let bytes0 = _rt::Vec::from_raw_parts(arg1.cast(), len0, len0); + let result1 = T::get_list( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + _rt::string_lift(bytes0), + ); + let ListHandle { id: id2 } = result1; + _rt::as_i64(id2) + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_commit_cabi( + arg0: *mut u8, + arg1: i32, + arg2: *mut u8, + arg3: usize, + ) { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + T::commit( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + match arg1 { + 0 => None, + 1 => { + let e = { + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts( + arg2.cast(), + len0, + len0, + ); + _rt::string_lift(bytes0) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }, + ); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_export_updates_cabi( + arg0: *mut u8, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::export_updates( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec2 = (result0).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_doc_export_updates( + arg0: *mut u8, + ) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::(); + let base2 = l0; + let len2 = l1; + _rt::cabi_dealloc(base2, len2 * 1, 1); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_export_snapshot_cabi( + arg0: *mut u8, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::export_snapshot( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec2 = (result0).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_doc_export_snapshot( + arg0: *mut u8, + ) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::(); + let base2 = l0; + let len2 = l1; + _rt::cabi_dealloc(base2, len2 * 1, 1); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_import_updates_cabi( + arg0: *mut u8, + arg1: *mut u8, + arg2: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg2; + let result1 = T::import_updates( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + _rt::Vec::from_raw_parts(arg1.cast(), len0, len0), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_doc_import_updates( + arg0: *mut u8, + ) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_to_json_cabi( + arg0: *mut u8, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::to_json( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_method_doc_to_json( + arg0: *mut u8, + ) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l0, l1, 1); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_is_empty_cabi( + arg0: *mut u8, + ) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::is_empty( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + ); + match result0 { + true => 1, + false => 0, + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_method_doc_fork_cabi( + arg0: *mut u8, + ) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::fork( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }.get(), + ); + (result0).take_handle() as i32 + } + pub trait Guest { + type Doc: GuestDoc; + } + pub trait GuestDoc: 'static { + #[doc(hidden)] + unsafe fn _resource_new(val: *mut u8) -> u32 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = val; + unreachable!(); + } + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]loro:crdt/loro-doc@0.1.0" + )] + unsafe extern "C" { + #[link_name = "[resource-new]doc"] + fn new(_: *mut u8) -> u32; + } + unsafe { new(val) } + } + } + #[doc(hidden)] + fn _resource_rep(handle: u32) -> *mut u8 + where + Self: Sized, + { + #[cfg(not(target_arch = "wasm32"))] + { + let _ = handle; + unreachable!(); + } + #[cfg(target_arch = "wasm32")] + { + #[link( + wasm_import_module = "[export]loro:crdt/loro-doc@0.1.0" + )] + unsafe extern "C" { + #[link_name = "[resource-rep]doc"] + fn rep(_: u32) -> *mut u8; + } + unsafe { rep(handle) } + } + } + /// Create a new Loro document + fn new() -> Self; + /// Create a new Loro document with a specific peer ID + fn new_with_peer_id(peer_id: u64) -> Doc; + /// Get the peer ID of this document + fn peer_id(&self) -> u64; + /// Get a text container by name + fn get_text(&self, name: _rt::String) -> TextHandle; + /// Get a map container by name + fn get_map(&self, name: _rt::String) -> MapHandle; + /// Get a list container by name + fn get_list(&self, name: _rt::String) -> ListHandle; + /// Commit pending changes with an optional message + fn commit(&self, message: Option<_rt::String>) -> (); + /// Export all updates as bytes + fn export_updates(&self) -> _rt::Vec; + /// Export a snapshot as bytes + fn export_snapshot(&self) -> _rt::Vec; + /// Import updates from bytes + fn import_updates( + &self, + bytes: _rt::Vec, + ) -> Result<(), _rt::String>; + /// Get the JSON representation of the document + fn to_json(&self) -> _rt::String; + /// Check if the document is empty + fn is_empty(&self) -> bool; + /// Fork the document to create an independent copy + fn fork(&self) -> Doc; + } + #[doc(hidden)] + macro_rules! __export_loro_crdt_loro_doc_0_1_0_cabi { + ($ty:ident with_types_in $($path_to_types:tt)*) => { + const _ : () = { #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[constructor]doc")] unsafe extern "C" + fn export_constructor_doc() -> i32 { unsafe { + $($path_to_types)*:: _export_constructor_doc_cabi::<<$ty as + $($path_to_types)*:: Guest >::Doc > () } } #[unsafe (export_name + = "loro:crdt/loro-doc@0.1.0#[static]doc.new-with-peer-id")] + unsafe extern "C" fn export_static_doc_new_with_peer_id(arg0 : + i64,) -> i32 { unsafe { $($path_to_types)*:: + _export_static_doc_new_with_peer_id_cabi::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0) } } #[unsafe + (export_name = "loro:crdt/loro-doc@0.1.0#[method]doc.peer-id")] + unsafe extern "C" fn export_method_doc_peer_id(arg0 : * mut u8,) + -> i64 { unsafe { $($path_to_types)*:: + _export_method_doc_peer_id_cabi::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0) } } #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.get-text")] unsafe extern + "C" fn export_method_doc_get_text(arg0 : * mut u8, arg1 : * mut + u8, arg2 : usize,) -> i64 { unsafe { $($path_to_types)*:: + _export_method_doc_get_text_cabi::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0, arg1, arg2) } } #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.get-map")] unsafe extern + "C" fn export_method_doc_get_map(arg0 : * mut u8, arg1 : * mut + u8, arg2 : usize,) -> i64 { unsafe { $($path_to_types)*:: + _export_method_doc_get_map_cabi::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0, arg1, arg2) } } #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.get-list")] unsafe extern + "C" fn export_method_doc_get_list(arg0 : * mut u8, arg1 : * mut + u8, arg2 : usize,) -> i64 { unsafe { $($path_to_types)*:: + _export_method_doc_get_list_cabi::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0, arg1, arg2) } } #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.commit")] unsafe extern "C" + fn export_method_doc_commit(arg0 : * mut u8, arg1 : i32, arg2 : * + mut u8, arg3 : usize,) { unsafe { $($path_to_types)*:: + _export_method_doc_commit_cabi::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0, arg1, arg2, arg3) } } #[unsafe (export_name + = "loro:crdt/loro-doc@0.1.0#[method]doc.export-updates")] unsafe + extern "C" fn export_method_doc_export_updates(arg0 : * mut u8,) + -> * mut u8 { unsafe { $($path_to_types)*:: + _export_method_doc_export_updates_cabi::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0) } } #[unsafe + (export_name = + "cabi_post_loro:crdt/loro-doc@0.1.0#[method]doc.export-updates")] + unsafe extern "C" fn _post_return_method_doc_export_updates(arg0 + : * mut u8,) { unsafe { $($path_to_types)*:: + __post_return_method_doc_export_updates::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0) } } #[unsafe + (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.export-snapshot")] unsafe + extern "C" fn export_method_doc_export_snapshot(arg0 : * mut u8,) + -> * mut u8 { unsafe { $($path_to_types)*:: + _export_method_doc_export_snapshot_cabi::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0) } } #[unsafe + (export_name = + "cabi_post_loro:crdt/loro-doc@0.1.0#[method]doc.export-snapshot")] + unsafe extern "C" fn _post_return_method_doc_export_snapshot(arg0 + : * mut u8,) { unsafe { $($path_to_types)*:: + __post_return_method_doc_export_snapshot::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0) } } #[unsafe + (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.import-updates")] unsafe + extern "C" fn export_method_doc_import_updates(arg0 : * mut u8, + arg1 : * mut u8, arg2 : usize,) -> * mut u8 { unsafe { + $($path_to_types)*:: + _export_method_doc_import_updates_cabi::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0, arg1, arg2) } } + #[unsafe (export_name = + "cabi_post_loro:crdt/loro-doc@0.1.0#[method]doc.import-updates")] + unsafe extern "C" fn _post_return_method_doc_import_updates(arg0 + : * mut u8,) { unsafe { $($path_to_types)*:: + __post_return_method_doc_import_updates::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0) } } #[unsafe + (export_name = "loro:crdt/loro-doc@0.1.0#[method]doc.to-json")] + unsafe extern "C" fn export_method_doc_to_json(arg0 : * mut u8,) + -> * mut u8 { unsafe { $($path_to_types)*:: + _export_method_doc_to_json_cabi::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-doc@0.1.0#[method]doc.to-json")] unsafe + extern "C" fn _post_return_method_doc_to_json(arg0 : * mut u8,) { + unsafe { $($path_to_types)*:: + __post_return_method_doc_to_json::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0) } } #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.is-empty")] unsafe extern + "C" fn export_method_doc_is_empty(arg0 : * mut u8,) -> i32 { + unsafe { $($path_to_types)*:: + _export_method_doc_is_empty_cabi::<<$ty as $($path_to_types)*:: + Guest >::Doc > (arg0) } } #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[method]doc.fork")] unsafe extern "C" + fn export_method_doc_fork(arg0 : * mut u8,) -> i32 { unsafe { + $($path_to_types)*:: _export_method_doc_fork_cabi::<<$ty as + $($path_to_types)*:: Guest >::Doc > (arg0) } } const _ : () = { + #[doc(hidden)] #[unsafe (export_name = + "loro:crdt/loro-doc@0.1.0#[dtor]doc")] #[allow(non_snake_case)] + unsafe extern "C" fn dtor(rep : * mut u8) { unsafe { + $($path_to_types)*:: Doc::dtor::< <$ty as $($path_to_types)*:: + Guest >::Doc > (rep) } } }; }; + }; + } + #[doc(hidden)] + pub(crate) use __export_loro_crdt_loro_doc_0_1_0_cabi; + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + struct _RetArea( + [::core::mem::MaybeUninit< + u8, + >; 3 * ::core::mem::size_of::<*const u8>()], + ); + static mut _RET_AREA: _RetArea = _RetArea( + [::core::mem::MaybeUninit::uninit(); 3 + * ::core::mem::size_of::<*const u8>()], + ); + } + /// Text CRDT operations + #[allow(dead_code, async_fn_in_trait, unused_imports, clippy::all)] + pub mod loro_text { + #[used] + #[doc(hidden)] + static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + pub type Doc = super::super::super::super::exports::loro::crdt::loro_doc::Doc; + pub type DocBorrow<'a> = super::super::super::super::exports::loro::crdt::loro_doc::DocBorrow< + 'a, + >; + pub type TextHandle = super::super::super::super::exports::loro::crdt::loro_doc::TextHandle; + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + arg3: *mut u8, + arg4: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg4; + let bytes0 = _rt::Vec::from_raw_parts(arg3.cast(), len0, len0); + let result1 = T::insert( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::TextHandle { + id: arg1 as u64, + }, + arg2 as u32, + _rt::string_lift(bytes0), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_delete_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + arg3: i32, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::delete( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::TextHandle { + id: arg1 as u64, + }, + arg2 as u32, + arg3 as u32, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + match result0 { + Ok(_) => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *ptr1 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr2.cast_mut(); + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_delete(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_to_string_cabi( + arg0: i32, + arg1: i64, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::to_string( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::TextHandle { + id: arg1 as u64, + }, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_to_string(arg0: *mut u8) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l0, l1, 1); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_len_utf8_cabi( + arg0: i32, + arg1: i64, + ) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::len_utf8( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::TextHandle { + id: arg1 as u64, + }, + ); + _rt::as_i32(result0) + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_len_unicode_cabi( + arg0: i32, + arg1: i64, + ) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::len_unicode( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::TextHandle { + id: arg1 as u64, + }, + ); + _rt::as_i32(result0) + } + pub trait Guest { + /// Insert text at a position + fn insert( + doc: DocBorrow<'_>, + handle: TextHandle, + pos: u32, + text: _rt::String, + ) -> Result<(), _rt::String>; + /// Delete text at a range + fn delete( + doc: DocBorrow<'_>, + handle: TextHandle, + pos: u32, + len: u32, + ) -> Result<(), _rt::String>; + /// Get the text content as a string + fn to_string(doc: DocBorrow<'_>, handle: TextHandle) -> _rt::String; + /// Get the length of the text in UTF-8 bytes + fn len_utf8(doc: DocBorrow<'_>, handle: TextHandle) -> u32; + /// Get the length of the text in Unicode characters + fn len_unicode(doc: DocBorrow<'_>, handle: TextHandle) -> u32; + } + #[doc(hidden)] + macro_rules! __export_loro_crdt_loro_text_0_1_0_cabi { + ($ty:ident with_types_in $($path_to_types:tt)*) => { + const _ : () = { #[unsafe (export_name = + "loro:crdt/loro-text@0.1.0#insert")] unsafe extern "C" fn + export_insert(arg0 : i32, arg1 : i64, arg2 : i32, arg3 : * mut + u8, arg4 : usize,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_insert_cabi::<$ty > (arg0, arg1, arg2, arg3, arg4) } } + #[unsafe (export_name = + "cabi_post_loro:crdt/loro-text@0.1.0#insert")] unsafe extern "C" + fn _post_return_insert(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_insert::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-text@0.1.0#delete")] + unsafe extern "C" fn export_delete(arg0 : i32, arg1 : i64, arg2 : + i32, arg3 : i32,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_delete_cabi::<$ty > (arg0, arg1, arg2, arg3) } } #[unsafe + (export_name = "cabi_post_loro:crdt/loro-text@0.1.0#delete")] + unsafe extern "C" fn _post_return_delete(arg0 : * mut u8,) { + unsafe { $($path_to_types)*:: __post_return_delete::<$ty > (arg0) + } } #[unsafe (export_name = + "loro:crdt/loro-text@0.1.0#to-string")] unsafe extern "C" fn + export_to_string(arg0 : i32, arg1 : i64,) -> * mut u8 { unsafe { + $($path_to_types)*:: _export_to_string_cabi::<$ty > (arg0, arg1) + } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-text@0.1.0#to-string")] unsafe extern + "C" fn _post_return_to_string(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_to_string::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-text@0.1.0#len-utf8")] + unsafe extern "C" fn export_len_utf8(arg0 : i32, arg1 : i64,) -> + i32 { unsafe { $($path_to_types)*:: _export_len_utf8_cabi::<$ty > + (arg0, arg1) } } #[unsafe (export_name = + "loro:crdt/loro-text@0.1.0#len-unicode")] unsafe extern "C" fn + export_len_unicode(arg0 : i32, arg1 : i64,) -> i32 { unsafe { + $($path_to_types)*:: _export_len_unicode_cabi::<$ty > (arg0, + arg1) } } }; + }; + } + #[doc(hidden)] + pub(crate) use __export_loro_crdt_loro_text_0_1_0_cabi; + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + struct _RetArea( + [::core::mem::MaybeUninit< + u8, + >; 3 * ::core::mem::size_of::<*const u8>()], + ); + static mut _RET_AREA: _RetArea = _RetArea( + [::core::mem::MaybeUninit::uninit(); 3 + * ::core::mem::size_of::<*const u8>()], + ); + } + /// Map CRDT operations + #[allow(dead_code, async_fn_in_trait, unused_imports, clippy::all)] + pub mod loro_map { + #[used] + #[doc(hidden)] + static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + pub type Doc = super::super::super::super::exports::loro::crdt::loro_doc::Doc; + pub type DocBorrow<'a> = super::super::super::super::exports::loro::crdt::loro_doc::DocBorrow< + 'a, + >; + pub type MapHandle = super::super::super::super::exports::loro::crdt::loro_doc::MapHandle; + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_string_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + arg4: *mut u8, + arg5: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let len1 = arg5; + let bytes1 = _rt::Vec::from_raw_parts(arg4.cast(), len1, len1); + let result2 = T::insert_string( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + _rt::string_lift(bytes1), + ); + let ptr3 = (&raw mut _RET_AREA.0).cast::(); + match result2 { + Ok(_) => { + *ptr3.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr3.add(0).cast::() = (1i32) as u8; + let vec4 = (e.into_bytes()).into_boxed_slice(); + let ptr4 = vec4.as_ptr().cast::(); + let len4 = vec4.len(); + ::core::mem::forget(vec4); + *ptr3 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len4; + *ptr3 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr4.cast_mut(); + } + }; + ptr3 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_string(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_number_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + arg4: f64, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let result1 = T::insert_number( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + arg4, + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_number(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_bool_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + arg4: i32, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let result1 = T::insert_bool( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + _rt::bool_lift(arg4 as u8), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_bool(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_null_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let result1 = T::insert_null( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_null(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_get_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let result1 = T::get( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Some(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + None => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_get(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_delete_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let result1 = T::delete( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_delete(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_contains_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + ) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let result1 = T::contains( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + ); + match result1 { + true => 1, + false => 0, + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_keys_cabi( + arg0: i32, + arg1: i64, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::keys( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec3 = result0; + let len3 = vec3.len(); + let layout3 = _rt::alloc::Layout::from_size_align_unchecked( + vec3.len() * (2 * ::core::mem::size_of::<*const u8>()), + ::core::mem::size_of::<*const u8>(), + ); + let result3 = if layout3.size() != 0 { + let ptr = _rt::alloc::alloc(layout3).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout3); + } + ptr + } else { + ::core::ptr::null_mut() + }; + for (i, e) in vec3.into_iter().enumerate() { + let base = result3 + .add(i * (2 * ::core::mem::size_of::<*const u8>())); + { + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *base + .add(::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *base.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + } + } + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len3; + *ptr1.add(0).cast::<*mut u8>() = result3; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_keys(arg0: *mut u8) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::(); + let base4 = l0; + let len4 = l1; + for i in 0..len4 { + let base = base4 + .add(i * (2 * ::core::mem::size_of::<*const u8>())); + { + let l2 = *base.add(0).cast::<*mut u8>(); + let l3 = *base + .add(::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l2, l3, 1); + } + } + _rt::cabi_dealloc( + base4, + len4 * (2 * ::core::mem::size_of::<*const u8>()), + ::core::mem::size_of::<*const u8>(), + ); + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_len_cabi(arg0: i32, arg1: i64) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::len( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::MapHandle { + id: arg1 as u64, + }, + ); + _rt::as_i32(result0) + } + pub trait Guest { + /// Insert or update a string value + fn insert_string( + doc: DocBorrow<'_>, + handle: MapHandle, + key: _rt::String, + value: _rt::String, + ) -> Result<(), _rt::String>; + /// Insert or update a number value + fn insert_number( + doc: DocBorrow<'_>, + handle: MapHandle, + key: _rt::String, + value: f64, + ) -> Result<(), _rt::String>; + /// Insert or update a boolean value + fn insert_bool( + doc: DocBorrow<'_>, + handle: MapHandle, + key: _rt::String, + value: bool, + ) -> Result<(), _rt::String>; + /// Insert a null value + fn insert_null( + doc: DocBorrow<'_>, + handle: MapHandle, + key: _rt::String, + ) -> Result<(), _rt::String>; + /// Get a value by key (returns JSON string) + fn get( + doc: DocBorrow<'_>, + handle: MapHandle, + key: _rt::String, + ) -> Option<_rt::String>; + /// Delete a key + fn delete( + doc: DocBorrow<'_>, + handle: MapHandle, + key: _rt::String, + ) -> Result<(), _rt::String>; + /// Check if a key exists + fn contains( + doc: DocBorrow<'_>, + handle: MapHandle, + key: _rt::String, + ) -> bool; + /// Get all keys + fn keys( + doc: DocBorrow<'_>, + handle: MapHandle, + ) -> _rt::Vec<_rt::String>; + /// Get the number of entries + fn len(doc: DocBorrow<'_>, handle: MapHandle) -> u32; + } + #[doc(hidden)] + macro_rules! __export_loro_crdt_loro_map_0_1_0_cabi { + ($ty:ident with_types_in $($path_to_types:tt)*) => { + const _ : () = { #[unsafe (export_name = + "loro:crdt/loro-map@0.1.0#insert-string")] unsafe extern "C" fn + export_insert_string(arg0 : i32, arg1 : i64, arg2 : * mut u8, + arg3 : usize, arg4 : * mut u8, arg5 : usize,) -> * mut u8 { + unsafe { $($path_to_types)*:: _export_insert_string_cabi::<$ty > + (arg0, arg1, arg2, arg3, arg4, arg5) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-map@0.1.0#insert-string")] unsafe + extern "C" fn _post_return_insert_string(arg0 : * mut u8,) { + unsafe { $($path_to_types)*:: __post_return_insert_string::<$ty > + (arg0) } } #[unsafe (export_name = + "loro:crdt/loro-map@0.1.0#insert-number")] unsafe extern "C" fn + export_insert_number(arg0 : i32, arg1 : i64, arg2 : * mut u8, + arg3 : usize, arg4 : f64,) -> * mut u8 { unsafe { + $($path_to_types)*:: _export_insert_number_cabi::<$ty > (arg0, + arg1, arg2, arg3, arg4) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-map@0.1.0#insert-number")] unsafe + extern "C" fn _post_return_insert_number(arg0 : * mut u8,) { + unsafe { $($path_to_types)*:: __post_return_insert_number::<$ty > + (arg0) } } #[unsafe (export_name = + "loro:crdt/loro-map@0.1.0#insert-bool")] unsafe extern "C" fn + export_insert_bool(arg0 : i32, arg1 : i64, arg2 : * mut u8, arg3 + : usize, arg4 : i32,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_insert_bool_cabi::<$ty > (arg0, arg1, arg2, arg3, arg4) } + } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-map@0.1.0#insert-bool")] unsafe extern + "C" fn _post_return_insert_bool(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_insert_bool::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-map@0.1.0#insert-null")] + unsafe extern "C" fn export_insert_null(arg0 : i32, arg1 : i64, + arg2 : * mut u8, arg3 : usize,) -> * mut u8 { unsafe { + $($path_to_types)*:: _export_insert_null_cabi::<$ty > (arg0, + arg1, arg2, arg3) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-map@0.1.0#insert-null")] unsafe extern + "C" fn _post_return_insert_null(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_insert_null::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-map@0.1.0#get")] unsafe + extern "C" fn export_get(arg0 : i32, arg1 : i64, arg2 : * mut u8, + arg3 : usize,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_get_cabi::<$ty > (arg0, arg1, arg2, arg3) } } #[unsafe + (export_name = "cabi_post_loro:crdt/loro-map@0.1.0#get")] unsafe + extern "C" fn _post_return_get(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_get::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-map@0.1.0#delete")] + unsafe extern "C" fn export_delete(arg0 : i32, arg1 : i64, arg2 : + * mut u8, arg3 : usize,) -> * mut u8 { unsafe { + $($path_to_types)*:: _export_delete_cabi::<$ty > (arg0, arg1, + arg2, arg3) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-map@0.1.0#delete")] unsafe extern "C" + fn _post_return_delete(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_delete::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-map@0.1.0#contains")] + unsafe extern "C" fn export_contains(arg0 : i32, arg1 : i64, arg2 + : * mut u8, arg3 : usize,) -> i32 { unsafe { $($path_to_types)*:: + _export_contains_cabi::<$ty > (arg0, arg1, arg2, arg3) } } + #[unsafe (export_name = "loro:crdt/loro-map@0.1.0#keys")] unsafe + extern "C" fn export_keys(arg0 : i32, arg1 : i64,) -> * mut u8 { + unsafe { $($path_to_types)*:: _export_keys_cabi::<$ty > (arg0, + arg1) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-map@0.1.0#keys")] unsafe extern "C" fn + _post_return_keys(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_keys::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-map@0.1.0#len")] unsafe + extern "C" fn export_len(arg0 : i32, arg1 : i64,) -> i32 { unsafe + { $($path_to_types)*:: _export_len_cabi::<$ty > (arg0, arg1) } } + }; + }; + } + #[doc(hidden)] + pub(crate) use __export_loro_crdt_loro_map_0_1_0_cabi; + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + struct _RetArea( + [::core::mem::MaybeUninit< + u8, + >; 3 * ::core::mem::size_of::<*const u8>()], + ); + static mut _RET_AREA: _RetArea = _RetArea( + [::core::mem::MaybeUninit::uninit(); 3 + * ::core::mem::size_of::<*const u8>()], + ); + } + /// List CRDT operations + #[allow(dead_code, async_fn_in_trait, unused_imports, clippy::all)] + pub mod loro_list { + #[used] + #[doc(hidden)] + static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + pub type Doc = super::super::super::super::exports::loro::crdt::loro_doc::Doc; + pub type DocBorrow<'a> = super::super::super::super::exports::loro::crdt::loro_doc::DocBorrow< + 'a, + >; + pub type ListHandle = super::super::super::super::exports::loro::crdt::loro_doc::ListHandle; + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_string_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + arg3: *mut u8, + arg4: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg4; + let bytes0 = _rt::Vec::from_raw_parts(arg3.cast(), len0, len0); + let result1 = T::insert_string( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + arg2 as u32, + _rt::string_lift(bytes0), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_string(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_number_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + arg3: f64, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::insert_number( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + arg2 as u32, + arg3, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + match result0 { + Ok(_) => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *ptr1 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr2.cast_mut(); + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_number(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_bool_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + arg3: i32, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::insert_bool( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + arg2 as u32, + _rt::bool_lift(arg3 as u8), + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + match result0 { + Ok(_) => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *ptr1 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr2.cast_mut(); + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_bool(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_insert_null_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::insert_null( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + arg2 as u32, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + match result0 { + Ok(_) => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *ptr1 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr2.cast_mut(); + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_insert_null(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_push_string_cabi( + arg0: i32, + arg1: i64, + arg2: *mut u8, + arg3: usize, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let len0 = arg3; + let bytes0 = _rt::Vec::from_raw_parts(arg2.cast(), len0, len0); + let result1 = T::push_string( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + _rt::string_lift(bytes0), + ); + let ptr2 = (&raw mut _RET_AREA.0).cast::(); + match result1 { + Ok(_) => { + *ptr2.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr2.add(0).cast::() = (1i32) as u8; + let vec3 = (e.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *ptr2 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len3; + *ptr2 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr3.cast_mut(); + } + }; + ptr2 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_push_string(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_push_number_cabi( + arg0: i32, + arg1: i64, + arg2: f64, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::push_number( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + arg2, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + match result0 { + Ok(_) => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *ptr1 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr2.cast_mut(); + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_push_number(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_get_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::get( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + arg2 as u32, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + match result0 { + Some(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *ptr1 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr2.cast_mut(); + } + None => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_get(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_delete_cabi( + arg0: i32, + arg1: i64, + arg2: i32, + ) -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::delete( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + arg2 as u32, + ); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + match result0 { + Ok(_) => { + *ptr1.add(0).cast::() = (0i32) as u8; + } + Err(e) => { + *ptr1.add(0).cast::() = (1i32) as u8; + let vec2 = (e.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::() = len2; + *ptr1 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>() = ptr2.cast_mut(); + } + }; + ptr1 + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn __post_return_delete(arg0: *mut u8) { + let l0 = i32::from(*arg0.add(0).cast::()); + match l0 { + 0 => {} + _ => { + let l1 = *arg0 + .add(::core::mem::size_of::<*const u8>()) + .cast::<*mut u8>(); + let l2 = *arg0 + .add(2 * ::core::mem::size_of::<*const u8>()) + .cast::(); + _rt::cabi_dealloc(l1, l2, 1); + } + } + } + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_len_cabi(arg0: i32, arg1: i64) -> i32 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::len( + unsafe { DocBorrow::lift(arg0 as u32 as usize) }, + super::super::super::super::exports::loro::crdt::loro_doc::ListHandle { + id: arg1 as u64, + }, + ); + _rt::as_i32(result0) + } + pub trait Guest { + /// Insert a string value at position + fn insert_string( + doc: DocBorrow<'_>, + handle: ListHandle, + pos: u32, + value: _rt::String, + ) -> Result<(), _rt::String>; + /// Insert a number value at position + fn insert_number( + doc: DocBorrow<'_>, + handle: ListHandle, + pos: u32, + value: f64, + ) -> Result<(), _rt::String>; + /// Insert a boolean value at position + fn insert_bool( + doc: DocBorrow<'_>, + handle: ListHandle, + pos: u32, + value: bool, + ) -> Result<(), _rt::String>; + /// Insert a null value at position + fn insert_null( + doc: DocBorrow<'_>, + handle: ListHandle, + pos: u32, + ) -> Result<(), _rt::String>; + /// Push a string value to the end + fn push_string( + doc: DocBorrow<'_>, + handle: ListHandle, + value: _rt::String, + ) -> Result<(), _rt::String>; + /// Push a number value to the end + fn push_number( + doc: DocBorrow<'_>, + handle: ListHandle, + value: f64, + ) -> Result<(), _rt::String>; + /// Get a value at index (returns JSON string) + fn get( + doc: DocBorrow<'_>, + handle: ListHandle, + index: u32, + ) -> Option<_rt::String>; + /// Delete an element at index + fn delete( + doc: DocBorrow<'_>, + handle: ListHandle, + index: u32, + ) -> Result<(), _rt::String>; + /// Get the length of the list + fn len(doc: DocBorrow<'_>, handle: ListHandle) -> u32; + } + #[doc(hidden)] + macro_rules! __export_loro_crdt_loro_list_0_1_0_cabi { + ($ty:ident with_types_in $($path_to_types:tt)*) => { + const _ : () = { #[unsafe (export_name = + "loro:crdt/loro-list@0.1.0#insert-string")] unsafe extern "C" fn + export_insert_string(arg0 : i32, arg1 : i64, arg2 : i32, arg3 : * + mut u8, arg4 : usize,) -> * mut u8 { unsafe { + $($path_to_types)*:: _export_insert_string_cabi::<$ty > (arg0, + arg1, arg2, arg3, arg4) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-list@0.1.0#insert-string")] unsafe + extern "C" fn _post_return_insert_string(arg0 : * mut u8,) { + unsafe { $($path_to_types)*:: __post_return_insert_string::<$ty > + (arg0) } } #[unsafe (export_name = + "loro:crdt/loro-list@0.1.0#insert-number")] unsafe extern "C" fn + export_insert_number(arg0 : i32, arg1 : i64, arg2 : i32, arg3 : + f64,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_insert_number_cabi::<$ty > (arg0, arg1, arg2, arg3) } } + #[unsafe (export_name = + "cabi_post_loro:crdt/loro-list@0.1.0#insert-number")] unsafe + extern "C" fn _post_return_insert_number(arg0 : * mut u8,) { + unsafe { $($path_to_types)*:: __post_return_insert_number::<$ty > + (arg0) } } #[unsafe (export_name = + "loro:crdt/loro-list@0.1.0#insert-bool")] unsafe extern "C" fn + export_insert_bool(arg0 : i32, arg1 : i64, arg2 : i32, arg3 : + i32,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_insert_bool_cabi::<$ty > (arg0, arg1, arg2, arg3) } } + #[unsafe (export_name = + "cabi_post_loro:crdt/loro-list@0.1.0#insert-bool")] unsafe extern + "C" fn _post_return_insert_bool(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_insert_bool::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-list@0.1.0#insert-null")] + unsafe extern "C" fn export_insert_null(arg0 : i32, arg1 : i64, + arg2 : i32,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_insert_null_cabi::<$ty > (arg0, arg1, arg2) } } #[unsafe + (export_name = + "cabi_post_loro:crdt/loro-list@0.1.0#insert-null")] unsafe extern + "C" fn _post_return_insert_null(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_insert_null::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-list@0.1.0#push-string")] + unsafe extern "C" fn export_push_string(arg0 : i32, arg1 : i64, + arg2 : * mut u8, arg3 : usize,) -> * mut u8 { unsafe { + $($path_to_types)*:: _export_push_string_cabi::<$ty > (arg0, + arg1, arg2, arg3) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-list@0.1.0#push-string")] unsafe extern + "C" fn _post_return_push_string(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_push_string::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-list@0.1.0#push-number")] + unsafe extern "C" fn export_push_number(arg0 : i32, arg1 : i64, + arg2 : f64,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_push_number_cabi::<$ty > (arg0, arg1, arg2) } } #[unsafe + (export_name = + "cabi_post_loro:crdt/loro-list@0.1.0#push-number")] unsafe extern + "C" fn _post_return_push_number(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_push_number::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-list@0.1.0#get")] unsafe + extern "C" fn export_get(arg0 : i32, arg1 : i64, arg2 : i32,) -> + * mut u8 { unsafe { $($path_to_types)*:: _export_get_cabi::<$ty > + (arg0, arg1, arg2) } } #[unsafe (export_name = + "cabi_post_loro:crdt/loro-list@0.1.0#get")] unsafe extern "C" fn + _post_return_get(arg0 : * mut u8,) { unsafe { + $($path_to_types)*:: __post_return_get::<$ty > (arg0) } } + #[unsafe (export_name = "loro:crdt/loro-list@0.1.0#delete")] + unsafe extern "C" fn export_delete(arg0 : i32, arg1 : i64, arg2 : + i32,) -> * mut u8 { unsafe { $($path_to_types)*:: + _export_delete_cabi::<$ty > (arg0, arg1, arg2) } } #[unsafe + (export_name = "cabi_post_loro:crdt/loro-list@0.1.0#delete")] + unsafe extern "C" fn _post_return_delete(arg0 : * mut u8,) { + unsafe { $($path_to_types)*:: __post_return_delete::<$ty > (arg0) + } } #[unsafe (export_name = "loro:crdt/loro-list@0.1.0#len")] + unsafe extern "C" fn export_len(arg0 : i32, arg1 : i64,) -> i32 { + unsafe { $($path_to_types)*:: _export_len_cabi::<$ty > (arg0, + arg1) } } }; + }; + } + #[doc(hidden)] + pub(crate) use __export_loro_crdt_loro_list_0_1_0_cabi; + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + struct _RetArea( + [::core::mem::MaybeUninit< + u8, + >; 3 * ::core::mem::size_of::<*const u8>()], + ); + static mut _RET_AREA: _RetArea = _RetArea( + [::core::mem::MaybeUninit::uninit(); 3 + * ::core::mem::size_of::<*const u8>()], + ); + } + } + } +} +#[rustfmt::skip] +mod _rt { + #![allow(dead_code, clippy::all)] + use core::fmt; + use core::marker; + use core::sync::atomic::{AtomicU32, Ordering::Relaxed}; + /// A type which represents a component model resource, either imported or + /// exported into this component. + /// + /// This is a low-level wrapper which handles the lifetime of the resource + /// (namely this has a destructor). The `T` provided defines the component model + /// intrinsics that this wrapper uses. + /// + /// One of the chief purposes of this type is to provide `Deref` implementations + /// to access the underlying data when it is owned. + /// + /// This type is primarily used in generated code for exported and imported + /// resources. + #[repr(transparent)] + pub struct Resource { + handle: AtomicU32, + _marker: marker::PhantomData, + } + /// A trait which all wasm resources implement, namely providing the ability to + /// drop a resource. + /// + /// This generally is implemented by generated code, not user-facing code. + #[allow(clippy::missing_safety_doc)] + pub unsafe trait WasmResource { + /// Invokes the `[resource-drop]...` intrinsic. + unsafe fn drop(handle: u32); + } + impl Resource { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + debug_assert!(handle != u32::MAX); + Self { + handle: AtomicU32::new(handle), + _marker: marker::PhantomData, + } + } + /// Takes ownership of the handle owned by `resource`. + /// + /// Note that this ideally would be `into_handle` taking `Resource` by + /// ownership. The code generator does not enable that in all situations, + /// unfortunately, so this is provided instead. + /// + /// Also note that `take_handle` is in theory only ever called on values + /// owned by a generated function. For example a generated function might + /// take `Resource` as an argument but then call `take_handle` on a + /// reference to that argument. In that sense the dynamic nature of + /// `take_handle` should only be exposed internally to generated code, not + /// to user code. + #[doc(hidden)] + pub fn take_handle(resource: &Resource) -> u32 { + resource.handle.swap(u32::MAX, Relaxed) + } + #[doc(hidden)] + pub fn handle(resource: &Resource) -> u32 { + resource.handle.load(Relaxed) + } + } + impl fmt::Debug for Resource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Resource").field("handle", &self.handle).finish() + } + } + impl Drop for Resource { + fn drop(&mut self) { + unsafe { + match self.handle.load(Relaxed) { + u32::MAX => {} + other => T::drop(other), + } + } + } + } + pub use alloc_crate::boxed::Box; + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + pub fn as_i64(t: T) -> i64 { + t.as_i64() + } + pub trait AsI64 { + fn as_i64(self) -> i64; + } + impl<'a, T: Copy + AsI64> AsI64 for &'a T { + fn as_i64(self) -> i64 { + (*self).as_i64() + } + } + impl AsI64 for i64 { + #[inline] + fn as_i64(self) -> i64 { + self as i64 + } + } + impl AsI64 for u64 { + #[inline] + fn as_i64(self) -> i64 { + self as i64 + } + } + pub use alloc_crate::vec::Vec; + pub unsafe fn string_lift(bytes: Vec) -> String { + if cfg!(debug_assertions) { + String::from_utf8(bytes).unwrap() + } else { + String::from_utf8_unchecked(bytes) + } + } + pub use alloc_crate::string::String; + pub unsafe fn invalid_enum_discriminant() -> T { + if cfg!(debug_assertions) { + panic!("invalid enum discriminant") + } else { + unsafe { core::hint::unreachable_unchecked() } + } + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr, layout); + } + pub fn as_i32(t: T) -> i32 { + t.as_i32() + } + pub trait AsI32 { + fn as_i32(self) -> i32; + } + impl<'a, T: Copy + AsI32> AsI32 for &'a T { + fn as_i32(self) -> i32 { + (*self).as_i32() + } + } + impl AsI32 for i32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + impl AsI32 for u32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + impl AsI32 for i16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + impl AsI32 for u16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + impl AsI32 for i8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + impl AsI32 for u8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + impl AsI32 for char { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + impl AsI32 for usize { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + pub unsafe fn bool_lift(val: u8) -> bool { + if cfg!(debug_assertions) { + match val { + 0 => false, + 1 => true, + _ => panic!("invalid bool discriminant"), + } + } else { + val != 0 + } + } + pub use alloc_crate::alloc; + extern crate alloc as alloc_crate; +} +/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as +/// the root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] +macro_rules! __export_loro_world_impl { + ($ty:ident) => { + self::export!($ty with_types_in self); + }; + ($ty:ident with_types_in $($path_to_types_root:tt)*) => { + $($path_to_types_root)*:: + exports::loro::crdt::loro_doc::__export_loro_crdt_loro_doc_0_1_0_cabi!($ty + with_types_in $($path_to_types_root)*:: exports::loro::crdt::loro_doc); + $($path_to_types_root)*:: + exports::loro::crdt::loro_text::__export_loro_crdt_loro_text_0_1_0_cabi!($ty + with_types_in $($path_to_types_root)*:: exports::loro::crdt::loro_text); + $($path_to_types_root)*:: + exports::loro::crdt::loro_map::__export_loro_crdt_loro_map_0_1_0_cabi!($ty + with_types_in $($path_to_types_root)*:: exports::loro::crdt::loro_map); + $($path_to_types_root)*:: + exports::loro::crdt::loro_list::__export_loro_crdt_loro_list_0_1_0_cabi!($ty + with_types_in $($path_to_types_root)*:: exports::loro::crdt::loro_list); + }; +} +#[doc(inline)] +pub(crate) use __export_loro_world_impl as export; +#[cfg(target_arch = "wasm32")] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:loro:crdt@0.1.0:loro-world:encoded world" +)] +#[doc(hidden)] +#[allow(clippy::octal_escapes)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1917] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xfc\x0d\x01A\x02\x01\ +A\x0c\x01B%\x04\0\x03doc\x03\x01\x01r\x01\x02idw\x04\0\x0btext-handle\x03\0\x01\x01\ +r\x01\x02idw\x04\0\x0amap-handle\x03\0\x03\x01r\x01\x02idw\x04\0\x0blist-handle\x03\ +\0\x05\x01i\0\x01@\0\0\x07\x04\0\x10[constructor]doc\x01\x08\x01@\x01\x07peer-id\ +w\0\x07\x04\0\x1c[static]doc.new-with-peer-id\x01\x09\x01h\0\x01@\x01\x04self\x0a\ +\0w\x04\0\x13[method]doc.peer-id\x01\x0b\x01@\x02\x04self\x0a\x04names\0\x02\x04\ +\0\x14[method]doc.get-text\x01\x0c\x01@\x02\x04self\x0a\x04names\0\x04\x04\0\x13\ +[method]doc.get-map\x01\x0d\x01@\x02\x04self\x0a\x04names\0\x06\x04\0\x14[method\ +]doc.get-list\x01\x0e\x01ks\x01@\x02\x04self\x0a\x07message\x0f\x01\0\x04\0\x12[\ +method]doc.commit\x01\x10\x01p}\x01@\x01\x04self\x0a\0\x11\x04\0\x1a[method]doc.\ +export-updates\x01\x12\x04\0\x1b[method]doc.export-snapshot\x01\x12\x01j\0\x01s\x01\ +@\x02\x04self\x0a\x05bytes\x11\0\x13\x04\0\x1a[method]doc.import-updates\x01\x14\ +\x01@\x01\x04self\x0a\0s\x04\0\x13[method]doc.to-json\x01\x15\x01@\x01\x04self\x0a\ +\0\x7f\x04\0\x14[method]doc.is-empty\x01\x16\x01@\x01\x04self\x0a\0\x07\x04\0\x10\ +[method]doc.fork\x01\x17\x04\0\x18loro:crdt/loro-doc@0.1.0\x05\0\x02\x03\0\0\x03\ +doc\x02\x03\0\0\x0btext-handle\x01B\x0f\x02\x03\x02\x01\x01\x04\0\x03doc\x03\0\0\ +\x02\x03\x02\x01\x02\x04\0\x0btext-handle\x03\0\x02\x01h\x01\x01j\0\x01s\x01@\x04\ +\x03doc\x04\x06handle\x03\x03posy\x04texts\0\x05\x04\0\x06insert\x01\x06\x01@\x04\ +\x03doc\x04\x06handle\x03\x03posy\x03leny\0\x05\x04\0\x06delete\x01\x07\x01@\x02\ +\x03doc\x04\x06handle\x03\0s\x04\0\x09to-string\x01\x08\x01@\x02\x03doc\x04\x06h\ +andle\x03\0y\x04\0\x08len-utf8\x01\x09\x04\0\x0blen-unicode\x01\x09\x04\0\x19lor\ +o:crdt/loro-text@0.1.0\x05\x03\x02\x03\0\0\x0amap-handle\x01B\x19\x02\x03\x02\x01\ +\x01\x04\0\x03doc\x03\0\0\x02\x03\x02\x01\x04\x04\0\x0amap-handle\x03\0\x02\x01h\ +\x01\x01j\0\x01s\x01@\x04\x03doc\x04\x06handle\x03\x03keys\x05values\0\x05\x04\0\ +\x0dinsert-string\x01\x06\x01@\x04\x03doc\x04\x06handle\x03\x03keys\x05valueu\0\x05\ +\x04\0\x0dinsert-number\x01\x07\x01@\x04\x03doc\x04\x06handle\x03\x03keys\x05val\ +ue\x7f\0\x05\x04\0\x0binsert-bool\x01\x08\x01@\x03\x03doc\x04\x06handle\x03\x03k\ +eys\0\x05\x04\0\x0binsert-null\x01\x09\x01ks\x01@\x03\x03doc\x04\x06handle\x03\x03\ +keys\0\x0a\x04\0\x03get\x01\x0b\x04\0\x06delete\x01\x09\x01@\x03\x03doc\x04\x06h\ +andle\x03\x03keys\0\x7f\x04\0\x08contains\x01\x0c\x01ps\x01@\x02\x03doc\x04\x06h\ +andle\x03\0\x0d\x04\0\x04keys\x01\x0e\x01@\x02\x03doc\x04\x06handle\x03\0y\x04\0\ +\x03len\x01\x0f\x04\0\x18loro:crdt/loro-map@0.1.0\x05\x05\x02\x03\0\0\x0blist-ha\ +ndle\x01B\x19\x02\x03\x02\x01\x01\x04\0\x03doc\x03\0\0\x02\x03\x02\x01\x06\x04\0\ +\x0blist-handle\x03\0\x02\x01h\x01\x01j\0\x01s\x01@\x04\x03doc\x04\x06handle\x03\ +\x03posy\x05values\0\x05\x04\0\x0dinsert-string\x01\x06\x01@\x04\x03doc\x04\x06h\ +andle\x03\x03posy\x05valueu\0\x05\x04\0\x0dinsert-number\x01\x07\x01@\x04\x03doc\ +\x04\x06handle\x03\x03posy\x05value\x7f\0\x05\x04\0\x0binsert-bool\x01\x08\x01@\x03\ +\x03doc\x04\x06handle\x03\x03posy\0\x05\x04\0\x0binsert-null\x01\x09\x01@\x03\x03\ +doc\x04\x06handle\x03\x05values\0\x05\x04\0\x0bpush-string\x01\x0a\x01@\x03\x03d\ +oc\x04\x06handle\x03\x05valueu\0\x05\x04\0\x0bpush-number\x01\x0b\x01ks\x01@\x03\ +\x03doc\x04\x06handle\x03\x05indexy\0\x0c\x04\0\x03get\x01\x0d\x01@\x03\x03doc\x04\ +\x06handle\x03\x05indexy\0\x05\x04\0\x06delete\x01\x0e\x01@\x02\x03doc\x04\x06ha\ +ndle\x03\0y\x04\0\x03len\x01\x0f\x04\0\x19loro:crdt/loro-list@0.1.0\x05\x07\x04\0\ +\x1aloro:crdt/loro-world@0.1.0\x04\0\x0b\x10\x01\0\x0aloro-world\x03\0\0\0G\x09p\ +roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\ +\x060.41.0"; +#[inline(never)] +#[doc(hidden)] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/crates/loro-wit/src/lib.rs b/crates/loro-wit/src/lib.rs new file mode 100644 index 000000000..ee8c80d92 --- /dev/null +++ b/crates/loro-wit/src/lib.rs @@ -0,0 +1,455 @@ +//! WebAssembly Component Model (WIT) bindings for Loro CRDT +//! +//! This crate provides WIT-based bindings for the Loro CRDT library, +//! enabling use with the WebAssembly Component Model and tools like +//! jco (JavaScript) and wasmtime. + +#[allow(warnings)] +mod bindings; + +use std::cell::RefCell; +use std::collections::HashMap; + +use bindings::exports::loro::crdt::loro_doc::{ + Doc as WitDoc, DocBorrow, GuestDoc, ListHandle, MapHandle, TextHandle, +}; +use loro::{ + ExportMode, LoroDoc, LoroList as InnerLoroList, LoroMap as InnerLoroMap, + LoroText as InnerLoroText, LoroValue, ValueOrContainer, +}; + +/// Global storage for container handles +/// This maps handle IDs to their container names, allowing us to +/// reconstruct containers from handles +struct HandleStorage { + next_id: u64, + text_names: HashMap, + map_names: HashMap, + list_names: HashMap, +} + +impl HandleStorage { + fn new() -> Self { + Self { + next_id: 1, + text_names: HashMap::new(), + map_names: HashMap::new(), + list_names: HashMap::new(), + } + } + + fn register_text(&mut self, name: String) -> u64 { + let id = self.next_id; + self.next_id += 1; + self.text_names.insert(id, name); + id + } + + fn register_map(&mut self, name: String) -> u64 { + let id = self.next_id; + self.next_id += 1; + self.map_names.insert(id, name); + id + } + + fn register_list(&mut self, name: String) -> u64 { + let id = self.next_id; + self.next_id += 1; + self.list_names.insert(id, name); + id + } + + fn get_text_name(&self, id: u64) -> Option { + self.text_names.get(&id).cloned() + } + + fn get_map_name(&self, id: u64) -> Option { + self.map_names.get(&id).cloned() + } + + fn get_list_name(&self, id: u64) -> Option { + self.list_names.get(&id).cloned() + } +} + +thread_local! { + static HANDLE_STORAGE: RefCell = RefCell::new(HandleStorage::new()); +} + +/// The Loro document resource implementation +pub struct Doc { + inner: LoroDoc, +} + +impl GuestDoc for Doc { + fn new() -> Self { + Self { + inner: LoroDoc::new(), + } + } + + fn new_with_peer_id(peer_id: u64) -> WitDoc { + let doc = LoroDoc::new(); + doc.set_peer_id(peer_id).expect("Failed to set peer ID"); + WitDoc::new(Self { inner: doc }) + } + + fn peer_id(&self) -> u64 { + self.inner.peer_id() + } + + fn get_text(&self, name: String) -> TextHandle { + // Get or create the text container to ensure it exists + let cloned_name = name.clone(); + let _ = self.inner.get_text(cloned_name); + let id = HANDLE_STORAGE.with(|storage| storage.borrow_mut().register_text(name)); + TextHandle { id } + } + + fn get_map(&self, name: String) -> MapHandle { + let cloned_name = name.clone(); + let _ = self.inner.get_map(cloned_name); + let id = HANDLE_STORAGE.with(|storage| storage.borrow_mut().register_map(name)); + MapHandle { id } + } + + fn get_list(&self, name: String) -> ListHandle { + let cloned_name = name.clone(); + let _ = self.inner.get_list(cloned_name); + let id = HANDLE_STORAGE.with(|storage| storage.borrow_mut().register_list(name)); + ListHandle { id } + } + + fn commit(&self, message: Option) { + if let Some(msg) = message { + self.inner.commit_with( + loro::CommitOptions::default().commit_msg(&msg), + ); + } else { + self.inner.commit(); + } + } + + fn export_updates(&self) -> Vec { + self.inner + .export(ExportMode::all_updates()) + .unwrap_or_default() + } + + fn export_snapshot(&self) -> Vec { + self.inner.export(ExportMode::Snapshot).unwrap_or_default() + } + + fn import_updates(&self, bytes: Vec) -> Result<(), String> { + self.inner + .import(&bytes) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn to_json(&self) -> String { + serde_json::to_string(&self.inner.get_deep_value()).unwrap_or_else(|_| "{}".to_string()) + } + + fn is_empty(&self) -> bool { + // Check if the document has no operations by checking export size + self.inner.export(ExportMode::all_updates()) + .map(|v| v.is_empty()) + .unwrap_or(true) + } + + fn fork(&self) -> WitDoc { + WitDoc::new(Self { + inner: self.inner.fork(), + }) + } +} + +// Helper functions to get containers from handles +fn get_text_from_handle(doc: &Doc, handle: &TextHandle) -> Option { + HANDLE_STORAGE.with(|storage| { + storage + .borrow() + .get_text_name(handle.id) + .map(|name| doc.inner.get_text(name)) + }) +} + +fn get_map_from_handle(doc: &Doc, handle: &MapHandle) -> Option { + HANDLE_STORAGE.with(|storage| { + storage + .borrow() + .get_map_name(handle.id) + .map(|name| doc.inner.get_map(name)) + }) +} + +fn get_list_from_handle(doc: &Doc, handle: &ListHandle) -> Option { + HANDLE_STORAGE.with(|storage| { + storage + .borrow() + .get_list_name(handle.id) + .map(|name| doc.inner.get_list(name)) + }) +} + +/// Convert ValueOrContainer to JSON string +fn value_or_container_to_json(v: ValueOrContainer) -> String { + let loro_value = v.get_deep_value(); + serde_json::to_string(&loro_value).unwrap_or_default() +} + +/// Main component struct that implements all interfaces +struct LoroComponent; + +impl bindings::exports::loro::crdt::loro_doc::Guest for LoroComponent { + type Doc = Doc; +} + +impl bindings::exports::loro::crdt::loro_text::Guest for LoroComponent { + fn insert( + doc: DocBorrow<'_>, + handle: TextHandle, + pos: u32, + text: String, + ) -> Result<(), String> { + let doc = doc.get::(); + let text_container = + get_text_from_handle(doc, &handle).ok_or_else(|| "Invalid text handle".to_string())?; + text_container + .insert(pos as usize, &text) + .map_err(|e| e.to_string()) + } + + fn delete( + doc: DocBorrow<'_>, + handle: TextHandle, + pos: u32, + len: u32, + ) -> Result<(), String> { + let doc = doc.get::(); + let text_container = + get_text_from_handle(doc, &handle).ok_or_else(|| "Invalid text handle".to_string())?; + text_container + .delete(pos as usize, len as usize) + .map_err(|e| e.to_string()) + } + + fn to_string(doc: DocBorrow<'_>, handle: TextHandle) -> String { + let doc = doc.get::(); + get_text_from_handle(doc, &handle) + .map(|t| t.to_string()) + .unwrap_or_default() + } + + fn len_utf8(doc: DocBorrow<'_>, handle: TextHandle) -> u32 { + let doc = doc.get::(); + get_text_from_handle(doc, &handle) + .map(|t| t.len_utf8() as u32) + .unwrap_or(0) + } + + fn len_unicode(doc: DocBorrow<'_>, handle: TextHandle) -> u32 { + let doc = doc.get::(); + get_text_from_handle(doc, &handle) + .map(|t| t.len_unicode() as u32) + .unwrap_or(0) + } +} + +impl bindings::exports::loro::crdt::loro_map::Guest for LoroComponent { + fn insert_string( + doc: DocBorrow<'_>, + handle: MapHandle, + key: String, + value: String, + ) -> Result<(), String> { + let doc = doc.get::(); + let map_container = + get_map_from_handle(doc, &handle).ok_or_else(|| "Invalid map handle".to_string())?; + map_container + .insert(&key, value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn insert_number( + doc: DocBorrow<'_>, + handle: MapHandle, + key: String, + value: f64, + ) -> Result<(), String> { + let doc = doc.get::(); + let map_container = + get_map_from_handle(doc, &handle).ok_or_else(|| "Invalid map handle".to_string())?; + map_container + .insert(&key, value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn insert_bool( + doc: DocBorrow<'_>, + handle: MapHandle, + key: String, + value: bool, + ) -> Result<(), String> { + let doc = doc.get::(); + let map_container = + get_map_from_handle(doc, &handle).ok_or_else(|| "Invalid map handle".to_string())?; + map_container + .insert(&key, value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn insert_null(doc: DocBorrow<'_>, handle: MapHandle, key: String) -> Result<(), String> { + let doc = doc.get::(); + let map_container = + get_map_from_handle(doc, &handle).ok_or_else(|| "Invalid map handle".to_string())?; + map_container + .insert(&key, LoroValue::Null) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn get(doc: DocBorrow<'_>, handle: MapHandle, key: String) -> Option { + let doc = doc.get::(); + let map_container = get_map_from_handle(doc, &handle)?; + map_container + .get(&key) + .map(value_or_container_to_json) + } + + fn delete(doc: DocBorrow<'_>, handle: MapHandle, key: String) -> Result<(), String> { + let doc = doc.get::(); + let map_container = + get_map_from_handle(doc, &handle).ok_or_else(|| "Invalid map handle".to_string())?; + map_container.delete(&key).map_err(|e| e.to_string()) + } + + fn contains(doc: DocBorrow<'_>, handle: MapHandle, key: String) -> bool { + let doc = doc.get::(); + get_map_from_handle(doc, &handle) + .and_then(|m| m.get(&key)) + .is_some() + } + + fn keys(doc: DocBorrow<'_>, handle: MapHandle) -> Vec { + let doc = doc.get::(); + get_map_from_handle(doc, &handle) + .map(|m| m.keys().map(|s| s.to_string()).collect()) + .unwrap_or_default() + } + + fn len(doc: DocBorrow<'_>, handle: MapHandle) -> u32 { + let doc = doc.get::(); + get_map_from_handle(doc, &handle) + .map(|m| m.len() as u32) + .unwrap_or(0) + } +} + +impl bindings::exports::loro::crdt::loro_list::Guest for LoroComponent { + fn insert_string( + doc: DocBorrow<'_>, + handle: ListHandle, + pos: u32, + value: String, + ) -> Result<(), String> { + let doc = doc.get::(); + let list_container = + get_list_from_handle(doc, &handle).ok_or_else(|| "Invalid list handle".to_string())?; + list_container + .insert(pos as usize, value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn insert_number( + doc: DocBorrow<'_>, + handle: ListHandle, + pos: u32, + value: f64, + ) -> Result<(), String> { + let doc = doc.get::(); + let list_container = + get_list_from_handle(doc, &handle).ok_or_else(|| "Invalid list handle".to_string())?; + list_container + .insert(pos as usize, value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn insert_bool( + doc: DocBorrow<'_>, + handle: ListHandle, + pos: u32, + value: bool, + ) -> Result<(), String> { + let doc = doc.get::(); + let list_container = + get_list_from_handle(doc, &handle).ok_or_else(|| "Invalid list handle".to_string())?; + list_container + .insert(pos as usize, value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn insert_null(doc: DocBorrow<'_>, handle: ListHandle, pos: u32) -> Result<(), String> { + let doc = doc.get::(); + let list_container = + get_list_from_handle(doc, &handle).ok_or_else(|| "Invalid list handle".to_string())?; + list_container + .insert(pos as usize, LoroValue::Null) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn push_string(doc: DocBorrow<'_>, handle: ListHandle, value: String) -> Result<(), String> { + let doc = doc.get::(); + let list_container = + get_list_from_handle(doc, &handle).ok_or_else(|| "Invalid list handle".to_string())?; + list_container + .push(value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn push_number(doc: DocBorrow<'_>, handle: ListHandle, value: f64) -> Result<(), String> { + let doc = doc.get::(); + let list_container = + get_list_from_handle(doc, &handle).ok_or_else(|| "Invalid list handle".to_string())?; + list_container + .push(value) + .map(|_| ()) + .map_err(|e| e.to_string()) + } + + fn get(doc: DocBorrow<'_>, handle: ListHandle, index: u32) -> Option { + let doc = doc.get::(); + let list_container = get_list_from_handle(doc, &handle)?; + list_container + .get(index as usize) + .map(value_or_container_to_json) + } + + fn delete(doc: DocBorrow<'_>, handle: ListHandle, index: u32) -> Result<(), String> { + let doc = doc.get::(); + let list_container = + get_list_from_handle(doc, &handle).ok_or_else(|| "Invalid list handle".to_string())?; + list_container + .delete(index as usize, 1) + .map_err(|e| e.to_string()) + } + + fn len(doc: DocBorrow<'_>, handle: ListHandle) -> u32 { + let doc = doc.get::(); + get_list_from_handle(doc, &handle) + .map(|l| l.len() as u32) + .unwrap_or(0) + } +} + +// Export the component +bindings::export!(LoroComponent with_types_in bindings); diff --git a/crates/loro-wit/wit/loro.wit b/crates/loro-wit/wit/loro.wit new file mode 100644 index 000000000..9bd2e02b3 --- /dev/null +++ b/crates/loro-wit/wit/loro.wit @@ -0,0 +1,153 @@ +package loro:crdt@0.1.0; + +/// Loro CRDT interface for collaborative data types +world loro-world { + export loro-doc; + export loro-text; + export loro-map; + export loro-list; +} + +/// The main document interface for Loro CRDT +interface loro-doc { + /// A handle to a Loro document + resource doc { + /// Create a new Loro document + constructor(); + + /// Create a new Loro document with a specific peer ID + new-with-peer-id: static func(peer-id: u64) -> doc; + + /// Get the peer ID of this document + peer-id: func() -> u64; + + /// Get a text container by name + get-text: func(name: string) -> text-handle; + + /// Get a map container by name + get-map: func(name: string) -> map-handle; + + /// Get a list container by name + get-list: func(name: string) -> list-handle; + + /// Commit pending changes with an optional message + commit: func(message: option); + + /// Export all updates as bytes + export-updates: func() -> list; + + /// Export a snapshot as bytes + export-snapshot: func() -> list; + + /// Import updates from bytes + import-updates: func(bytes: list) -> result<_, string>; + + /// Get the JSON representation of the document + to-json: func() -> string; + + /// Check if the document is empty + is-empty: func() -> bool; + + /// Fork the document to create an independent copy + fork: func() -> doc; + } + + /// Handle to a text container + record text-handle { + id: u64, + } + + /// Handle to a map container + record map-handle { + id: u64, + } + + /// Handle to a list container + record list-handle { + id: u64, + } +} + +/// Text CRDT operations +interface loro-text { + use loro-doc.{doc, text-handle}; + + /// Insert text at a position + insert: func(doc: borrow, handle: text-handle, pos: u32, text: string) -> result<_, string>; + + /// Delete text at a range + delete: func(doc: borrow, handle: text-handle, pos: u32, len: u32) -> result<_, string>; + + /// Get the text content as a string + to-string: func(doc: borrow, handle: text-handle) -> string; + + /// Get the length of the text in UTF-8 bytes + len-utf8: func(doc: borrow, handle: text-handle) -> u32; + + /// Get the length of the text in Unicode characters + len-unicode: func(doc: borrow, handle: text-handle) -> u32; +} + +/// Map CRDT operations +interface loro-map { + use loro-doc.{doc, map-handle}; + + /// Insert or update a string value + insert-string: func(doc: borrow, handle: map-handle, key: string, value: string) -> result<_, string>; + + /// Insert or update a number value + insert-number: func(doc: borrow, handle: map-handle, key: string, value: f64) -> result<_, string>; + + /// Insert or update a boolean value + insert-bool: func(doc: borrow, handle: map-handle, key: string, value: bool) -> result<_, string>; + + /// Insert a null value + insert-null: func(doc: borrow, handle: map-handle, key: string) -> result<_, string>; + + /// Get a value by key (returns JSON string) + get: func(doc: borrow, handle: map-handle, key: string) -> option; + + /// Delete a key + delete: func(doc: borrow, handle: map-handle, key: string) -> result<_, string>; + + /// Check if a key exists + contains: func(doc: borrow, handle: map-handle, key: string) -> bool; + + /// Get all keys + keys: func(doc: borrow, handle: map-handle) -> list; + + /// Get the number of entries + len: func(doc: borrow, handle: map-handle) -> u32; +} + +/// List CRDT operations +interface loro-list { + use loro-doc.{doc, list-handle}; + + /// Insert a string value at position + insert-string: func(doc: borrow, handle: list-handle, pos: u32, value: string) -> result<_, string>; + + /// Insert a number value at position + insert-number: func(doc: borrow, handle: list-handle, pos: u32, value: f64) -> result<_, string>; + + /// Insert a boolean value at position + insert-bool: func(doc: borrow, handle: list-handle, pos: u32, value: bool) -> result<_, string>; + + /// Insert a null value at position + insert-null: func(doc: borrow, handle: list-handle, pos: u32) -> result<_, string>; + + /// Push a string value to the end + push-string: func(doc: borrow, handle: list-handle, value: string) -> result<_, string>; + + /// Push a number value to the end + push-number: func(doc: borrow, handle: list-handle, value: f64) -> result<_, string>; + + /// Get a value at index (returns JSON string) + get: func(doc: borrow, handle: list-handle, index: u32) -> option; + + /// Delete an element at index + delete: func(doc: borrow, handle: list-handle, index: u32) -> result<_, string>; + + /// Get the length of the list + len: func(doc: borrow, handle: list-handle) -> u32; +} diff --git a/examples/wit-demo/README.md b/examples/wit-demo/README.md new file mode 100644 index 000000000..032b8f232 --- /dev/null +++ b/examples/wit-demo/README.md @@ -0,0 +1,128 @@ +# Loro CRDT WebAssembly Component Demo + +This demo showcases how to use Loro CRDT as a WebAssembly Component using the [WebAssembly Interface Types (WIT)](https://component-model.bytecodealliance.org/design/wit.html) specification. + +## Overview + +The `loro-wit` crate provides WebAssembly Component Model bindings for the Loro CRDT library. This enables using Loro from any language that supports the WebAssembly Component Model, including: + +- JavaScript/TypeScript (via [jco](https://github.com/bytecodealliance/jco)) +- Rust (via [wasmtime](https://wasmtime.dev/)) +- Python (via [wasmtime-py](https://github.com/bytecodealliance/wasmtime-py)) +- Go, C/C++, and more + +## WIT Interface + +The WIT interface defines the following interfaces: + +- **loro-doc**: Main document interface with `Doc` resource + - Create documents, get containers, commit changes + - Export/import updates for sync + - Fork documents + +- **loro-text**: Text CRDT operations + - Insert, delete, get content + +- **loro-map**: Map CRDT operations + - Insert string/number/boolean values + - Get, delete, check keys + +- **loro-list**: List CRDT operations + - Insert at position, push, get, delete + +## Building the Component + +First, build the Loro WebAssembly Component: + +```bash +# From the repository root +cargo component build --release -p loro-wit +``` + +This creates `target/wasm32-wasip1/release/loro_wit.wasm`. + +## Running the Demos + +### JavaScript Demo (jco) + +The jco demo transpiles the WebAssembly Component to JavaScript for use in Node.js or browsers. + +```bash +cd examples/wit-demo/jco + +# Install dependencies +npm install + +# Build (transpile the component) +npm run build + +# Run the demo +npm run demo +``` + +### Rust Demo (wasmtime) + +The wasmtime demo shows how to host the component from a Rust application. + +```bash +cd examples/wit-demo/wasmtime-host + +# Run the demo (it will build and execute) +cargo run --release +``` + +## Example Usage + +### JavaScript (after jco transpilation) + +```javascript +import { loroDoc, loroText, loroMap } from './gen/loro.js'; + +// Create a document +const doc = new loroDoc.Doc(); + +// Work with text +const text = doc.getText('content'); +loroText.insert(doc, text, 0, 'Hello, World!'); +console.log(loroText.toString(doc, text)); + +// Work with map +const map = doc.getMap('data'); +loroMap.insertString(doc, map, 'key', 'value'); + +// Commit and export +doc.commit('My changes'); +const updates = doc.exportUpdates(); + +// Sync to another document +const doc2 = new loroDoc.Doc(); +doc2.importUpdates(updates); +``` + +### Rust (with wasmtime) + +```rust +use wasmtime::component::{Component, Linker}; +use wasmtime::{Engine, Store}; + +// Load and instantiate the component +let engine = Engine::new(&config)?; +let component = Component::from_file(&engine, "loro_wit.wasm")?; +let (loro, _) = LoroWorld::instantiate(&mut store, &component, &linker)?; + +// Use the interfaces +let doc = loro.loro_crdt_loro_doc().doc().call_constructor(&mut store)?; +let text = loro.loro_crdt_loro_doc().doc().call_get_text(&mut store, doc, "content")?; +loro.loro_crdt_loro_text().call_insert(&mut store, doc, text, 0, "Hello!")?; +``` + +## WIT Interface Definition + +See `crates/loro-wit/wit/loro.wit` for the full interface definition. + +## Requirements + +- Rust 1.85+ with `wasm32-wasip1` target +- [cargo-component](https://github.com/bytecodealliance/cargo-component) +- Node.js 18+ (for jco demo) +- npm or pnpm diff --git a/examples/wit-demo/jco/.gitignore b/examples/wit-demo/jco/.gitignore new file mode 100644 index 000000000..4059f2fed --- /dev/null +++ b/examples/wit-demo/jco/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +gen/ diff --git a/examples/wit-demo/jco/demo.mjs b/examples/wit-demo/jco/demo.mjs new file mode 100644 index 000000000..8d1435a1b --- /dev/null +++ b/examples/wit-demo/jco/demo.mjs @@ -0,0 +1,81 @@ +/** + * Loro CRDT WebAssembly Component Demo with jco + * + * This demo shows how to use the Loro CRDT library compiled as a + * WebAssembly Component, transpiled to JavaScript using jco. + */ + +// Import the transpiled component +import { loroDoc, loroText, loroMap, loroList } from './gen/loro.js'; + +console.log('=== Loro CRDT WebAssembly Component Demo ===\n'); + +// Create a new document +console.log('1. Creating a new Loro document...'); +const doc = new loroDoc.Doc(); +console.log(` Document created with peer ID: ${doc.peerId()}`); +console.log(` Is empty: ${doc.isEmpty()}\n`); + +// Working with Text +console.log('2. Working with Text container...'); +const textHandle = doc.getText('my-text'); +loroText.insert(doc, textHandle, 0, 'Hello, '); +loroText.insert(doc, textHandle, 7, 'World!'); +console.log(` Text content: "${loroText.toString(doc, textHandle)}"`); +console.log(` Length (UTF-8): ${loroText.lenUtf8(doc, textHandle)}`); +console.log(` Length (Unicode): ${loroText.lenUnicode(doc, textHandle)}\n`); + +// Working with Map +console.log('3. Working with Map container...'); +const mapHandle = doc.getMap('my-map'); +loroMap.insertString(doc, mapHandle, 'name', 'Loro'); +loroMap.insertNumber(doc, mapHandle, 'version', 1.10); +loroMap.insertBool(doc, mapHandle, 'isAwesome', true); +console.log(` Keys: ${JSON.stringify(loroMap.keys(doc, mapHandle))}`); +console.log(` Name: ${loroMap.get(doc, mapHandle, 'name')}`); +console.log(` Version: ${loroMap.get(doc, mapHandle, 'version')}`); +console.log(` Map length: ${loroMap.len(doc, mapHandle)}\n`); + +// Working with List +console.log('4. Working with List container...'); +const listHandle = doc.getList('my-list'); +loroList.pushString(doc, listHandle, 'first'); +loroList.pushNumber(doc, listHandle, 42); +loroList.insertString(doc, listHandle, 0, 'zeroth'); +console.log(` List length: ${loroList.len(doc, listHandle)}`); +console.log(` Item 0: ${loroList.get(doc, listHandle, 0)}`); +console.log(` Item 1: ${loroList.get(doc, listHandle, 1)}`); +console.log(` Item 2: ${loroList.get(doc, listHandle, 2)}\n`); + +// Commit changes +console.log('5. Committing changes...'); +doc.commit('Initial data setup'); +console.log(' Changes committed!\n'); + +// Export and show document state +console.log('6. Document state:'); +const jsonState = doc.toJson(); +console.log(` JSON: ${jsonState}\n`); + +// Export updates +console.log('7. Exporting updates...'); +const updates = doc.exportUpdates(); +console.log(` Updates size: ${updates.length} bytes\n`); + +// Create a new document and import updates +console.log('8. Syncing with another document...'); +const doc2 = new loroDoc.Doc(); +console.log(` Doc2 peer ID: ${doc2.peerId()}`); +doc2.importUpdates(updates); +console.log(` Doc2 after import: ${doc2.toJson()}\n`); + +// Fork the document +console.log('9. Forking document...'); +const forked = doc.fork(); +console.log(` Forked doc peer ID: ${forked.peerId()}`); +const forkedText = forked.getText('my-text'); +loroText.insert(forked, forkedText, 0, '[Forked] '); +forked.commit('Forked edit'); +console.log(` Forked text: "${loroText.toString(forked, forkedText)}"\n`); + +console.log('=== Demo Complete ==='); diff --git a/examples/wit-demo/jco/package-lock.json b/examples/wit-demo/jco/package-lock.json new file mode 100644 index 000000000..27e1eaccc --- /dev/null +++ b/examples/wit-demo/jco/package-lock.json @@ -0,0 +1,910 @@ +{ + "name": "loro-wit-jco-demo", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "loro-wit-jco-demo", + "version": "1.0.0", + "dependencies": { + "@bytecodealliance/jco": "^1.7.0", + "@bytecodealliance/preview2-shim": "^0.17.0" + } + }, + "node_modules/@bytecodealliance/componentize-js": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@bytecodealliance/componentize-js/-/componentize-js-0.19.3.tgz", + "integrity": "sha512-ju7Y4WeF0B9uMkSPHJgmT6ouEfSwbe9M1uR/YOnYZjBpxJjH9qzxIkJg/kf8NycVDyFJ2/lscmJ1E1uPiDQVRQ==", + "workspaces": [ + "." + ], + "dependencies": { + "@bytecodealliance/jco": "^1.15.1", + "@bytecodealliance/wizer": "^10.0.0", + "es-module-lexer": "^1.6.0", + "oxc-parser": "^0.76.0" + }, + "bin": { + "componentize-js": "src/cli.js" + } + }, + "node_modules/@bytecodealliance/jco": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco/-/jco-1.15.4.tgz", + "integrity": "sha512-Lu5ZVPD+ethKrOCbfVe7zHwOH8JmhU1sDXBn/7WN4Zf/KcJc34YQmUQCjxrN5n4h9Q2ep3dcK8Gb7DeV1e2i7w==", + "license": "(Apache-2.0 WITH LLVM-exception)", + "dependencies": { + "@bytecodealliance/componentize-js": "^0.19.3", + "@bytecodealliance/preview2-shim": "^0.17.3", + "binaryen": "^123.0.0", + "commander": "^14", + "mkdirp": "^3", + "ora": "^8", + "terser": "^5" + }, + "bin": { + "jco": "src/jco.js" + } + }, + "node_modules/@bytecodealliance/preview2-shim": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.5.tgz", + "integrity": "sha512-F4WYVC6aHOiOXSsG3WDGFALrkpb952+9/EIX119qIzDtYgE5tvbOnKeBb0Y+NMzGEsu3334GdHIRXQ6wibY0MA==", + "license": "(Apache-2.0 WITH LLVM-exception)" + }, + "node_modules/@bytecodealliance/wizer": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer/-/wizer-10.0.0.tgz", + "integrity": "sha512-ziWmovyu1jQl9TsKlfC2bwuUZwxVPFHlX4fOqTzxhgS76jITIo45nzODEwPgU+jjmOr8F3YX2V2wAChC5NKujg==", + "license": "Apache-2.0", + "bin": { + "wizer": "wizer.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@bytecodealliance/wizer-darwin-arm64": "10.0.0", + "@bytecodealliance/wizer-darwin-x64": "10.0.0", + "@bytecodealliance/wizer-linux-arm64": "10.0.0", + "@bytecodealliance/wizer-linux-s390x": "10.0.0", + "@bytecodealliance/wizer-linux-x64": "10.0.0", + "@bytecodealliance/wizer-win32-x64": "10.0.0" + } + }, + "node_modules/@bytecodealliance/wizer-darwin-arm64": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-arm64/-/wizer-darwin-arm64-10.0.0.tgz", + "integrity": "sha512-dhZTWel+xccGTKSJtI9A7oM4yyP20FWflsT+AoqkOqkCY7kCNrj4tmMtZ6GXZFRDkrPY5+EnOh62sfShEibAMA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "wizer-darwin-arm64": "wizer" + } + }, + "node_modules/@bytecodealliance/wizer-darwin-x64": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-x64/-/wizer-darwin-x64-10.0.0.tgz", + "integrity": "sha512-r/LUIZw6Q3Hf4htd46mD+EBxfwjBkxVIrTM1r+B2pTCddoBYQnKVdVsI4UFyy7NoBxzEg8F8BwmTNoSLmFRjpw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "wizer-darwin-x64": "wizer" + } + }, + "node_modules/@bytecodealliance/wizer-linux-arm64": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-arm64/-/wizer-linux-arm64-10.0.0.tgz", + "integrity": "sha512-pGSfFWXzeTqHm6z1PtVaEn+7Fm3QGC8YnHrzBV4sQDVS3N1NwmuHZAc8kslmlFPNdu61ycEvdOsSgCny8JPQvg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "wizer-linux-arm64": "wizer" + } + }, + "node_modules/@bytecodealliance/wizer-linux-s390x": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-s390x/-/wizer-linux-s390x-10.0.0.tgz", + "integrity": "sha512-O8vHxRTAdb1lUnVXMIMTcp/9q4pq1D4iIKigJCipg2JN15taV9uFAWh0fO88wylXwuSlO7dOE1AwQl54fMKXQg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "wizer-linux-s390x": "wizer" + } + }, + "node_modules/@bytecodealliance/wizer-linux-x64": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-x64/-/wizer-linux-x64-10.0.0.tgz", + "integrity": "sha512-fJtM1sy43FBMnp+xpapFX6U1YdTBKA/1T4CYfG/qeE8jn0SXk2EuiYoY/EnC2uyNy9hjTrvfdYO5n4MXW0EIdQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "wizer-linux-x64": "wizer" + } + }, + "node_modules/@bytecodealliance/wizer-win32-x64": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-win32-x64/-/wizer-win32-x64-10.0.0.tgz", + "integrity": "sha512-55BPLfGT7iT7gH5M69NpTM16QknJZ7OxJ0z73VOEoeGA9CT8QPKMRzFKsPIvLs+W8G28fdudFA94nElrdkp3Kg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "wizer-win32-x64": "wizer" + } + }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.76.0.tgz", + "integrity": "sha512-1XJW/16CDmF5bHE7LAyPPmEEVnxSadDgdJz+xiLqBrmC4lfAeuAfRw3HlOygcPGr+AJsbD4Z5sFJMkwjbSZlQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.76.0.tgz", + "integrity": "sha512-yoQwSom8xsB+JdGsPUU0xxmxLKiF2kdlrK7I56WtGKZilixuBf/TmOwNYJYLRWkBoW5l2/pDZOhBm2luwmLiLw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.76.0.tgz", + "integrity": "sha512-uRIopPLvr3pf2Xj7f5LKyCuqzIU6zOS+zEIR8UDYhcgJyZHnvBkfrYnfcztyIcrGdQehrFUi3uplmI09E7RdiQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.76.0.tgz", + "integrity": "sha512-a0EOFvnOd2FqmDSvH6uWLROSlU6KV/JDKbsYDA/zRLyKcG6HCsmFnPsp8iV7/xr9WMbNgyJi6R5IMpePQlUq7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.76.0.tgz", + "integrity": "sha512-ikRYDHL3fOdZwfJKmcdqjlLgkeNZ3Ez0qM8wAev5zlHZ+lY/Ig7qG5SCqPlvuTu+nNQ6zrFFaKvvt69EBKXU/g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.76.0.tgz", + "integrity": "sha512-dtRv5J5MRCLR7x39K8ufIIW4svIc7gYFUaI0YFXmmeOBhK/K2t/CkguPnDroKtsmXIPHDRtmJ1JJYzNcgJl6Wg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.76.0.tgz", + "integrity": "sha512-IE4iiiggFH2snagQxHrY5bv6dDpRMMat+vdlMN/ibonA65eOmRLp8VLTXnDiNrcla/itJ1L9qGABHNKU+SnE8g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.76.0.tgz", + "integrity": "sha512-wi9zQPMDHrBuRuT7Iurfidc9qlZh7cKa5vfYzOWNBCaqJdgxmNOFzvYen02wVUxSWGKhpiPHxrPX0jdRyJ8Npg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.76.0.tgz", + "integrity": "sha512-0tqqu1pqPee2lLGY8vtYlX1L415fFn89e0a3yp4q5N9f03j1rRs0R31qesTm3bt/UK8HYjECZ+56FCVPs2MEMQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.76.0.tgz", + "integrity": "sha512-y36Hh1a5TA+oIGtlc8lT7N9vdHXBlhBetQJW0p457KbiVQ7jF7AZkaPWhESkjHWAsTVKD2OjCa9ZqfaqhSI0FQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.76.0.tgz", + "integrity": "sha512-7/acaG9htovp3gp/J0kHgbItQTuHctl+rbqPPqZ9DRBYTz8iV8kv3QN8t8Or8i/hOmOjfZp9McDoSU1duoR4/A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.76.0.tgz", + "integrity": "sha512-AxFt0reY6Q2rfudABmMTFGR8tFFr58NlH2rRBQgcj+F+iEwgJ+jMwAPhXd2y1I2zaI8GspuahedUYQinqxWqjA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.76.0.tgz", + "integrity": "sha512-wHdkHdhf6AWBoO8vs5cpoR6zEFY1rB+fXWtq6j/xb9j/lu1evlujRVMkh8IM/M/pOUIrNkna3nzST/mRImiveQ==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.76.0.tgz", + "integrity": "sha512-G7ZlEWcb2hNwCK3qalzqJoyB6HaTigQ/GEa7CU8sAJ/WwMdG/NnPqiC9IqpEAEy1ARSo4XMALfKbKNuqbSs5mg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.76.0.tgz", + "integrity": "sha512-0jLzzmnu8/mqNhKBnNS2lFUbPEzRdj5ReiZwHGHpjma0+ullmmwP2AqSEqx3ssHDK9CpcEMdKOK2LsbCfhHKIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.76.0.tgz", + "integrity": "sha512-CH3THIrSViKal8yV/Wh3FK0pFhp40nzW1MUDCik9fNuid2D/7JJXKJnfFOAvMxInGXDlvmgT6ACAzrl47TqzkQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/binaryen": { + "version": "123.0.0", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-123.0.0.tgz", + "integrity": "sha512-/hls/a309aZCc0itqP6uhoR+5DsKSlJVfB8Opd2BY9Ndghs84IScTunlyidyF4r2Xe3lQttnfBNIDjaNpj6mTw==", + "license": "Apache-2.0", + "bin": { + "wasm-as": "bin/wasm-as", + "wasm-ctor-eval": "bin/wasm-ctor-eval", + "wasm-dis": "bin/wasm-dis", + "wasm-merge": "bin/wasm-merge", + "wasm-metadce": "bin/wasm-metadce", + "wasm-opt": "bin/wasm-opt", + "wasm-reduce": "bin/wasm-reduce", + "wasm-shell": "bin/wasm-shell", + "wasm2js": "bin/wasm2js" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oxc-parser": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.76.0.tgz", + "integrity": "sha512-l98B2e9evuhES7zN99rb1QGhbzx25829TJFaKi2j0ib3/K/G5z1FdGYz6HZkrU3U8jdH7v2FC8mX1j2l9JrOUg==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.76.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm64": "0.76.0", + "@oxc-parser/binding-darwin-arm64": "0.76.0", + "@oxc-parser/binding-darwin-x64": "0.76.0", + "@oxc-parser/binding-freebsd-x64": "0.76.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.76.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.76.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.76.0", + "@oxc-parser/binding-linux-arm64-musl": "0.76.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.76.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.76.0", + "@oxc-parser/binding-linux-x64-gnu": "0.76.0", + "@oxc-parser/binding-linux-x64-musl": "0.76.0", + "@oxc-parser/binding-wasm32-wasi": "0.76.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.76.0", + "@oxc-parser/binding-win32-x64-msvc": "0.76.0" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/terser": { + "version": "5.44.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", + "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + } + } +} diff --git a/examples/wit-demo/jco/package.json b/examples/wit-demo/jco/package.json new file mode 100644 index 000000000..72a29fe95 --- /dev/null +++ b/examples/wit-demo/jco/package.json @@ -0,0 +1,14 @@ +{ + "name": "loro-wit-jco-demo", + "version": "1.0.0", + "description": "Demo of Loro CRDT WebAssembly Component with jco", + "type": "module", + "scripts": { + "build": "jco transpile ../../../target/wasm32-wasip1/release/loro_wit.wasm -o ./gen --name loro", + "demo": "node demo.mjs" + }, + "dependencies": { + "@bytecodealliance/jco": "^1.7.0", + "@bytecodealliance/preview2-shim": "^0.17.0" + } +} diff --git a/examples/wit-demo/wasmtime-host/Cargo.toml b/examples/wit-demo/wasmtime-host/Cargo.toml new file mode 100644 index 000000000..aa40cdd19 --- /dev/null +++ b/examples/wit-demo/wasmtime-host/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "loro-wit-wasmtime-demo" +version = "0.1.0" +edition = "2021" +description = "Demo of hosting the Loro CRDT WebAssembly Component with wasmtime" + +[[bin]] +name = "loro-wit-demo" +path = "src/main.rs" + +[dependencies] +wasmtime = { version = "27.0", features = ["component-model"] } +wasmtime-wasi = "27.0" +anyhow = "1.0" diff --git a/examples/wit-demo/wasmtime-host/src/main.rs b/examples/wit-demo/wasmtime-host/src/main.rs new file mode 100644 index 000000000..8c79f08cd --- /dev/null +++ b/examples/wit-demo/wasmtime-host/src/main.rs @@ -0,0 +1,159 @@ +//! Loro CRDT WebAssembly Component Demo with wasmtime +//! +//! This demo shows how to host and use the Loro CRDT library compiled as a +//! WebAssembly Component using wasmtime. + +use anyhow::Result; +use wasmtime::component::{Component, Linker, ResourceTable}; +use wasmtime::{Config, Engine, Store}; +use wasmtime_wasi::preview2::{WasiCtx, WasiCtxBuilder, WasiView}; + +// Generate bindings for the Loro component +wasmtime::component::bindgen!({ + path: "../../../crates/loro-wit/wit", + world: "loro-world", + async: false, +}); + +struct MyState { + ctx: WasiCtx, + table: ResourceTable, +} + +impl WasiView for MyState { + fn ctx(&mut self) -> &mut WasiCtx { + &mut self.ctx + } + fn table(&mut self) -> &mut ResourceTable { + &mut self.table + } +} + +fn main() -> Result<()> { + println!("=== Loro CRDT WebAssembly Component Demo (wasmtime) ===\n"); + + // Configure the engine with component model support + let mut config = Config::new(); + config.wasm_component_model(true); + let engine = Engine::new(&config)?; + + // Load the component + let component_path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../../target/wasm32-wasip1/release/loro_wit.wasm" + ); + println!("Loading component from: {}\n", component_path); + let component = Component::from_file(&engine, component_path)?; + + // Set up the linker with WASI + let mut linker = Linker::new(&engine); + wasmtime_wasi::preview2::command::add_to_linker(&mut linker)?; + + // Create the store with WASI context + let wasi_ctx = WasiCtxBuilder::new() + .inherit_stdio() + .build(); + let state = MyState { + ctx: wasi_ctx, + table: ResourceTable::new(), + }; + let mut store = Store::new(&engine, state); + + // Instantiate the component + let (loro, _instance) = LoroWorld::instantiate(&mut store, &component, &linker)?; + + // Get the interfaces + let doc_interface = &loro.loro_crdt_loro_doc(); + let text_interface = &loro.loro_crdt_loro_text(); + let map_interface = &loro.loro_crdt_loro_map(); + let list_interface = &loro.loro_crdt_loro_list(); + + // Create a new document + println!("1. Creating a new Loro document..."); + let doc = doc_interface.doc().call_constructor(&mut store)?; + let peer_id = doc_interface.doc().call_peer_id(&mut store, doc)?; + let is_empty = doc_interface.doc().call_is_empty(&mut store, doc)?; + println!(" Document created with peer ID: {}", peer_id); + println!(" Is empty: {}\n", is_empty); + + // Working with Text + println!("2. Working with Text container..."); + let text_handle = doc_interface.doc().call_get_text(&mut store, doc, "my-text")?; + text_interface.call_insert(&mut store, doc, text_handle, 0, "Hello, ")?; + text_interface.call_insert(&mut store, doc, text_handle, 7, "World!")?; + let text_content = text_interface.call_to_string(&mut store, doc, text_handle)?; + let text_len_utf8 = text_interface.call_len_utf8(&mut store, doc, text_handle)?; + let text_len_unicode = text_interface.call_len_unicode(&mut store, doc, text_handle)?; + println!(" Text content: \"{}\"", text_content); + println!(" Length (UTF-8): {}", text_len_utf8); + println!(" Length (Unicode): {}\n", text_len_unicode); + + // Working with Map + println!("3. Working with Map container..."); + let map_handle = doc_interface.doc().call_get_map(&mut store, doc, "my-map")?; + map_interface.call_insert_string(&mut store, doc, map_handle, "name", "Loro")?; + map_interface.call_insert_number(&mut store, doc, map_handle, "version", 1.10)?; + map_interface.call_insert_bool(&mut store, doc, map_handle, "isAwesome", true)?; + let keys = map_interface.call_keys(&mut store, doc, map_handle)?; + let name = map_interface.call_get(&mut store, doc, map_handle, "name")?; + let version = map_interface.call_get(&mut store, doc, map_handle, "version")?; + let map_len = map_interface.call_len(&mut store, doc, map_handle)?; + println!(" Keys: {:?}", keys); + println!(" Name: {:?}", name); + println!(" Version: {:?}", version); + println!(" Map length: {}\n", map_len); + + // Working with List + println!("4. Working with List container..."); + let list_handle = doc_interface.doc().call_get_list(&mut store, doc, "my-list")?; + list_interface.call_push_string(&mut store, doc, list_handle, "first")?; + list_interface.call_push_number(&mut store, doc, list_handle, 42.0)?; + list_interface.call_insert_string(&mut store, doc, list_handle, 0, "zeroth")?; + let list_len = list_interface.call_len(&mut store, doc, list_handle)?; + let item0 = list_interface.call_get(&mut store, doc, list_handle, 0)?; + let item1 = list_interface.call_get(&mut store, doc, list_handle, 1)?; + let item2 = list_interface.call_get(&mut store, doc, list_handle, 2)?; + println!(" List length: {}", list_len); + println!(" Item 0: {:?}", item0); + println!(" Item 1: {:?}", item1); + println!(" Item 2: {:?}\n", item2); + + // Commit changes + println!("5. Committing changes..."); + doc_interface.doc().call_commit(&mut store, doc, Some("Initial data setup"))?; + println!(" Changes committed!\n"); + + // Export and show document state + println!("6. Document state:"); + let json_state = doc_interface.doc().call_to_json(&mut store, doc)?; + println!(" JSON: {}\n", json_state); + + // Export updates + println!("7. Exporting updates..."); + let updates = doc_interface.doc().call_export_updates(&mut store, doc)?; + println!(" Updates size: {} bytes\n", updates.len()); + + // Create a new document and import updates + println!("8. Syncing with another document..."); + let doc2 = doc_interface.doc().call_constructor(&mut store)?; + let peer_id2 = doc_interface.doc().call_peer_id(&mut store, doc2)?; + println!(" Doc2 peer ID: {}", peer_id2); + doc_interface.doc().call_import_updates(&mut store, doc2, &updates)?; + let doc2_json = doc_interface.doc().call_to_json(&mut store, doc2)?; + println!(" Doc2 after import: {}\n", doc2_json); + + // Fork the document + println!("9. Forking document..."); + let forked = doc_interface.doc().call_fork(&mut store, doc)?; + let forked_peer_id = doc_interface.doc().call_peer_id(&mut store, forked)?; + println!(" Forked doc peer ID: {}", forked_peer_id); + let forked_text = doc_interface.doc().call_get_text(&mut store, forked, "my-text")?; + text_interface.call_insert(&mut store, forked, forked_text, 0, "[Forked] ")?; + doc_interface.doc().call_commit(&mut store, forked, Some("Forked edit"))?; + let forked_text_content = text_interface.call_to_string(&mut store, forked, forked_text)?; + println!(" Forked text: \"{}\"\n", forked_text_content); + + println!("=== Demo Complete ==="); + + Ok(()) +}