From e03f2943dc0712ad8f7c11ef15f0197c9ed6d355 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Sun, 10 Sep 2023 13:20:19 +0200 Subject: [PATCH 01/13] wip --- crates/gen-guest-js/src/lib.rs | 35 ++++++- crates/gen-guest-js/tests/resources.js | 123 +++++++++++++++++++++++-- crates/gen-guest-ts/tests/resources.ts | 62 +++++++++++++ crates/gen-host/src/lib.rs | 87 +++++++++++++++-- crates/gen-host/tests/resources.rs | 107 ++++++++++++++++++++- crates/gen-js/src/lib.rs | 4 +- crates/host/src/lib.rs | 117 ++++++++++++++++++----- 7 files changed, 489 insertions(+), 46 deletions(-) diff --git a/crates/gen-guest-js/src/lib.rs b/crates/gen-guest-js/src/lib.rs index 920125c..d1dec36 100644 --- a/crates/gen-guest-js/src/lib.rs +++ b/crates/gen-guest-js/src/lib.rs @@ -80,6 +80,7 @@ export async function {ident} ({params}) {{ fn print_resource( &self, + mod_ident: &str, docs: &str, ident: &str, functions: &[Function], @@ -91,13 +92,33 @@ export async function {ident} ({params}) {{ .iter() .map(|func| { let docs = self.print_docs(func); + let mod_ident = mod_ident.to_snake_case(); + let resource_ident = ident.to_snake_case(); let ident = func.ident.to_lower_camel_case(); let params = print_function_params(&func.params); + let deserialize_result = func + .result + .as_ref() + .map(|res| self.print_deserialize_function_result(res)) + .unwrap_or_default(); + + let serialize_params = func + .params + .iter() + .map(|(ident, ty)| self.print_serialize_ty(&ident.to_lower_camel_case(), ty)) + .collect::>() + .join(";\n"); + format!( r#" {docs} async {ident} ({params}) {{ +const out = [] +serializeU32(out, this.#id); +{serialize_params} + +await fetch('ipc://localhost/{mod_ident}::resource::{resource_ident}/{ident}', {{ method: "POST", body: Uint8Array.from(out), headers: {{ 'Content-Type': 'application/octet-stream' }} }}){deserialize_result} }} "# ) @@ -106,9 +127,9 @@ async {ident} ({params}) {{ let deserialize = if info.contains(TypeInfo::RESULT) { format!( - "deserialize(de) {{ + "static deserialize(de) {{ const self = new {ident}(); - self.#id = deserializeU64(de); + self.#id = deserializeU32(de); return self }}" ) @@ -117,7 +138,7 @@ async {ident} ({params}) {{ }; format!( - "{docs}\nclass {ident} {{ + "{docs}\nexport class {ident} {{ #id; {functions} {deserialize} @@ -292,7 +313,13 @@ impl Generate for JavaScript { .filter_map(|(id, typedef)| { let info = self.infos[id]; if let TypeDefKind::Resource(functions) = &typedef.kind { - Some(self.print_resource(&typedef.docs, &typedef.ident, functions, info)) + Some(self.print_resource( + &self.interface.ident, + &typedef.docs, + &typedef.ident, + functions, + info, + )) } else { None } diff --git a/crates/gen-guest-js/tests/resources.js b/crates/gen-guest-js/tests/resources.js index 8aaefc0..dfc6cc4 100644 --- a/crates/gen-guest-js/tests/resources.js +++ b/crates/gen-guest-js/tests/resources.js @@ -17,6 +17,68 @@ class Deserializer { return out } } +// function varint_max(bits) { +// const BITS_PER_BYTE = 8; +// const BITS_PER_VARINT_BYTE = 7; + +// const roundup_bits = bits + (BITS_PER_BYTE - 1); + +// return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE); +// } + +const varint_max = { + 16: 3, + 32: 5, + 64: 10, + 128: 19 +} +function max_of_last_byte(type) { + let extra_bits = type % 7; + return (1 << extra_bits) - 1; +} + +function de_varint(de, bits) { + let out = 0; + + for (let i = 0; i < varint_max[bits]; i++) { + const val = de.pop(); + const carry = val & 0x7F; + out |= carry << (7 * i); + + if ((val & 0x80) === 0) { + if (i === varint_max[bits] - 1 && val > max_of_last_byte(bits)) { + throw new Error('deserialize bad variant') + } else { + return out + } + } + } + + throw new Error('deserialize bad variant') +} + +function de_varint_big(de, bits) { + let out = 0n; + + for (let i = 0; i < varint_max[bits]; i++) { + const val = de.pop(); + const carry = BigInt(val) & 0x7Fn; + out |= carry << (7n * BigInt(i)); + + if ((val & 0x80) === 0) { + if (i === varint_max[bits] - 1 && val > max_of_last_byte(bits)) { + throw new Error('deserialize bad variant') + } else { + return out + } + } + } + + throw new Error('deserialize bad variant') +} +function deserializeU32(de) { + return de_varint(de, 32) +} /** @@ -52,18 +114,28 @@ export async function constructorB () { } -class A { +export class A { #id; /** */ async f1 () { +const out = [] +serializeU32(out, this.#id); + + +await fetch('ipc://localhost/resources::resource::a/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } /** * @param {number} a */ async f2 (a) { +const out = [] +serializeU32(out, this.#id); +serializeU32(out, a) + +await fetch('ipc://localhost/resources::resource::a/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } /** @@ -71,21 +143,38 @@ async f2 (a) { * @param {number} b */ async f3 (a, b) { +const out = [] +serializeU32(out, this.#id); +serializeU32(out, a); +serializeU32(out, b) + +await fetch('ipc://localhost/resources::resource::a/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } - deserialize(de) { + static deserialize(de) { const self = new A(); - self.#id = deserializeU64(de); + self.#id = deserializeU32(de); return self } } -class B { +export class B { #id; /** * @returns {Promise} */ async f1 () { +const out = [] +serializeU32(out, this.#id); + + +await fetch('ipc://localhost/resources::resource::b/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return A.deserialize(de) + }) } /** @@ -93,6 +182,17 @@ async f1 () { * @returns {Promise>} */ async f2 (x) { +const out = [] +serializeU32(out, this.#id); +x.serialize(out) + +await fetch('ipc://localhost/resources::resource::b/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => deserializeU32(de), () => {}) + }) } /** @@ -100,11 +200,22 @@ async f2 (x) { * @returns {Promise>} */ async f3 (x) { +const out = [] +serializeU32(out, this.#id); +serializeOption(out, (out, v) => serializeList(out, (out, v) => v.serialize(out), v), x) + +await fetch('ipc://localhost/resources::resource::b/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => A.deserialize(de), () => {}) + }) } - deserialize(de) { + static deserialize(de) { const self = new B(); - self.#id = deserializeU64(de); + self.#id = deserializeU32(de); return self } } \ No newline at end of file diff --git a/crates/gen-guest-ts/tests/resources.ts b/crates/gen-guest-ts/tests/resources.ts index f633ef7..f90add0 100644 --- a/crates/gen-guest-ts/tests/resources.ts +++ b/crates/gen-guest-ts/tests/resources.ts @@ -18,6 +18,68 @@ class Deserializer { return out } } +// function varint_max(bits) { +// const BITS_PER_BYTE = 8; +// const BITS_PER_VARINT_BYTE = 7; + +// const roundup_bits = bits + (BITS_PER_BYTE - 1); + +// return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE); +// } + +const varint_max = { + 16: 3, + 32: 5, + 64: 10, + 128: 19 +} +function max_of_last_byte(type) { + let extra_bits = type % 7; + return (1 << extra_bits) - 1; +} + +function de_varint(de, bits) { + let out = 0; + + for (let i = 0; i < varint_max[bits]; i++) { + const val = de.pop(); + const carry = val & 0x7F; + out |= carry << (7 * i); + + if ((val & 0x80) === 0) { + if (i === varint_max[bits] - 1 && val > max_of_last_byte(bits)) { + throw new Error('deserialize bad variant') + } else { + return out + } + } + } + + throw new Error('deserialize bad variant') +} + +function de_varint_big(de, bits) { + let out = 0n; + + for (let i = 0; i < varint_max[bits]; i++) { + const val = de.pop(); + const carry = BigInt(val) & 0x7Fn; + out |= carry << (7n * BigInt(i)); + + if ((val & 0x80) === 0) { + if (i === varint_max[bits] - 1 && val > max_of_last_byte(bits)) { + throw new Error('deserialize bad variant') + } else { + return out + } + } + } + + throw new Error('deserialize bad variant') +} +function deserializeU32(de) { + return de_varint(de, 32) +} class A { diff --git a/crates/gen-host/src/lib.rs b/crates/gen-host/src/lib.rs index ee9a441..aa561f5 100644 --- a/crates/gen-host/src/lib.rs +++ b/crates/gen-host/src/lib.rs @@ -5,6 +5,7 @@ clippy::unused_self )] +use std::borrow::Cow; use std::collections::HashSet; use std::path::PathBuf; @@ -293,6 +294,7 @@ impl Host { &self, mod_ident: &str, functions: impl Iterator, + methods: impl Iterator, ) -> TokenStream { let trait_ident = format_ident!("{}", mod_ident.to_upper_camel_case()); @@ -343,6 +345,61 @@ impl Host { } }); + let methods = methods.map(|(resource_name, method)| { + let func_name = method.ident.to_snake_case(); + let func_ident = format_ident!("{}", func_name); + + let params = self.print_function_params(&method.params, &BorrowMode::Owned); + + let param_idents = method + .params + .iter() + .map(|(ident, _)| format_ident!("{}", ident)); + + let result = match method.result.as_ref() { + Some(FunctionResult::Anon(ty)) => { + let ty = self.print_ty(ty, &BorrowMode::Owned); + + quote! { #ty } + } + Some(FunctionResult::Named(types)) if types.len() == 1 => { + let (_, ty) = &types[0]; + let ty = self.print_ty(ty, &BorrowMode::Owned); + + quote! { #ty } + } + Some(FunctionResult::Named(types)) => { + let types = types + .iter() + .map(|(_, ty)| self.print_ty(ty, &BorrowMode::Owned)); + + quote! { (#(#types),*) } + } + _ => quote! { () }, + }; + + let mod_name = format!("{}::resource::{}", mod_name, resource_name); + let get_r_ident = format_ident!("get_{}", resource_name.to_snake_case()); + + quote! { + let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx); + router.func_wrap( + #mod_name, + #func_name, + move | + ctx: ::tauri_bindgen_host::ipc_router_wip::Caller, + this_rid: ::tauri_bindgen_host::ResourceId, + #params + | -> ::tauri_bindgen_host::anyhow::Result<#result> { + let ctx = get_cx(ctx.data()); + let r = ctx.#get_r_ident(this_rid)?; + + Ok(r.#func_ident(#(#param_idents),*)) + }, + )?; + } + }); + quote! { pub fn add_to_router( router: &mut ::tauri_bindgen_host::ipc_router_wip::Router, @@ -354,6 +411,7 @@ impl Host { let wrapped_get_cx = ::std::sync::Arc::new(get_cx); #( #functions )* + #( #methods )* Ok(()) } @@ -365,22 +423,36 @@ impl Generate for Host { fn to_tokens(&mut self) -> TokenStream { let docs = self.print_docs(&self.interface.docs); - let ident = format_ident!("{}", self.interface.ident.to_snake_case()); + let iface_name = self.interface.ident.to_snake_case(); + let ident = format_ident!("{}", iface_name); let typedefs = self.print_typedefs( self.interface.typedefs.iter().map(|(id, _)| id), &BorrowMode::Owned, ); + let methods = self + .interface() + .typedefs + .iter() + .filter_map(|(_, typedef)| { + if let TypeDefKind::Resource(methods) = &typedef.kind { + Some(std::iter::repeat(typedef.ident.as_str()).zip(methods.iter())) + } else { + None + } + }) + .flatten(); + let resources = self.interface.typedefs.iter().filter_map(|(_, typedef)| { if let TypeDefKind::Resource(_) = &typedef.kind { let ident = format_ident!("{}", typedef.ident.to_upper_camel_case()); - let func_ident = format_ident!("get_{}_mut", typedef.ident.to_snake_case()); + let func_ident = format_ident!("get_{}", typedef.ident.to_snake_case()); Some(quote! { - type #ident: #ident; + type #ident: #ident + Send + Sync; - fn #func_ident(&mut self, id: ::tauri_bindgen_host::ResourceId) -> &mut Self::#ident; + fn #func_ident(&self, id: ::tauri_bindgen_host::ResourceId) -> ::tauri_bindgen_host::Result<::std::sync::Arc>; }) } else { None @@ -394,8 +466,11 @@ impl Generate for Host { true, ); - let add_to_router = - self.print_add_to_router(&self.interface.ident, self.interface.functions.iter()); + let add_to_router = self.print_add_to_router( + &self.interface.ident, + self.interface.functions.iter(), + methods, + ); quote! { #docs diff --git a/crates/gen-host/tests/resources.rs b/crates/gen-host/tests/resources.rs index 394be6d..00d5c72 100644 --- a/crates/gen-host/tests/resources.rs +++ b/crates/gen-host/tests/resources.rs @@ -18,10 +18,16 @@ pub mod resources { ) -> Result<::tauri_bindgen_host::ResourceId, ()>; } pub trait Resources: Sized { - type A: A; - fn get_a_mut(&mut self, id: ::tauri_bindgen_host::ResourceId) -> &mut Self::A; - type B: B; - fn get_b_mut(&mut self, id: ::tauri_bindgen_host::ResourceId) -> &mut Self::B; + type A: A + Send + Sync; + fn get_a( + &self, + id: ::tauri_bindgen_host::ResourceId, + ) -> ::tauri_bindgen_host::Result<::std::sync::Arc>; + type B: B + Send + Sync; + fn get_b( + &self, + id: ::tauri_bindgen_host::ResourceId, + ) -> ::tauri_bindgen_host::Result<::std::sync::Arc>; fn constructor_a(&self) -> ::tauri_bindgen_host::ResourceId; fn constructor_b(&self) -> ::tauri_bindgen_host::ResourceId; } @@ -61,6 +67,99 @@ pub mod resources { Ok(ctx.constructor_b()) }, )?; + let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx); + router + .func_wrap( + "resources::resource::a", + "f1", + move | + ctx: ::tauri_bindgen_host::ipc_router_wip::Caller, + this_rid: ::tauri_bindgen_host::ResourceId, + | -> ::tauri_bindgen_host::anyhow::Result<()> { + let ctx = get_cx(ctx.data()); + let r = ctx.get_a(this_rid)?; + Ok(r.f1()) + }, + )?; + let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx); + router + .func_wrap( + "resources::resource::a", + "f2", + move | + ctx: ::tauri_bindgen_host::ipc_router_wip::Caller, + this_rid: ::tauri_bindgen_host::ResourceId, + a: u32, + | -> ::tauri_bindgen_host::anyhow::Result<()> { + let ctx = get_cx(ctx.data()); + let r = ctx.get_a(this_rid)?; + Ok(r.f2(a)) + }, + )?; + let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx); + router + .func_wrap( + "resources::resource::a", + "f3", + move | + ctx: ::tauri_bindgen_host::ipc_router_wip::Caller, + this_rid: ::tauri_bindgen_host::ResourceId, + a: u32, + b: u32, + | -> ::tauri_bindgen_host::anyhow::Result<()> { + let ctx = get_cx(ctx.data()); + let r = ctx.get_a(this_rid)?; + Ok(r.f3(a, b)) + }, + )?; + let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx); + router + .func_wrap( + "resources::resource::b", + "f1", + move | + ctx: ::tauri_bindgen_host::ipc_router_wip::Caller, + this_rid: ::tauri_bindgen_host::ResourceId, + | -> ::tauri_bindgen_host::anyhow::Result< + ::tauri_bindgen_host::ResourceId, + > { + let ctx = get_cx(ctx.data()); + let r = ctx.get_b(this_rid)?; + Ok(r.f1()) + }, + )?; + let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx); + router + .func_wrap( + "resources::resource::b", + "f2", + move | + ctx: ::tauri_bindgen_host::ipc_router_wip::Caller, + this_rid: ::tauri_bindgen_host::ResourceId, + x: ::tauri_bindgen_host::ResourceId, + | -> ::tauri_bindgen_host::anyhow::Result> { + let ctx = get_cx(ctx.data()); + let r = ctx.get_b(this_rid)?; + Ok(r.f2(x)) + }, + )?; + let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx); + router + .func_wrap( + "resources::resource::b", + "f3", + move | + ctx: ::tauri_bindgen_host::ipc_router_wip::Caller, + this_rid: ::tauri_bindgen_host::ResourceId, + x: Option>, + | -> ::tauri_bindgen_host::anyhow::Result< + Result<::tauri_bindgen_host::ResourceId, ()>, + > { + let ctx = get_cx(ctx.data()); + let r = ctx.get_b(this_rid)?; + Ok(r.f3(x)) + }, + )?; Ok(()) } } diff --git a/crates/gen-js/src/lib.rs b/crates/gen-js/src/lib.rs index e5a230b..74abb18 100644 --- a/crates/gen-js/src/lib.rs +++ b/crates/gen-js/src/lib.rs @@ -752,7 +752,9 @@ impl SerdeUtils { wit_parser::Int::U128 => SerdeUtils::U128, }; } - TypeDefKind::Resource(_) => {} + TypeDefKind::Resource(_) => { + info |= SerdeUtils::U32; + } } log::debug!("collected info for {:?}: {:?}", typedefs[id].ident, info,); diff --git a/crates/host/src/lib.rs b/crates/host/src/lib.rs index d80f7a5..775c35b 100644 --- a/crates/host/src/lib.rs +++ b/crates/host/src/lib.rs @@ -1,34 +1,101 @@ -pub use tauri_bindgen_host_macro::*; +use std::marker::PhantomData; +use std::sync::Arc; +use std::sync::RwLock; +use std::{any::Any, collections::HashMap}; -pub use generational_arena::Arena as ResourceTable; +pub use tauri_bindgen_host_macro::*; #[doc(hidden)] pub use {anyhow, async_trait::async_trait, bitflags, ipc_router_wip, serde, tauri, tracing}; - -pub type ResourceId = u64; - pub type Result = anyhow::Result; -// #[derive(Debug)] -// pub struct ResourceId { -// id: generational_arena::Index, -// _m: PhantomData, -// } +pub type ResourceId = u32; -// impl Clone for ResourceId { -// fn clone(&self) -> Self { -// Self { -// id: self.id.clone(), -// _m: PhantomData, -// } -// } -// } +#[derive(Default)] +pub struct ResourceTable(RwLock); -// impl Copy for ResourceId {} +#[derive(Default)] +pub struct ResourceTableInner { + map: HashMap>, + next_rid: ResourceId, +} -// impl PartialEq for ResourceId { -// fn eq(&self, other: &Self) -> bool { -// self.id == other.id -// } -// } +impl ResourceTable { + /// Create an empty table. New insertions will begin at 3, above stdio. + pub fn new() -> Self { + Self(RwLock::new(ResourceTableInner { + map: HashMap::new(), + next_rid: 0, + })) + } -// impl Eq for ResourceId {} + /// Insert a resource at the next available index. + pub fn push(&self, a: Arc) -> Result { + let mut inner = self.0.write().unwrap(); + // NOTE: The performance of this new key calculation could be very bad once keys wrap + // around. + if inner.map.len() == u32::MAX as usize { + return Err(anyhow::anyhow!("table has no free keys")); + } + loop { + let key = inner.next_rid; + inner.next_rid += 1; + if inner.map.contains_key(&key) { + continue; + } + inner.map.insert(key, a); + return Ok(key); + } + } + + /// Check if the table has a resource at the given index. + pub fn contains_key(&self, key: ResourceId) -> bool { + self.0.read().unwrap().map.contains_key(&key) + } + + /// Check if the resource at a given index can be downcast to a given type. + /// Note: this will always fail if the resource is already borrowed. + pub fn is(&self, key: ResourceId) -> bool { + if let Some(r) = self.0.read().unwrap().map.get(&key) { + r.is::() + } else { + false + } + } + + /// Get an Arc reference to a resource of a given type at a given index. Multiple + /// immutable references can be borrowed at any given time. + pub fn get(&self, key: ResourceId) -> Result> { + if let Some(r) = self.0.read().unwrap().map.get(&key).cloned() { + r.downcast::() + .map_err(|_| anyhow::anyhow!("element is a different type")) + } else { + Err(anyhow::anyhow!("key not in table")) + } + } + + /// Get a mutable reference to a resource of a given type at a given index. + /// Only one such reference can be borrowed at any given time. + pub fn get_mut(&mut self, key: ResourceId) -> Result<&mut T> { + let entry = match self.0.get_mut().unwrap().map.get_mut(&key) { + Some(entry) => entry, + None => return Err(anyhow::anyhow!("key not in table")), + }; + let entry = match Arc::get_mut(entry) { + Some(entry) => entry, + None => return Err(anyhow::anyhow!("cannot mutably borrow shared file")), + }; + entry + .downcast_mut::() + .ok_or_else(|| anyhow::anyhow!("element is a different type")) + } + + /// Remove a resource at a given index from the table and returns it. + pub fn take(&self, key: ResourceId) -> Option> { + self.0 + .write() + .unwrap() + .map + .remove(&key) + .map(|r| r.downcast::().unwrap()) + } +} From 03920c85c936b5f9397c7e98d68005c797b9d7f3 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Sun, 10 Sep 2023 13:33:27 +0200 Subject: [PATCH 02/13] wip: ts guest impl --- crates/gen-guest-js/src/lib.rs | 11 +++-- crates/gen-guest-js/tests/resources.js | 58 ++++++++++++------------- crates/gen-guest-ts/src/lib.rs | 40 ++++++++++++++--- crates/gen-guest-ts/tests/resources.ts | 59 ++++++++++++++++++++++---- 4 files changed, 115 insertions(+), 53 deletions(-) diff --git a/crates/gen-guest-js/src/lib.rs b/crates/gen-guest-js/src/lib.rs index d1dec36..1be9c4b 100644 --- a/crates/gen-guest-js/src/lib.rs +++ b/crates/gen-guest-js/src/lib.rs @@ -111,14 +111,13 @@ export async function {ident} ({params}) {{ .join(";\n"); format!( - r#" -{docs} + r#"{docs} async {ident} ({params}) {{ -const out = [] -serializeU32(out, this.#id); -{serialize_params} + const out = [] + serializeU32(out, this.#id); + {serialize_params} -await fetch('ipc://localhost/{mod_ident}::resource::{resource_ident}/{ident}', {{ method: "POST", body: Uint8Array.from(out), headers: {{ 'Content-Type': 'application/octet-stream' }} }}){deserialize_result} + await fetch('ipc://localhost/{mod_ident}::resource::{resource_ident}/{ident}', {{ method: "POST", body: Uint8Array.from(out), headers: {{ 'Content-Type': 'application/octet-stream' }} }}){deserialize_result} }} "# ) diff --git a/crates/gen-guest-js/tests/resources.js b/crates/gen-guest-js/tests/resources.js index dfc6cc4..46f7e3c 100644 --- a/crates/gen-guest-js/tests/resources.js +++ b/crates/gen-guest-js/tests/resources.js @@ -116,39 +116,36 @@ export async function constructorB () { export class A { #id; - -/** + /** */ async f1 () { -const out = [] -serializeU32(out, this.#id); + const out = [] + serializeU32(out, this.#id); + - -await fetch('ipc://localhost/resources::resource::a/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + await fetch('ipc://localhost/resources::resource::a/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } - /** * @param {number} a */ async f2 (a) { -const out = [] -serializeU32(out, this.#id); -serializeU32(out, a) + const out = [] + serializeU32(out, this.#id); + serializeU32(out, a) -await fetch('ipc://localhost/resources::resource::a/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + await fetch('ipc://localhost/resources::resource::a/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } - /** * @param {number} a * @param {number} b */ async f3 (a, b) { -const out = [] -serializeU32(out, this.#id); -serializeU32(out, a); + const out = [] + serializeU32(out, this.#id); + serializeU32(out, a); serializeU32(out, b) -await fetch('ipc://localhost/resources::resource::a/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + await fetch('ipc://localhost/resources::resource::a/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } static deserialize(de) { @@ -159,16 +156,15 @@ await fetch('ipc://localhost/resources::resource::a/f3', { method: "POST", body: } export class B { #id; - -/** + /** * @returns {Promise} */ async f1 () { -const out = [] -serializeU32(out, this.#id); + const out = [] + serializeU32(out, this.#id); + - -await fetch('ipc://localhost/resources::resource::b/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + await fetch('ipc://localhost/resources::resource::b/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) .then(r => r.arrayBuffer()) .then(bytes => { const de = new Deserializer(new Uint8Array(bytes)) @@ -176,17 +172,16 @@ await fetch('ipc://localhost/resources::resource::b/f1', { method: "POST", body: return A.deserialize(de) }) } - /** * @param {A} x * @returns {Promise>} */ async f2 (x) { -const out = [] -serializeU32(out, this.#id); -x.serialize(out) + const out = [] + serializeU32(out, this.#id); + x.serialize(out) -await fetch('ipc://localhost/resources::resource::b/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + await fetch('ipc://localhost/resources::resource::b/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) .then(r => r.arrayBuffer()) .then(bytes => { const de = new Deserializer(new Uint8Array(bytes)) @@ -194,17 +189,16 @@ await fetch('ipc://localhost/resources::resource::b/f2', { method: "POST", body: return deserializeResult(de, (de) => deserializeU32(de), () => {}) }) } - /** * @param {A[] | null} x * @returns {Promise>} */ async f3 (x) { -const out = [] -serializeU32(out, this.#id); -serializeOption(out, (out, v) => serializeList(out, (out, v) => v.serialize(out), v), x) + const out = [] + serializeU32(out, this.#id); + serializeOption(out, (out, v) => serializeList(out, (out, v) => v.serialize(out), v), x) -await fetch('ipc://localhost/resources::resource::b/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + await fetch('ipc://localhost/resources::resource::b/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) .then(r => r.arrayBuffer()) .then(bytes => { const de = new Deserializer(new Uint8Array(bytes)) diff --git a/crates/gen-guest-ts/src/lib.rs b/crates/gen-guest-ts/src/lib.rs index 3db5549..a945a7c 100644 --- a/crates/gen-guest-ts/src/lib.rs +++ b/crates/gen-guest-ts/src/lib.rs @@ -189,7 +189,9 @@ export async function {ident} ({params}) : {result} {{ TypeDefKind::Variant(cases) => self.print_variant(&docs, ident, cases), TypeDefKind::Enum(cases) => self.print_enum(&docs, ident, cases), TypeDefKind::Union(cases) => self.print_union(&docs, ident, cases), - TypeDefKind::Resource(functions) => self.print_resource(&docs, ident, functions), + TypeDefKind::Resource(functions) => { + self.print_resource(&self.interface.ident, &docs, ident, functions) + } } } @@ -293,12 +295,19 @@ export async function {ident} ({params}) : {result} {{ format!("{docs}\nexport type {ident} = {cases};\n") } - fn print_resource(&self, docs: &str, ident: &str, functions: &[Function]) -> String { + fn print_resource( + &self, + mod_ident: &str, + docs: &str, + ident: &str, + functions: &[Function], + ) -> String { let functions: String = functions .iter() .map(|func| { let docs = print_docs(&func.docs); - + let mod_ident = mod_ident.to_snake_case(); + let resource_ident = ident.to_snake_case(); let ident = func.ident.to_lower_camel_case(); let params = self.print_function_params(&func.params); @@ -306,12 +315,29 @@ export async function {ident} ({params}) : {result} {{ .result .as_ref() .map(|result| self.print_function_result(result)) + .unwrap_or("void".to_string()); + + let deserialize_result = func + .result + .as_ref() + .map(|res| self.print_deserialize_function_result(res)) .unwrap_or_default(); + let serialize_params = func + .params + .iter() + .map(|(ident, ty)| self.print_serialize_ty(&ident.to_lower_camel_case(), ty)) + .collect::>() + .join(";\n"); + format!( - r#" -{docs} -async {ident} ({params}) {result} {{ + r#"{docs} +async {ident} ({params}) : {result} {{ + const out = [] + serializeU32(out, this.#id); + {serialize_params} + + await fetch('ipc://localhost/{mod_ident}::resource::{resource_ident}/{ident}', {{ method: "POST", body: Uint8Array.from(out), headers: {{ 'Content-Type': 'application/octet-stream' }} }}){deserialize_result} }} "# ) @@ -319,7 +345,7 @@ async {ident} ({params}) {result} {{ .collect(); format!( - "{docs}\nclass {ident} {{ + "{docs}\nexport class {ident} {{ #id: number; {functions} diff --git a/crates/gen-guest-ts/tests/resources.ts b/crates/gen-guest-ts/tests/resources.ts index f90add0..34cfd4a 100644 --- a/crates/gen-guest-ts/tests/resources.ts +++ b/crates/gen-guest-ts/tests/resources.ts @@ -82,37 +82,80 @@ function deserializeU32(de) { } -class A { +export class A { #id: number; +async f1 () : void { + const out = [] + serializeU32(out, this.#id); + -async f1 () { + await fetch('ipc://localhost/resources::resource::a/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } +async f2 (a: number) : void { + const out = [] + serializeU32(out, this.#id); + serializeU32(out, a) -async f2 (a: number) { + await fetch('ipc://localhost/resources::resource::a/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } +async f3 (a: number, b: number) : void { + const out = [] + serializeU32(out, this.#id); + serializeU32(out, a); +serializeU32(out, b) -async f3 (a: number, b: number) { + await fetch('ipc://localhost/resources::resource::a/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) } } -class B { +export class B { #id: number; +async f1 () : Promise { + const out = [] + serializeU32(out, this.#id); + -async f1 () Promise { + await fetch('ipc://localhost/resources::resource::b/f1', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return A.deserialize(de) + }) } +async f2 (x: A) : Promise> { + const out = [] + serializeU32(out, this.#id); + x.serialize(out) -async f2 (x: A) Promise> { + await fetch('ipc://localhost/resources::resource::b/f2', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => deserializeU32(de), () => {}) + }) } +async f3 (x: A[] | null) : Promise> { + const out = [] + serializeU32(out, this.#id); + serializeOption(out, (out, v) => serializeList(out, (out, v) => v.serialize(out), v), x) -async f3 (x: A[] | null) Promise> { + await fetch('ipc://localhost/resources::resource::b/f3', { method: "POST", body: Uint8Array.from(out), headers: { 'Content-Type': 'application/octet-stream' } }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => A.deserialize(de), () => {}) + }) } } From 5059b872f2ce7a7e9ea40949d72c35f66053c25f Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Sun, 10 Sep 2023 13:53:39 +0200 Subject: [PATCH 03/13] fix(js/ts): serialize variant --- crates/gen-guest-js/tests/lists.js | 21 +- crates/gen-guest-js/tests/variants.js | 57 +- crates/gen-guest-ts/tests/lists.ts | 21 +- crates/gen-guest-ts/tests/variants.ts | 1148 +++++++++++++------------ crates/gen-js/src/lib.rs | 3 +- 5 files changed, 651 insertions(+), 599 deletions(-) diff --git a/crates/gen-guest-js/tests/lists.js b/crates/gen-guest-js/tests/lists.js index d83a34e..77b7da0 100644 --- a/crates/gen-guest-js/tests/lists.js +++ b/crates/gen-guest-js/tests/lists.js @@ -335,15 +335,18 @@ serializeS64(out, val.c4) }function serializeOtherVariant(out, val) { if (val.A) { serializeU32(out, 0); - return + + return } if (val.B) { serializeU32(out, 1); - return serializeU32(out, val.B) + serializeU32(out, val.B) + return } if (val.C) { serializeU32(out, 2); - return serializeString(out, val.C) + serializeString(out, val.C) + return } @@ -351,19 +354,23 @@ if (val.C) { }function serializeSomeVariant(out, val) { if (val.A) { serializeU32(out, 0); - return serializeString(out, val.A) + serializeString(out, val.A) + return } if (val.B) { serializeU32(out, 1); - return + + return } if (val.C) { serializeU32(out, 2); - return serializeU32(out, val.C) + serializeU32(out, val.C) + return } if (val.D) { serializeU32(out, 3); - return serializeList(out, (out, v) => serializeOtherVariant(out, v), val.D) + serializeList(out, (out, v) => serializeOtherVariant(out, v), val.D) + return } diff --git a/crates/gen-guest-js/tests/variants.js b/crates/gen-guest-js/tests/variants.js index a7aafef..0845012 100644 --- a/crates/gen-guest-js/tests/variants.js +++ b/crates/gen-guest-js/tests/variants.js @@ -431,31 +431,38 @@ case 1: }function serializeV1(out, val) { if (val.A) { serializeU32(out, 0); - return + + return } if (val.B) { serializeU32(out, 1); - return serializeU1(out, val.B) + serializeU1(out, val.B) + return } if (val.C) { serializeU32(out, 2); - return serializeE1(out, val.C) + serializeE1(out, val.C) + return } if (val.D) { serializeU32(out, 3); - return serializeString(out, val.D) + serializeString(out, val.D) + return } if (val.E) { serializeU32(out, 4); - return serializeEmpty(out, val.E) + serializeEmpty(out, val.E) + return } if (val.F) { serializeU32(out, 5); - return + + return } if (val.G) { serializeU32(out, 6); - return serializeU32(out, val.G) + serializeU32(out, val.G) + return } @@ -463,11 +470,13 @@ if (val.G) { }function serializeCasts1(out, val) { if (val.A) { serializeU32(out, 0); - return serializeS32(out, val.A) + serializeS32(out, val.A) + return } if (val.B) { serializeU32(out, 1); - return serializeF32(out, val.B) + serializeF32(out, val.B) + return } @@ -475,11 +484,13 @@ if (val.B) { }function serializeCasts2(out, val) { if (val.A) { serializeU32(out, 0); - return serializeF64(out, val.A) + serializeF64(out, val.A) + return } if (val.B) { serializeU32(out, 1); - return serializeF32(out, val.B) + serializeF32(out, val.B) + return } @@ -487,11 +498,13 @@ if (val.B) { }function serializeCasts3(out, val) { if (val.A) { serializeU32(out, 0); - return serializeF64(out, val.A) + serializeF64(out, val.A) + return } if (val.B) { serializeU32(out, 1); - return serializeU64(out, val.B) + serializeU64(out, val.B) + return } @@ -499,11 +512,13 @@ if (val.B) { }function serializeCasts4(out, val) { if (val.A) { serializeU32(out, 0); - return serializeU32(out, val.A) + serializeU32(out, val.A) + return } if (val.B) { serializeU32(out, 1); - return serializeS64(out, val.B) + serializeS64(out, val.B) + return } @@ -511,11 +526,13 @@ if (val.B) { }function serializeCasts5(out, val) { if (val.A) { serializeU32(out, 0); - return serializeF32(out, val.A) + serializeF32(out, val.A) + return } if (val.B) { serializeU32(out, 1); - return serializeS64(out, val.B) + serializeS64(out, val.B) + return } @@ -523,11 +540,13 @@ if (val.B) { }function serializeCasts6(out, val) { if (val.A) { serializeU32(out, 0); - return {serializeF32(out, val.A[0]);serializeU32(out, val.A[1])} + {serializeF32(out, val.A[0]);serializeU32(out, val.A[1])} + return } if (val.B) { serializeU32(out, 1); - return {serializeU32(out, val.B[0]);serializeU32(out, val.B[1])} + {serializeU32(out, val.B[0]);serializeU32(out, val.B[1])} + return } diff --git a/crates/gen-guest-ts/tests/lists.ts b/crates/gen-guest-ts/tests/lists.ts index d67b141..c5d3803 100644 --- a/crates/gen-guest-ts/tests/lists.ts +++ b/crates/gen-guest-ts/tests/lists.ts @@ -336,15 +336,18 @@ serializeS64(out, val.c4) }function serializeOtherVariant(out, val) { if (val.A) { serializeU32(out, 0); - return + + return } if (val.B) { serializeU32(out, 1); - return serializeU32(out, val.B) + serializeU32(out, val.B) + return } if (val.C) { serializeU32(out, 2); - return serializeString(out, val.C) + serializeString(out, val.C) + return } @@ -352,19 +355,23 @@ if (val.C) { }function serializeSomeVariant(out, val) { if (val.A) { serializeU32(out, 0); - return serializeString(out, val.A) + serializeString(out, val.A) + return } if (val.B) { serializeU32(out, 1); - return + + return } if (val.C) { serializeU32(out, 2); - return serializeU32(out, val.C) + serializeU32(out, val.C) + return } if (val.D) { serializeU32(out, 3); - return serializeList(out, (out, v) => serializeOtherVariant(out, v), val.D) + serializeList(out, (out, v) => serializeOtherVariant(out, v), val.D) + return } diff --git a/crates/gen-guest-ts/tests/variants.ts b/crates/gen-guest-ts/tests/variants.ts index dda3e05..06f5051 100644 --- a/crates/gen-guest-ts/tests/variants.ts +++ b/crates/gen-guest-ts/tests/variants.ts @@ -1,23 +1,23 @@ // @ts-nocheck export type Result = { tag: 'ok', val: T } | { tag: 'err', val: E }; class Deserializer { - source - offset - - constructor(bytes) { - this.source = bytes - this.offset = 0 - } + source + offset - pop() { - return this.source[this.offset++] - } + constructor(bytes) { + this.source = bytes + this.offset = 0 + } - try_take_n(len) { - const out = this.source.slice(this.offset, this.offset + len) - this.offset += len - return out - } + pop() { + return this.source[this.offset++] + } + + try_take_n(len) { + const out = this.source.slice(this.offset, this.offset + len) + this.offset += len + return out + } } // function varint_max(bits) { // const BITS_PER_BYTE = 8; @@ -79,31 +79,31 @@ function de_varint_big(de, bits) { throw new Error('deserialize bad variant') } function deserializeBool(de) { - const val = de.pop(); + const val = de.pop(); - return val != 0 + return val != 0 } function deserializeU8(de) { - return de.pop() + return de.pop() } function deserializeU32(de) { - return de_varint(de, 32) + return de_varint(de, 32) } function deserializeU64(de) { return de_varint_big(de, 64) } function deserializeS8(de) { - const buf = new ArrayBuffer(1); - const view = new DataView(buf); + const buf = new ArrayBuffer(1); + const view = new DataView(buf); - buf[0] = view.setUint8(0, de.pop()); + buf[0] = view.setUint8(0, de.pop()); - return view.getInt8(0); + return view.getInt8(0); } function deserializeS32(de) { - const n = de_varint(de, 32) + const n = de_varint(de, 32) - return Number(((n >> 1) & 0xFFFFFFFF) ^ (-((n & 0b1) & 0xFFFFFFFF))) + return Number(((n >> 1) & 0xFFFFFFFF) ^ (-((n & 0b1) & 0xFFFFFFFF))) } function deserializeS64(de) { const n = de_varint_big(de, 64) @@ -111,62 +111,62 @@ function deserializeS64(de) { return ((n >> 1n) & 0xFFFFFFFFFFFFFFFFn) ^ (-((n & 0b1n) & 0xFFFFFFFFFFFFFFFFn)) } function deserializeF32(de) { - const bytes = de.try_take_n(4); + const bytes = de.try_take_n(4); - const buf = new ArrayBuffer(4); - const view = new DataView(buf); + const buf = new ArrayBuffer(4); + const view = new DataView(buf); - bytes.forEach((v, i) => view.setUint8(i, v)); + bytes.forEach((v, i) => view.setUint8(i, v)); - return view.getFloat32(0, true); + return view.getFloat32(0, true); } function deserializeF64(de) { - const bytes = de.try_take_n(8); + const bytes = de.try_take_n(8); - const buf = new ArrayBuffer(8); - const view = new DataView(buf); + const buf = new ArrayBuffer(8); + const view = new DataView(buf); - bytes.forEach((v, i) => view.setUint8(i, v)); + bytes.forEach((v, i) => view.setUint8(i, v)); - return view.getFloat64(0, true); + return view.getFloat64(0, true); } function deserializeString(de) { - const sz = deserializeU64(de); + const sz = deserializeU64(de); - let bytes = de.try_take_n(Number(sz)); + let bytes = de.try_take_n(Number(sz)); - return __text_decoder.decode(bytes); + return __text_decoder.decode(bytes); } function deserializeBytes(de) { - const sz = deserializeU64(de); + const sz = deserializeU64(de); - let bytes = de.try_take_n(Number(sz)); + let bytes = de.try_take_n(Number(sz)); - return bytes; + return bytes; } function deserializeOption(de, inner) { - const tag = de.pop() + const tag = de.pop() - switch (tag) { - case 0: - return null - case 1: - return inner(de) - default: - throw new Error(`Deserialize bad option ${tag}`) - } + switch (tag) { + case 0: + return null + case 1: + return inner(de) + default: + throw new Error(`Deserialize bad option ${tag}`) + } } function deserializeResult(de, ok, err) { - const tag = de.pop() + const tag = de.pop() - switch (tag) { - case 0: - return { tag: 'ok', val: ok(de) } - case 1: - return { tag: 'err', val: err(de) } - default: - throw new Error(`Deserialize bad result ${tag}`) - } + switch (tag) { + case 0: + return { tag: 'ok', val: ok(de) } + case 1: + return { tag: 'err', val: err(de) } + default: + throw new Error(`Deserialize bad result ${tag}`) + } } function ser_varint(out, bits, val) { let buf = [] @@ -204,351 +204,370 @@ function ser_varint_big(out, bits, val) { out.push(...buf) } function serializeBool(out, val) { - out.push(val === true ? 1 : 0) + out.push(val === true ? 1 : 0) } function serializeU8(out, val) { - return out.push(val) + return out.push(val) } function serializeU32(out, val) { - return ser_varint(out, 32, val) + return ser_varint(out, 32, val) } function serializeU64(out, val) { return ser_varint_big(out, 64, BigInt(val)) } function serializeS8(out, val) { - out.push(val) + out.push(val) } function serializeS32(out, val) { - ser_varint(out, 32, (val << 1) ^ (val >> 31)) + ser_varint(out, 32, (val << 1) ^ (val >> 31)) } function serializeS64(out, val) { val = BigInt(val) ser_varint_big(out, 64, (val << 1n) ^ (val >> 63n)) } function serializeF32(out, val) { - const buf = new ArrayBuffer(4); - const view = new DataView(buf); + const buf = new ArrayBuffer(4); + const view = new DataView(buf); - view.setFloat32(0, val, true); + view.setFloat32(0, val, true); - out.push(...new Uint8Array(buf)) + out.push(...new Uint8Array(buf)) } function serializeF64(out, val) { - const buf = new ArrayBuffer(8); - const view = new DataView(buf); + const buf = new ArrayBuffer(8); + const view = new DataView(buf); - view.setFloat64(0, val, true); + view.setFloat64(0, val, true); - out.push(...new Uint8Array(buf)) + out.push(...new Uint8Array(buf)) } function serializeString(out, val) { - serializeU64(out, val.length); + serializeU64(out, val.length); - out.push(...__text_encoder.encode(val)) + out.push(...__text_encoder.encode(val)) } function serializeBytes(out, val) { - serializeU64(out, val.length); - out.push(...val) + serializeU64(out, val.length); + out.push(...val) } function serializeOption(out, inner, val) { - serializeU8(out, !!val ? 1 : 0) - if (val) { - inner(out, val) - } + serializeU8(out, !!val ? 1 : 0) + if (val) { + inner(out, val) + } } function serializeResult(out, ok, err, val) { - if (val.Ok) { - serializeU8(out, 0); - return ok(out, val.Ok); - } + if (val.Ok) { + serializeU8(out, 0); + return ok(out, val.Ok); + } - if (val.Err) { - serializeU8(out, 1); - return err(out, val.Err); - } + if (val.Err) { + serializeU8(out, 1); + return err(out, val.Err); + } - throw new Error(`Serialize bad result ${val}`); + throw new Error(`Serialize bad result ${val}`); } const __text_decoder = new TextDecoder('utf-8'); const __text_encoder = new TextEncoder(); function deserializeE1(de) { - const tag = deserializeU32(de) + const tag = deserializeU32(de) - switch (tag) { - case 0: - return "A" + switch (tag) { + case 0: + return "A" - default: - throw new Error(`unknown enum case ${tag}`) - } -}function deserializeU1(de) { - const tag = deserializeU32(de) + default: + throw new Error(`unknown enum case ${tag}`) + } +} function deserializeU1(de) { + const tag = deserializeU32(de) - switch (tag) { - case 0: - return { U32: deserializeU32(de) } -case 1: - return { F32: deserializeF32(de) } + switch (tag) { + case 0: + return { U32: deserializeU32(de) } + case 1: + return { F32: deserializeF32(de) } - default: - throw new Error(`unknown union case ${tag}`) - } -}function deserializeEmpty(de) { - return { - - } -}function deserializeV1(de) { - const tag = deserializeU32(de) + default: + throw new Error(`unknown union case ${tag}`) + } +} function deserializeEmpty(de) { + return { - switch (tag) { - case 0: - return { A: null } -case 1: - return { B: deserializeU1(de) } -case 2: - return { C: deserializeE1(de) } -case 3: - return { D: deserializeString(de) } -case 4: - return { E: deserializeEmpty(de) } -case 5: - return { F: null } -case 6: - return { G: deserializeU32(de) } + } +} function deserializeV1(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -}function deserializeCasts1(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: null } + case 1: + return { B: deserializeU1(de) } + case 2: + return { C: deserializeE1(de) } + case 3: + return { D: deserializeString(de) } + case 4: + return { E: deserializeEmpty(de) } + case 5: + return { F: null } + case 6: + return { G: deserializeU32(de) } - switch (tag) { - case 0: - return { A: deserializeS32(de) } -case 1: - return { B: deserializeF32(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +} function deserializeCasts1(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -}function deserializeCasts2(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeS32(de) } + case 1: + return { B: deserializeF32(de) } - switch (tag) { - case 0: - return { A: deserializeF64(de) } -case 1: - return { B: deserializeF32(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +} function deserializeCasts2(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -}function deserializeCasts3(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeF64(de) } + case 1: + return { B: deserializeF32(de) } - switch (tag) { - case 0: - return { A: deserializeF64(de) } -case 1: - return { B: deserializeU64(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +} function deserializeCasts3(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -}function deserializeCasts4(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeF64(de) } + case 1: + return { B: deserializeU64(de) } - switch (tag) { - case 0: - return { A: deserializeU32(de) } -case 1: - return { B: deserializeS64(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +} function deserializeCasts4(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -}function deserializeCasts5(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeU32(de) } + case 1: + return { B: deserializeS64(de) } - switch (tag) { - case 0: - return { A: deserializeF32(de) } -case 1: - return { B: deserializeS64(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +} function deserializeCasts5(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -}function deserializeCasts6(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeF32(de) } + case 1: + return { B: deserializeS64(de) } - switch (tag) { - case 0: - return { A: [deserializeF32(de), deserializeU32(de)] } -case 1: - return { B: [deserializeU32(de), deserializeU32(de)] } + default: + throw new Error(`unknown variant case ${tag}`) + } +} function deserializeCasts6(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -}function deserializeMyErrno(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: [deserializeF32(de), deserializeU32(de)] } + case 1: + return { B: [deserializeU32(de), deserializeU32(de)] } - switch (tag) { - case 0: - return "Bad1" -case 1: - return "Bad2" + default: + throw new Error(`unknown variant case ${tag}`) + } +} function deserializeMyErrno(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown enum case ${tag}`) - } -}function deserializeIsClone(de) { - return { - v1: deserializeV1(de) - } -}function serializeE1(out, val) { - switch (val) { - case "A": - serializeU32(out, 0) - return + switch (tag) { + case 0: + return "Bad1" + case 1: + return "Bad2" - default: - throw new Error("unknown enum case") - } -}function serializeU1(out, val) { - if (val.U32) { + default: + throw new Error(`unknown enum case ${tag}`) + } +} function deserializeIsClone(de) { + return { + v1: deserializeV1(de) + } +} function serializeE1(out, val) { + switch (val) { + case "A": + serializeU32(out, 0) + return + + default: + throw new Error("unknown enum case") + } +} function serializeU1(out, val) { + if (val.U32) { serializeU32(out, 0); return serializeU32(out, val.U32) -} - if (val.F32) { + } + if (val.F32) { serializeU32(out, 1); return serializeF32(out, val.F32) -} - + } - throw new Error("unknown union case") -}function serializeEmpty(out, val) { - -}function serializeV1(out, val) { - if (val.A) { + + throw new Error("unknown union case") +} function serializeEmpty(out, val) { + +} function serializeV1(out, val) { + if (val.A) { serializeU32(out, 0); - return -} -if (val.B) { + + return + } + if (val.B) { serializeU32(out, 1); - return serializeU1(out, val.B) -} -if (val.C) { + serializeU1(out, val.B) + return + } + if (val.C) { serializeU32(out, 2); - return serializeE1(out, val.C) -} -if (val.D) { + serializeE1(out, val.C) + return + } + if (val.D) { serializeU32(out, 3); - return serializeString(out, val.D) -} -if (val.E) { + serializeString(out, val.D) + return + } + if (val.E) { serializeU32(out, 4); - return serializeEmpty(out, val.E) -} -if (val.F) { + serializeEmpty(out, val.E) + return + } + if (val.F) { serializeU32(out, 5); - return -} -if (val.G) { + + return + } + if (val.G) { serializeU32(out, 6); - return serializeU32(out, val.G) -} + serializeU32(out, val.G) + return + } - throw new Error("unknown variant case") -}function serializeCasts1(out, val) { - if (val.A) { + throw new Error("unknown variant case") +} function serializeCasts1(out, val) { + if (val.A) { serializeU32(out, 0); - return serializeS32(out, val.A) -} -if (val.B) { + serializeS32(out, val.A) + return + } + if (val.B) { serializeU32(out, 1); - return serializeF32(out, val.B) -} + serializeF32(out, val.B) + return + } - throw new Error("unknown variant case") -}function serializeCasts2(out, val) { - if (val.A) { + throw new Error("unknown variant case") +} function serializeCasts2(out, val) { + if (val.A) { serializeU32(out, 0); - return serializeF64(out, val.A) -} -if (val.B) { + serializeF64(out, val.A) + return + } + if (val.B) { serializeU32(out, 1); - return serializeF32(out, val.B) -} + serializeF32(out, val.B) + return + } - throw new Error("unknown variant case") -}function serializeCasts3(out, val) { - if (val.A) { + throw new Error("unknown variant case") +} function serializeCasts3(out, val) { + if (val.A) { serializeU32(out, 0); - return serializeF64(out, val.A) -} -if (val.B) { + serializeF64(out, val.A) + return + } + if (val.B) { serializeU32(out, 1); - return serializeU64(out, val.B) -} + serializeU64(out, val.B) + return + } - throw new Error("unknown variant case") -}function serializeCasts4(out, val) { - if (val.A) { + throw new Error("unknown variant case") +} function serializeCasts4(out, val) { + if (val.A) { serializeU32(out, 0); - return serializeU32(out, val.A) -} -if (val.B) { + serializeU32(out, val.A) + return + } + if (val.B) { serializeU32(out, 1); - return serializeS64(out, val.B) -} + serializeS64(out, val.B) + return + } - throw new Error("unknown variant case") -}function serializeCasts5(out, val) { - if (val.A) { + throw new Error("unknown variant case") +} function serializeCasts5(out, val) { + if (val.A) { serializeU32(out, 0); - return serializeF32(out, val.A) -} -if (val.B) { + serializeF32(out, val.A) + return + } + if (val.B) { serializeU32(out, 1); - return serializeS64(out, val.B) -} + serializeS64(out, val.B) + return + } - throw new Error("unknown variant case") -}function serializeCasts6(out, val) { - if (val.A) { + throw new Error("unknown variant case") +} function serializeCasts6(out, val) { + if (val.A) { serializeU32(out, 0); - return {serializeF32(out, val.A[0]);serializeU32(out, val.A[1])} -} -if (val.B) { + { serializeF32(out, val.A[0]); serializeU32(out, val.A[1]) } + return + } + if (val.B) { serializeU32(out, 1); - return {serializeU32(out, val.B[0]);serializeU32(out, val.B[1])} + { serializeU32(out, val.B[0]); serializeU32(out, val.B[1]) } + return + } + + + throw new Error("unknown variant case") +} function serializeIsClone(out, val) { + serializeV1(out, val.v1) } - - throw new Error("unknown variant case") -}function serializeIsClone(out, val) { - serializeV1(out, val.v1) +export enum E1 { + A, } -export enum E1 { -A, - } +export type U1 = + number + | + number + ; -export type U1 = -number - | -number -; - -export interface Empty { } +export interface Empty { } export interface V1A { tag: 0 } @@ -565,387 +584,386 @@ export interface V1F { tag: 5 } export interface V1G { tag: 6, value: number } -export type V1 = -V1A | -V1B | -V1C | -V1D | -V1E | -V1F | -V1G +export type V1 = + V1A | + V1B | + V1C | + V1D | + V1E | + V1F | + V1G export interface Casts1A { tag: 0, value: number } export interface Casts1B { tag: 1, value: number } -export type Casts1 = -Casts1A | -Casts1B +export type Casts1 = + Casts1A | + Casts1B export interface Casts2A { tag: 0, value: number } export interface Casts2B { tag: 1, value: number } -export type Casts2 = -Casts2A | -Casts2B +export type Casts2 = + Casts2A | + Casts2B export interface Casts3A { tag: 0, value: number } export interface Casts3B { tag: 1, value: bigint } -export type Casts3 = -Casts3A | -Casts3B +export type Casts3 = + Casts3A | + Casts3B export interface Casts4A { tag: 0, value: number } export interface Casts4B { tag: 1, value: bigint } -export type Casts4 = -Casts4A | -Casts4B +export type Casts4 = + Casts4A | + Casts4B export interface Casts5A { tag: 0, value: number } export interface Casts5B { tag: 1, value: bigint } -export type Casts5 = -Casts5A | -Casts5B +export type Casts5 = + Casts5A | + Casts5B export interface Casts6A { tag: 0, value: [number, number] } export interface Casts6B { tag: 1, value: [number, number] } -export type Casts6 = -Casts6A | -Casts6B +export type Casts6 = + Casts6A | + Casts6B -export enum MyErrno { -Bad1, +export enum MyErrno { + Bad1, -Bad2, - } - -export interface IsClone { -v1: V1, - } - - - -export async function e1Arg (x: E1) : Promise { - const out = [] - serializeE1(out, x) - - fetch('ipc://localhost/variants/e1_arg', { method: "POST", body: Uint8Array.from(out) }) + Bad2, } - -export async function e1Result () : Promise { - const out = [] - - - return fetch('ipc://localhost/variants/e1_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeE1(de) - }) as Promise +export interface IsClone { + v1: V1, } - -export async function u1Arg (x: U1) : Promise { - const out = [] - serializeU1(out, x) - fetch('ipc://localhost/variants/u1_arg', { method: "POST", body: Uint8Array.from(out) }) + +export async function e1Arg(x: E1): Promise { + const out = [] + serializeE1(out, x) + + fetch('ipc://localhost/variants/e1_arg', { method: "POST", body: Uint8Array.from(out) }) } - -export async function u1Result () : Promise { - const out = [] - - return fetch('ipc://localhost/variants/u1_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function e1Result(): Promise { + const out = [] - return deserializeU1(de) - }) as Promise + + return fetch('ipc://localhost/variants/e1_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeE1(de) + }) as Promise } - -export async function v1Arg (x: V1) : Promise { - const out = [] - serializeV1(out, x) - fetch('ipc://localhost/variants/v1_arg', { method: "POST", body: Uint8Array.from(out) }) +export async function u1Arg(x: U1): Promise { + const out = [] + serializeU1(out, x) + + fetch('ipc://localhost/variants/u1_arg', { method: "POST", body: Uint8Array.from(out) }) } - -export async function v1Result () : Promise { - const out = [] - - return fetch('ipc://localhost/variants/v1_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function u1Result(): Promise { + const out = [] - return deserializeV1(de) - }) as Promise + + return fetch('ipc://localhost/variants/u1_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeU1(de) + }) as Promise } - -export async function boolArg (x: boolean) : Promise { - const out = [] - serializeBool(out, x) - fetch('ipc://localhost/variants/bool_arg', { method: "POST", body: Uint8Array.from(out) }) +export async function v1Arg(x: V1): Promise { + const out = [] + serializeV1(out, x) + + fetch('ipc://localhost/variants/v1_arg', { method: "POST", body: Uint8Array.from(out) }) } - -export async function boolResult () : Promise { - const out = [] - - return fetch('ipc://localhost/variants/bool_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function v1Result(): Promise { + const out = [] - return deserializeBool(de) - }) as Promise + + return fetch('ipc://localhost/variants/v1_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeV1(de) + }) as Promise } - -export async function optionArg (a: boolean | null, b: [] | null, c: number | null, d: E1 | null, e: number | null, f: U1 | null, g: boolean | null | null) : Promise { - const out = [] - serializeOption(out, (out, v) => serializeBool(out, v), a); -serializeOption(out, (out, v) => {}, b); -serializeOption(out, (out, v) => serializeU32(out, v), c); -serializeOption(out, (out, v) => serializeE1(out, v), d); -serializeOption(out, (out, v) => serializeF32(out, v), e); -serializeOption(out, (out, v) => serializeU1(out, v), f); -serializeOption(out, (out, v) => serializeOption(out, (out, v) => serializeBool(out, v), v), g) - fetch('ipc://localhost/variants/option_arg', { method: "POST", body: Uint8Array.from(out) }) +export async function boolArg(x: boolean): Promise { + const out = [] + serializeBool(out, x) + + fetch('ipc://localhost/variants/bool_arg', { method: "POST", body: Uint8Array.from(out) }) } - -export async function optionResult () : Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> { - const out = [] - - return fetch('ipc://localhost/variants/option_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function boolResult(): Promise { + const out = [] - return [deserializeOption(de, (de) => deserializeBool(de)), deserializeOption(de, (de) => []), deserializeOption(de, (de) => deserializeU32(de)), deserializeOption(de, (de) => deserializeE1(de)), deserializeOption(de, (de) => deserializeF32(de)), deserializeOption(de, (de) => deserializeU1(de)), deserializeOption(de, (de) => deserializeOption(de, (de) => deserializeBool(de)))] - }) as Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> + + return fetch('ipc://localhost/variants/bool_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeBool(de) + }) as Promise } - -export async function casts (a: Casts1, b: Casts2, c: Casts3, d: Casts4, e: Casts5, f: Casts6) : Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> { - const out = [] - serializeCasts1(out, a); -serializeCasts2(out, b); -serializeCasts3(out, c); -serializeCasts4(out, d); -serializeCasts5(out, e); -serializeCasts6(out, f) - return fetch('ipc://localhost/variants/casts', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function optionArg(a: boolean | null, b: [] | null, c: number | null, d: E1 | null, e: number | null, f: U1 | null, g: boolean | null | null): Promise { + const out = [] + serializeOption(out, (out, v) => serializeBool(out, v), a); + serializeOption(out, (out, v) => { }, b); + serializeOption(out, (out, v) => serializeU32(out, v), c); + serializeOption(out, (out, v) => serializeE1(out, v), d); + serializeOption(out, (out, v) => serializeF32(out, v), e); + serializeOption(out, (out, v) => serializeU1(out, v), f); + serializeOption(out, (out, v) => serializeOption(out, (out, v) => serializeBool(out, v), v), g) - return [deserializeCasts1(de), deserializeCasts2(de), deserializeCasts3(de), deserializeCasts4(de), deserializeCasts5(de), deserializeCasts6(de)] - }) as Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> + fetch('ipc://localhost/variants/option_arg', { method: "POST", body: Uint8Array.from(out) }) } - -export async function resultArg (a: Result, b: Result, c: Result, d: Result<[], []>, e: Result, f: Result) : Promise { - const out = [] - serializeResult(out, (out, v) => {}, (out, v) => {}, a); -serializeResult(out, (out, v) => {}, (out, v) => serializeE1(out, v), b); -serializeResult(out, (out, v) => serializeE1(out, v), (out, v) => {}, c); -serializeResult(out, (out, v) => {}, (out, v) => {}, d); -serializeResult(out, (out, v) => serializeU32(out, v), (out, v) => serializeV1(out, v), e); -serializeResult(out, (out, v) => serializeString(out, v), (out, v) => serializeBytes(out, v), f) - fetch('ipc://localhost/variants/result_arg', { method: "POST", body: Uint8Array.from(out) }) +export async function optionResult(): Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> { + const out = [] + + + return fetch('ipc://localhost/variants/option_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return [deserializeOption(de, (de) => deserializeBool(de)), deserializeOption(de, (de) => []), deserializeOption(de, (de) => deserializeU32(de)), deserializeOption(de, (de) => deserializeE1(de)), deserializeOption(de, (de) => deserializeF32(de)), deserializeOption(de, (de) => deserializeU1(de)), deserializeOption(de, (de) => deserializeOption(de, (de) => deserializeBool(de)))] + }) as Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> } - -export async function resultResult () : Promise<[Result, Result, Result, Result<[], []>, Result, Result]> { - const out = [] - - return fetch('ipc://localhost/variants/result_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function casts(a: Casts1, b: Casts2, c: Casts3, d: Casts4, e: Casts5, f: Casts6): Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> { + const out = [] + serializeCasts1(out, a); + serializeCasts2(out, b); + serializeCasts3(out, c); + serializeCasts4(out, d); + serializeCasts5(out, e); + serializeCasts6(out, f) - return [deserializeResult(de, () => {}, () => {}), deserializeResult(de, () => {}, (de) => deserializeE1(de)), deserializeResult(de, (de) => deserializeE1(de), () => {}), deserializeResult(de, (de) => [], (de) => []), deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeV1(de)), deserializeResult(de, (de) => deserializeString(de), (de) => deserializeBytes(de))] - }) as Promise<[Result, Result, Result, Result<[], []>, Result, Result]> + return fetch('ipc://localhost/variants/casts', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return [deserializeCasts1(de), deserializeCasts2(de), deserializeCasts3(de), deserializeCasts4(de), deserializeCasts5(de), deserializeCasts6(de)] + }) as Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> } - -export async function returnResultSugar () : Promise> { - const out = [] - - return fetch('ipc://localhost/variants/return_result_sugar', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function resultArg(a: Result, b: Result, c: Result, d: Result<[], []>, e: Result, f: Result): Promise { + const out = [] + serializeResult(out, (out, v) => { }, (out, v) => { }, a); + serializeResult(out, (out, v) => { }, (out, v) => serializeE1(out, v), b); + serializeResult(out, (out, v) => serializeE1(out, v), (out, v) => { }, c); + serializeResult(out, (out, v) => { }, (out, v) => { }, d); + serializeResult(out, (out, v) => serializeU32(out, v), (out, v) => serializeV1(out, v), e); + serializeResult(out, (out, v) => serializeString(out, v), (out, v) => serializeBytes(out, v), f) - return deserializeResult(de, (de) => deserializeS32(de), (de) => deserializeMyErrno(de)) - }) as Promise> + fetch('ipc://localhost/variants/result_arg', { method: "POST", body: Uint8Array.from(out) }) } - -export async function returnResultSugar2 () : Promise> { - const out = [] - - return fetch('ipc://localhost/variants/return_result_sugar2', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function resultResult(): Promise<[Result, Result, Result, Result<[], []>, Result, Result]> { + const out = [] - return deserializeResult(de, () => {}, (de) => deserializeMyErrno(de)) - }) as Promise> + + return fetch('ipc://localhost/variants/result_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return [deserializeResult(de, () => { }, () => { }), deserializeResult(de, () => { }, (de) => deserializeE1(de)), deserializeResult(de, (de) => deserializeE1(de), () => { }), deserializeResult(de, (de) => [], (de) => []), deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeV1(de)), deserializeResult(de, (de) => deserializeString(de), (de) => deserializeBytes(de))] + }) as Promise<[Result, Result, Result, Result<[], []>, Result, Result]> } - -export async function returnResultSugar3 () : Promise> { - const out = [] - - return fetch('ipc://localhost/variants/return_result_sugar3', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function returnResultSugar(): Promise> { + const out = [] - return deserializeResult(de, (de) => deserializeMyErrno(de), (de) => deserializeMyErrno(de)) - }) as Promise> + + return fetch('ipc://localhost/variants/return_result_sugar', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => deserializeS32(de), (de) => deserializeMyErrno(de)) + }) as Promise> } - -export async function returnResultSugar4 () : Promise> { - const out = [] - - return fetch('ipc://localhost/variants/return_result_sugar4', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function returnResultSugar2(): Promise> { + const out = [] - return deserializeResult(de, (de) => [deserializeS32(de), deserializeU32(de)], (de) => deserializeMyErrno(de)) - }) as Promise> + + return fetch('ipc://localhost/variants/return_result_sugar2', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, () => { }, (de) => deserializeMyErrno(de)) + }) as Promise> } - -export async function returnOptionSugar () : Promise { - const out = [] - - return fetch('ipc://localhost/variants/return_option_sugar', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function returnResultSugar3(): Promise> { + const out = [] - return deserializeOption(de, (de) => deserializeS32(de)) - }) as Promise + + return fetch('ipc://localhost/variants/return_result_sugar3', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => deserializeMyErrno(de), (de) => deserializeMyErrno(de)) + }) as Promise> } - -export async function returnOptionSugar2 () : Promise { - const out = [] - - return fetch('ipc://localhost/variants/return_option_sugar2', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function returnResultSugar4(): Promise> { + const out = [] - return deserializeOption(de, (de) => deserializeMyErrno(de)) - }) as Promise + + return fetch('ipc://localhost/variants/return_result_sugar4', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => [deserializeS32(de), deserializeU32(de)], (de) => deserializeMyErrno(de)) + }) as Promise> } - -export async function resultSimple () : Promise> { - const out = [] - - return fetch('ipc://localhost/variants/result_simple', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function returnOptionSugar(): Promise { + const out = [] - return deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeS32(de)) - }) as Promise> + + return fetch('ipc://localhost/variants/return_option_sugar', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeOption(de, (de) => deserializeS32(de)) + }) as Promise } - -export async function isCloneArg (a: IsClone) : Promise { - const out = [] - serializeIsClone(out, a) - fetch('ipc://localhost/variants/is_clone_arg', { method: "POST", body: Uint8Array.from(out) }) +export async function returnOptionSugar2(): Promise { + const out = [] + + + return fetch('ipc://localhost/variants/return_option_sugar2', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeOption(de, (de) => deserializeMyErrno(de)) + }) as Promise } - -export async function isCloneReturn () : Promise { - const out = [] - - return fetch('ipc://localhost/variants/is_clone_return', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function resultSimple(): Promise> { + const out = [] - return deserializeIsClone(de) - }) as Promise + + return fetch('ipc://localhost/variants/result_simple', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeS32(de)) + }) as Promise> } - -export async function returnNamedOption () : Promise { - const out = [] - - return fetch('ipc://localhost/variants/return_named_option', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function isCloneArg(a: IsClone): Promise { + const out = [] + serializeIsClone(out, a) - return deserializeOption(de, (de) => deserializeU8(de)) - }) as Promise + fetch('ipc://localhost/variants/is_clone_arg', { method: "POST", body: Uint8Array.from(out) }) } - -export async function returnNamedResult () : Promise> { - const out = [] - - return fetch('ipc://localhost/variants/return_named_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) +export async function isCloneReturn(): Promise { + const out = [] - return deserializeResult(de, (de) => deserializeU8(de), (de) => deserializeMyErrno(de)) - }) as Promise> + + return fetch('ipc://localhost/variants/is_clone_return', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeIsClone(de) + }) as Promise +} + + +export async function returnNamedOption(): Promise { + const out = [] + + + return fetch('ipc://localhost/variants/return_named_option', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeOption(de, (de) => deserializeU8(de)) + }) as Promise +} + + +export async function returnNamedResult(): Promise> { + const out = [] + + + return fetch('ipc://localhost/variants/return_named_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeResult(de, (de) => deserializeU8(de), (de) => deserializeMyErrno(de)) + }) as Promise> } - \ No newline at end of file diff --git a/crates/gen-js/src/lib.rs b/crates/gen-js/src/lib.rs index 74abb18..023a2f3 100644 --- a/crates/gen-js/src/lib.rs +++ b/crates/gen-js/src/lib.rs @@ -387,7 +387,8 @@ pub trait JavaScriptGenerator { format!( "if ({prop_access}) {{ serializeU32(out, {tag}); - return {inner} + {inner} + return }} " ) From 64f3d3fc1003bbfb632b599a6f0eb6219b04e173 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Sun, 10 Sep 2023 14:00:39 +0200 Subject: [PATCH 04/13] clippy --- crates/gen-guest-ts/src/lib.rs | 3 +- crates/gen-host/src/lib.rs | 8 ++--- crates/gen-js/src/lib.rs | 5 +-- crates/host/src/lib.rs | 60 +++++++++++++++++++++++++++------- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/crates/gen-guest-ts/src/lib.rs b/crates/gen-guest-ts/src/lib.rs index a945a7c..d50cb84 100644 --- a/crates/gen-guest-ts/src/lib.rs +++ b/crates/gen-guest-ts/src/lib.rs @@ -314,8 +314,7 @@ export async function {ident} ({params}) : {result} {{ let result = func .result .as_ref() - .map(|result| self.print_function_result(result)) - .unwrap_or("void".to_string()); + .map_or("void".to_string(), |result| self.print_function_result(result)); let deserialize_result = func .result diff --git a/crates/gen-host/src/lib.rs b/crates/gen-host/src/lib.rs index aa561f5..09f2715 100644 --- a/crates/gen-host/src/lib.rs +++ b/crates/gen-host/src/lib.rs @@ -5,15 +5,13 @@ clippy::unused_self )] -use std::borrow::Cow; -use std::collections::HashSet; -use std::path::PathBuf; - use heck::ToKebabCase; use heck::{ToSnakeCase, ToUpperCamelCase}; use proc_macro2::TokenStream; use quote::format_ident; use quote::quote; +use std::collections::HashSet; +use std::path::PathBuf; use tauri_bindgen_core::{Generate, GeneratorBuilder, TypeInfo, TypeInfos}; use tauri_bindgen_gen_rust::{print_generics, BorrowMode, FnSig, RustGenerator}; use wit_parser::{Function, FunctionResult, Interface, Type, TypeDefKind}; @@ -378,7 +376,7 @@ impl Host { _ => quote! { () }, }; - let mod_name = format!("{}::resource::{}", mod_name, resource_name); + let mod_name = format!("{mod_name}::resource::{resource_name}"); let get_r_ident = format_ident!("get_{}", resource_name.to_snake_case()); quote! { diff --git a/crates/gen-js/src/lib.rs b/crates/gen-js/src/lib.rs index 023a2f3..a9a9ff2 100644 --- a/crates/gen-js/src/lib.rs +++ b/crates/gen-js/src/lib.rs @@ -741,7 +741,7 @@ impl SerdeUtils { info |= Self::collect_type_info(typedefs, &case.ty); } } - TypeDefKind::Enum(_) => { + TypeDefKind::Enum(_) | TypeDefKind::Resource(_) => { info |= SerdeUtils::U32; } TypeDefKind::Flags(fields) => { @@ -753,9 +753,6 @@ impl SerdeUtils { wit_parser::Int::U128 => SerdeUtils::U128, }; } - TypeDefKind::Resource(_) => { - info |= SerdeUtils::U32; - } } log::debug!("collected info for {:?}: {:?}", typedefs[id].ident, info,); diff --git a/crates/host/src/lib.rs b/crates/host/src/lib.rs index 775c35b..c036efe 100644 --- a/crates/host/src/lib.rs +++ b/crates/host/src/lib.rs @@ -1,4 +1,3 @@ -use std::marker::PhantomData; use std::sync::Arc; use std::sync::RwLock; use std::{any::Any, collections::HashMap}; @@ -20,7 +19,8 @@ pub struct ResourceTableInner { } impl ResourceTable { - /// Create an empty table. New insertions will begin at 3, above stdio. + /// Create an empty table. + #[must_use] pub fn new() -> Self { Self(RwLock::new(ResourceTableInner { map: HashMap::new(), @@ -29,6 +29,14 @@ impl ResourceTable { } /// Insert a resource at the next available index. + /// + /// # Errors + /// + /// Returns an error if the table is full. + /// + /// # Panics + /// + /// Panics if the resource is already borrowed. pub fn push(&self, a: Arc) -> Result { let mut inner = self.0.write().unwrap(); // NOTE: The performance of this new key calculation could be very bad once keys wrap @@ -48,12 +56,20 @@ impl ResourceTable { } /// Check if the table has a resource at the given index. + /// + /// # Panics + /// + /// Panics if the resource is already borrowed. pub fn contains_key(&self, key: ResourceId) -> bool { self.0.read().unwrap().map.contains_key(&key) } /// Check if the resource at a given index can be downcast to a given type. /// Note: this will always fail if the resource is already borrowed. + /// + /// # Panics + /// + /// Panics if the resource is already borrowed. pub fn is(&self, key: ResourceId) -> bool { if let Some(r) = self.0.read().unwrap().map.get(&key) { r.is::() @@ -64,6 +80,14 @@ impl ResourceTable { /// Get an Arc reference to a resource of a given type at a given index. Multiple /// immutable references can be borrowed at any given time. + /// + /// # Errors + /// + /// Returns an error if the resource is not of the given type. + /// + /// # Panics + /// + /// Panics if the resource is already borrowed. pub fn get(&self, key: ResourceId) -> Result> { if let Some(r) = self.0.read().unwrap().map.get(&key).cloned() { r.downcast::() @@ -74,22 +98,36 @@ impl ResourceTable { } /// Get a mutable reference to a resource of a given type at a given index. - /// Only one such reference can be borrowed at any given time. + /// + /// # Errors + /// + /// Returns an error if the resource is not of the given type or if the resource is already borrowed. + /// + /// # Panics + /// + /// Panics if the resource is already borrowed. pub fn get_mut(&mut self, key: ResourceId) -> Result<&mut T> { - let entry = match self.0.get_mut().unwrap().map.get_mut(&key) { - Some(entry) => entry, - None => return Err(anyhow::anyhow!("key not in table")), - }; - let entry = match Arc::get_mut(entry) { - Some(entry) => entry, - None => return Err(anyhow::anyhow!("cannot mutably borrow shared file")), - }; + let entry = self + .0 + .get_mut() + .unwrap() + .map + .get_mut(&key) + .ok_or(anyhow::anyhow!("key not in table"))?; + + let entry = + Arc::get_mut(entry).ok_or(anyhow::anyhow!("cannot mutably borrow shared file"))?; + entry .downcast_mut::() .ok_or_else(|| anyhow::anyhow!("element is a different type")) } /// Remove a resource at a given index from the table and returns it. + /// + /// # Panics + /// + /// Panics if the resource is already borrowed. pub fn take(&self, key: ResourceId) -> Option> { self.0 .write() From a40ec95b2dc26bf0eb8f5684f1e4fee6694f6c9e Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Sun, 10 Sep 2023 14:02:13 +0200 Subject: [PATCH 05/13] Update netlify.toml --- playground/netlify.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playground/netlify.toml b/playground/netlify.toml index b06c05b..f6115c0 100644 --- a/playground/netlify.toml +++ b/playground/netlify.toml @@ -2,10 +2,10 @@ NPM_FLAGS = "--version" # prevent Netlify npm install [build] publish = 'dist' - command = """ + command = """ cd editor npx pnpm install --store=node_modules/.pnpm-store cd .. wget -qO- https://github.com/thedodd/trunk/releases/download/v0.16.0/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- ./trunk build - """ \ No newline at end of file + """ From 4954d865f16702b28f91dd25dd4c9eec98af17cc Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Sun, 10 Sep 2023 14:29:14 +0200 Subject: [PATCH 06/13] feat(rust): implement resource --- crates/core/src/lib.rs | 5 +- crates/gen-guest-js/src/lib.rs | 17 +- crates/gen-guest-rust/src/lib.rs | 33 +- crates/gen-guest-rust/tests/resources.rs | 34 +- crates/gen-guest-ts/src/lib.rs | 17 +- crates/gen-guest-ts/tests/variants.ts | 1099 +++++++++++----------- crates/gen-host/src/lib.rs | 18 +- crates/gen-rust/src/lib.rs | 3 +- 8 files changed, 654 insertions(+), 572 deletions(-) diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index ca15c75..461dded 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -73,7 +73,10 @@ pub struct TypeInfos { impl TypeInfos { #[must_use] - pub fn collect_from_functions(typedefs: &TypeDefArena, functions: &[Function]) -> Self { + pub fn collect_from_functions<'a>( + typedefs: &TypeDefArena, + functions: impl Iterator, + ) -> Self { let mut this = Self::default(); for func in functions { diff --git a/crates/gen-guest-js/src/lib.rs b/crates/gen-guest-js/src/lib.rs index 1be9c4b..7f16a9a 100644 --- a/crates/gen-guest-js/src/lib.rs +++ b/crates/gen-guest-js/src/lib.rs @@ -23,7 +23,22 @@ pub struct Builder { impl GeneratorBuilder for Builder { fn build(self, interface: Interface) -> Box { - let infos = TypeInfos::collect_from_functions(&interface.typedefs, &interface.functions); + let methods = interface + .typedefs + .iter() + .filter_map(|(_, typedef)| { + if let TypeDefKind::Resource(methods) = &typedef.kind { + Some(methods.iter()) + } else { + None + } + }) + .flatten(); + + let infos = TypeInfos::collect_from_functions( + &interface.typedefs, + interface.functions.iter().chain(methods), + ); let serde_utils = SerdeUtils::collect_from_functions(&interface.typedefs, &interface.functions); diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index b3fdc8a..4c59b66 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -14,6 +14,7 @@ use tauri_bindgen_core::TypeInfo; use tauri_bindgen_core::TypeInfos; use tauri_bindgen_gen_rust::FnSig; use tauri_bindgen_gen_rust::{BorrowMode, RustGenerator}; +use wit_parser::TypeDefKind; use wit_parser::{Function, Interface}; #[derive(Default, Debug, Clone)] @@ -35,7 +36,22 @@ pub struct Builder { impl GeneratorBuilder for Builder { fn build(self, interface: Interface) -> Box { - let infos = TypeInfos::collect_from_functions(&interface.typedefs, &interface.functions); + let methods = interface + .typedefs + .iter() + .filter_map(|(_, typedef)| { + if let TypeDefKind::Resource(methods) = &typedef.kind { + Some(methods.iter()) + } else { + None + } + }) + .flatten(); + + let infos = TypeInfos::collect_from_functions( + &interface.typedefs, + interface.functions.iter().chain(methods), + ); Box::new(RustWasm { opts: self, @@ -117,6 +133,7 @@ impl RustGenerator for RustWasm { fn print_resource( &self, + mod_ident: &str, docs: &str, ident: &proc_macro2::Ident, functions: &[Function], @@ -139,9 +156,17 @@ impl RustGenerator for RustWasm { &BorrowMode::Owned, ); + let mod_ident = format!("{mod_ident}::resource::{}", ident.to_string().to_snake_case()); + let ident = func.ident.to_snake_case(); + + let param_idents = func + .params + .iter() + .map(|(ident, _)| format_ident!("{}", ident)); + quote! { #sig { - todo!() + ::tauri_bindgen_guest_rust::invoke(#mod_ident, #ident, &(self.0, #(#param_idents),*)).await.unwrap() } } }); @@ -149,9 +174,7 @@ impl RustGenerator for RustWasm { quote! { #docs #additional_attrs - pub struct #ident { - id: u64 - } + pub struct #ident(u32); impl #ident { #(#functions)* diff --git a/crates/gen-guest-rust/tests/resources.rs b/crates/gen-guest-rust/tests/resources.rs index e486d62..fcd2c05 100644 --- a/crates/gen-guest-rust/tests/resources.rs +++ b/crates/gen-guest-rust/tests/resources.rs @@ -3,34 +3,42 @@ pub mod resources { use ::tauri_bindgen_guest_rust::serde; use ::tauri_bindgen_guest_rust::bitflags; - #[derive(serde::Deserialize)] - pub struct A { - id: u64, - } + #[derive(serde::Serialize, serde::Deserialize)] + pub struct A(u32); impl A { pub async fn f1(&self) { - todo!() + ::tauri_bindgen_guest_rust::invoke("resources;::resource::A", "f1", &()) + .await + .unwrap() } pub async fn f2(&self, a: u32) { - todo!() + ::tauri_bindgen_guest_rust::invoke("resources;::resource::A", "f2", &(a)) + .await + .unwrap() } pub async fn f3(&self, a: u32, b: u32) { - todo!() + ::tauri_bindgen_guest_rust::invoke("resources;::resource::A", "f3", &(a, b)) + .await + .unwrap() } } #[derive(serde::Deserialize)] - pub struct B { - id: u64, - } + pub struct B(u32); impl B { pub async fn f1(&self) -> A { - todo!() + ::tauri_bindgen_guest_rust::invoke("resources;::resource::B", "f1", &()) + .await + .unwrap() } pub async fn f2(&self, x: A) -> Result { - todo!() + ::tauri_bindgen_guest_rust::invoke("resources;::resource::B", "f2", &(x)) + .await + .unwrap() } pub async fn f3(&self, x: Option<&'_ [A]>) -> Result { - todo!() + ::tauri_bindgen_guest_rust::invoke("resources;::resource::B", "f3", &(x)) + .await + .unwrap() } } pub async fn constructor_a() -> A { diff --git a/crates/gen-guest-ts/src/lib.rs b/crates/gen-guest-ts/src/lib.rs index d50cb84..d5fbd2f 100644 --- a/crates/gen-guest-ts/src/lib.rs +++ b/crates/gen-guest-ts/src/lib.rs @@ -31,7 +31,22 @@ pub struct Builder { impl GeneratorBuilder for Builder { fn build(self, interface: Interface) -> Box { - let infos = TypeInfos::collect_from_functions(&interface.typedefs, &interface.functions); + let methods = interface + .typedefs + .iter() + .filter_map(|(_, typedef)| { + if let TypeDefKind::Resource(methods) = &typedef.kind { + Some(methods.iter()) + } else { + None + } + }) + .flatten(); + + let infos = TypeInfos::collect_from_functions( + &interface.typedefs, + interface.functions.iter().chain(methods), + ); let serde_utils = SerdeUtils::collect_from_functions(&interface.typedefs, &interface.functions); diff --git a/crates/gen-guest-ts/tests/variants.ts b/crates/gen-guest-ts/tests/variants.ts index 06f5051..08e590b 100644 --- a/crates/gen-guest-ts/tests/variants.ts +++ b/crates/gen-guest-ts/tests/variants.ts @@ -1,23 +1,23 @@ // @ts-nocheck export type Result = { tag: 'ok', val: T } | { tag: 'err', val: E }; class Deserializer { - source - offset + source + offset + + constructor(bytes) { + this.source = bytes + this.offset = 0 + } - constructor(bytes) { - this.source = bytes - this.offset = 0 - } + pop() { + return this.source[this.offset++] + } - pop() { - return this.source[this.offset++] - } - - try_take_n(len) { - const out = this.source.slice(this.offset, this.offset + len) - this.offset += len - return out - } + try_take_n(len) { + const out = this.source.slice(this.offset, this.offset + len) + this.offset += len + return out + } } // function varint_max(bits) { // const BITS_PER_BYTE = 8; @@ -79,31 +79,31 @@ function de_varint_big(de, bits) { throw new Error('deserialize bad variant') } function deserializeBool(de) { - const val = de.pop(); + const val = de.pop(); - return val != 0 + return val != 0 } function deserializeU8(de) { - return de.pop() + return de.pop() } function deserializeU32(de) { - return de_varint(de, 32) + return de_varint(de, 32) } function deserializeU64(de) { return de_varint_big(de, 64) } function deserializeS8(de) { - const buf = new ArrayBuffer(1); - const view = new DataView(buf); + const buf = new ArrayBuffer(1); + const view = new DataView(buf); - buf[0] = view.setUint8(0, de.pop()); + buf[0] = view.setUint8(0, de.pop()); - return view.getInt8(0); + return view.getInt8(0); } function deserializeS32(de) { - const n = de_varint(de, 32) + const n = de_varint(de, 32) - return Number(((n >> 1) & 0xFFFFFFFF) ^ (-((n & 0b1) & 0xFFFFFFFF))) + return Number(((n >> 1) & 0xFFFFFFFF) ^ (-((n & 0b1) & 0xFFFFFFFF))) } function deserializeS64(de) { const n = de_varint_big(de, 64) @@ -111,62 +111,62 @@ function deserializeS64(de) { return ((n >> 1n) & 0xFFFFFFFFFFFFFFFFn) ^ (-((n & 0b1n) & 0xFFFFFFFFFFFFFFFFn)) } function deserializeF32(de) { - const bytes = de.try_take_n(4); + const bytes = de.try_take_n(4); - const buf = new ArrayBuffer(4); - const view = new DataView(buf); + const buf = new ArrayBuffer(4); + const view = new DataView(buf); - bytes.forEach((v, i) => view.setUint8(i, v)); + bytes.forEach((v, i) => view.setUint8(i, v)); - return view.getFloat32(0, true); + return view.getFloat32(0, true); } function deserializeF64(de) { - const bytes = de.try_take_n(8); + const bytes = de.try_take_n(8); - const buf = new ArrayBuffer(8); - const view = new DataView(buf); + const buf = new ArrayBuffer(8); + const view = new DataView(buf); - bytes.forEach((v, i) => view.setUint8(i, v)); + bytes.forEach((v, i) => view.setUint8(i, v)); - return view.getFloat64(0, true); + return view.getFloat64(0, true); } function deserializeString(de) { - const sz = deserializeU64(de); + const sz = deserializeU64(de); - let bytes = de.try_take_n(Number(sz)); + let bytes = de.try_take_n(Number(sz)); - return __text_decoder.decode(bytes); + return __text_decoder.decode(bytes); } function deserializeBytes(de) { - const sz = deserializeU64(de); + const sz = deserializeU64(de); - let bytes = de.try_take_n(Number(sz)); + let bytes = de.try_take_n(Number(sz)); - return bytes; + return bytes; } function deserializeOption(de, inner) { - const tag = de.pop() + const tag = de.pop() - switch (tag) { - case 0: - return null - case 1: - return inner(de) - default: - throw new Error(`Deserialize bad option ${tag}`) - } + switch (tag) { + case 0: + return null + case 1: + return inner(de) + default: + throw new Error(`Deserialize bad option ${tag}`) + } } function deserializeResult(de, ok, err) { - const tag = de.pop() + const tag = de.pop() - switch (tag) { - case 0: - return { tag: 'ok', val: ok(de) } - case 1: - return { tag: 'err', val: err(de) } - default: - throw new Error(`Deserialize bad result ${tag}`) - } + switch (tag) { + case 0: + return { tag: 'ok', val: ok(de) } + case 1: + return { tag: 'err', val: err(de) } + default: + throw new Error(`Deserialize bad result ${tag}`) + } } function ser_varint(out, bits, val) { let buf = [] @@ -204,370 +204,370 @@ function ser_varint_big(out, bits, val) { out.push(...buf) } function serializeBool(out, val) { - out.push(val === true ? 1 : 0) + out.push(val === true ? 1 : 0) } function serializeU8(out, val) { - return out.push(val) + return out.push(val) } function serializeU32(out, val) { - return ser_varint(out, 32, val) + return ser_varint(out, 32, val) } function serializeU64(out, val) { return ser_varint_big(out, 64, BigInt(val)) } function serializeS8(out, val) { - out.push(val) + out.push(val) } function serializeS32(out, val) { - ser_varint(out, 32, (val << 1) ^ (val >> 31)) + ser_varint(out, 32, (val << 1) ^ (val >> 31)) } function serializeS64(out, val) { val = BigInt(val) ser_varint_big(out, 64, (val << 1n) ^ (val >> 63n)) } function serializeF32(out, val) { - const buf = new ArrayBuffer(4); - const view = new DataView(buf); + const buf = new ArrayBuffer(4); + const view = new DataView(buf); - view.setFloat32(0, val, true); + view.setFloat32(0, val, true); - out.push(...new Uint8Array(buf)) + out.push(...new Uint8Array(buf)) } function serializeF64(out, val) { - const buf = new ArrayBuffer(8); - const view = new DataView(buf); + const buf = new ArrayBuffer(8); + const view = new DataView(buf); - view.setFloat64(0, val, true); + view.setFloat64(0, val, true); - out.push(...new Uint8Array(buf)) + out.push(...new Uint8Array(buf)) } function serializeString(out, val) { - serializeU64(out, val.length); + serializeU64(out, val.length); - out.push(...__text_encoder.encode(val)) + out.push(...__text_encoder.encode(val)) } function serializeBytes(out, val) { - serializeU64(out, val.length); - out.push(...val) + serializeU64(out, val.length); + out.push(...val) } function serializeOption(out, inner, val) { - serializeU8(out, !!val ? 1 : 0) - if (val) { - inner(out, val) - } + serializeU8(out, !!val ? 1 : 0) + if (val) { + inner(out, val) + } } function serializeResult(out, ok, err, val) { - if (val.Ok) { - serializeU8(out, 0); - return ok(out, val.Ok); - } + if (val.Ok) { + serializeU8(out, 0); + return ok(out, val.Ok); + } - if (val.Err) { - serializeU8(out, 1); - return err(out, val.Err); - } + if (val.Err) { + serializeU8(out, 1); + return err(out, val.Err); + } - throw new Error(`Serialize bad result ${val}`); + throw new Error(`Serialize bad result ${val}`); } const __text_decoder = new TextDecoder('utf-8'); const __text_encoder = new TextEncoder(); function deserializeE1(de) { - const tag = deserializeU32(de) + const tag = deserializeU32(de) - switch (tag) { - case 0: - return "A" + switch (tag) { + case 0: + return "A" - default: - throw new Error(`unknown enum case ${tag}`) - } -} function deserializeU1(de) { - const tag = deserializeU32(de) + default: + throw new Error(`unknown enum case ${tag}`) + } +}function deserializeU1(de) { + const tag = deserializeU32(de) - switch (tag) { - case 0: - return { U32: deserializeU32(de) } - case 1: - return { F32: deserializeF32(de) } + switch (tag) { + case 0: + return { U32: deserializeU32(de) } +case 1: + return { F32: deserializeF32(de) } - default: - throw new Error(`unknown union case ${tag}`) - } -} function deserializeEmpty(de) { - return { + default: + throw new Error(`unknown union case ${tag}`) + } +}function deserializeEmpty(de) { + return { + + } +}function deserializeV1(de) { + const tag = deserializeU32(de) - } -} function deserializeV1(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: null } +case 1: + return { B: deserializeU1(de) } +case 2: + return { C: deserializeE1(de) } +case 3: + return { D: deserializeString(de) } +case 4: + return { E: deserializeEmpty(de) } +case 5: + return { F: null } +case 6: + return { G: deserializeU32(de) } - switch (tag) { - case 0: - return { A: null } - case 1: - return { B: deserializeU1(de) } - case 2: - return { C: deserializeE1(de) } - case 3: - return { D: deserializeString(de) } - case 4: - return { E: deserializeEmpty(de) } - case 5: - return { F: null } - case 6: - return { G: deserializeU32(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +}function deserializeCasts1(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -} function deserializeCasts1(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeS32(de) } +case 1: + return { B: deserializeF32(de) } - switch (tag) { - case 0: - return { A: deserializeS32(de) } - case 1: - return { B: deserializeF32(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +}function deserializeCasts2(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -} function deserializeCasts2(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeF64(de) } +case 1: + return { B: deserializeF32(de) } - switch (tag) { - case 0: - return { A: deserializeF64(de) } - case 1: - return { B: deserializeF32(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +}function deserializeCasts3(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -} function deserializeCasts3(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeF64(de) } +case 1: + return { B: deserializeU64(de) } - switch (tag) { - case 0: - return { A: deserializeF64(de) } - case 1: - return { B: deserializeU64(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +}function deserializeCasts4(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -} function deserializeCasts4(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeU32(de) } +case 1: + return { B: deserializeS64(de) } - switch (tag) { - case 0: - return { A: deserializeU32(de) } - case 1: - return { B: deserializeS64(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +}function deserializeCasts5(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -} function deserializeCasts5(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: deserializeF32(de) } +case 1: + return { B: deserializeS64(de) } - switch (tag) { - case 0: - return { A: deserializeF32(de) } - case 1: - return { B: deserializeS64(de) } + default: + throw new Error(`unknown variant case ${tag}`) + } +}function deserializeCasts6(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -} function deserializeCasts6(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return { A: [deserializeF32(de), deserializeU32(de)] } +case 1: + return { B: [deserializeU32(de), deserializeU32(de)] } - switch (tag) { - case 0: - return { A: [deserializeF32(de), deserializeU32(de)] } - case 1: - return { B: [deserializeU32(de), deserializeU32(de)] } + default: + throw new Error(`unknown variant case ${tag}`) + } +}function deserializeMyErrno(de) { + const tag = deserializeU32(de) - default: - throw new Error(`unknown variant case ${tag}`) - } -} function deserializeMyErrno(de) { - const tag = deserializeU32(de) + switch (tag) { + case 0: + return "Bad1" +case 1: + return "Bad2" - switch (tag) { - case 0: - return "Bad1" - case 1: - return "Bad2" + default: + throw new Error(`unknown enum case ${tag}`) + } +}function deserializeIsClone(de) { + return { + v1: deserializeV1(de) + } +}function serializeE1(out, val) { + switch (val) { + case "A": + serializeU32(out, 0) + return - default: - throw new Error(`unknown enum case ${tag}`) - } -} function deserializeIsClone(de) { - return { - v1: deserializeV1(de) - } -} function serializeE1(out, val) { - switch (val) { - case "A": - serializeU32(out, 0) - return - - default: - throw new Error("unknown enum case") - } -} function serializeU1(out, val) { - if (val.U32) { + default: + throw new Error("unknown enum case") + } +}function serializeU1(out, val) { + if (val.U32) { serializeU32(out, 0); return serializeU32(out, val.U32) - } - if (val.F32) { +} + if (val.F32) { serializeU32(out, 1); return serializeF32(out, val.F32) - } +} + - - throw new Error("unknown union case") -} function serializeEmpty(out, val) { - -} function serializeV1(out, val) { - if (val.A) { + throw new Error("unknown union case") +}function serializeEmpty(out, val) { + +}function serializeV1(out, val) { + if (val.A) { serializeU32(out, 0); - + return - } - if (val.B) { +} +if (val.B) { serializeU32(out, 1); serializeU1(out, val.B) return - } - if (val.C) { +} +if (val.C) { serializeU32(out, 2); serializeE1(out, val.C) return - } - if (val.D) { +} +if (val.D) { serializeU32(out, 3); serializeString(out, val.D) return - } - if (val.E) { +} +if (val.E) { serializeU32(out, 4); serializeEmpty(out, val.E) return - } - if (val.F) { +} +if (val.F) { serializeU32(out, 5); - + return - } - if (val.G) { +} +if (val.G) { serializeU32(out, 6); serializeU32(out, val.G) return - } +} - throw new Error("unknown variant case") -} function serializeCasts1(out, val) { - if (val.A) { + throw new Error("unknown variant case") +}function serializeCasts1(out, val) { + if (val.A) { serializeU32(out, 0); serializeS32(out, val.A) return - } - if (val.B) { +} +if (val.B) { serializeU32(out, 1); serializeF32(out, val.B) return - } +} - throw new Error("unknown variant case") -} function serializeCasts2(out, val) { - if (val.A) { + throw new Error("unknown variant case") +}function serializeCasts2(out, val) { + if (val.A) { serializeU32(out, 0); serializeF64(out, val.A) return - } - if (val.B) { +} +if (val.B) { serializeU32(out, 1); serializeF32(out, val.B) return - } +} - throw new Error("unknown variant case") -} function serializeCasts3(out, val) { - if (val.A) { + throw new Error("unknown variant case") +}function serializeCasts3(out, val) { + if (val.A) { serializeU32(out, 0); serializeF64(out, val.A) return - } - if (val.B) { +} +if (val.B) { serializeU32(out, 1); serializeU64(out, val.B) return - } +} - throw new Error("unknown variant case") -} function serializeCasts4(out, val) { - if (val.A) { + throw new Error("unknown variant case") +}function serializeCasts4(out, val) { + if (val.A) { serializeU32(out, 0); serializeU32(out, val.A) return - } - if (val.B) { +} +if (val.B) { serializeU32(out, 1); serializeS64(out, val.B) return - } +} - throw new Error("unknown variant case") -} function serializeCasts5(out, val) { - if (val.A) { + throw new Error("unknown variant case") +}function serializeCasts5(out, val) { + if (val.A) { serializeU32(out, 0); serializeF32(out, val.A) return - } - if (val.B) { +} +if (val.B) { serializeU32(out, 1); serializeS64(out, val.B) return - } +} - throw new Error("unknown variant case") -} function serializeCasts6(out, val) { - if (val.A) { + throw new Error("unknown variant case") +}function serializeCasts6(out, val) { + if (val.A) { serializeU32(out, 0); - { serializeF32(out, val.A[0]); serializeU32(out, val.A[1]) } + {serializeF32(out, val.A[0]);serializeU32(out, val.A[1])} return - } - if (val.B) { +} +if (val.B) { serializeU32(out, 1); - { serializeU32(out, val.B[0]); serializeU32(out, val.B[1]) } + {serializeU32(out, val.B[0]);serializeU32(out, val.B[1])} return - } - - - throw new Error("unknown variant case") -} function serializeIsClone(out, val) { - serializeV1(out, val.v1) } -export enum E1 { - A, + + throw new Error("unknown variant case") +}function serializeIsClone(out, val) { + serializeV1(out, val.v1) } -export type U1 = - number - | - number - ; +export enum E1 { +A, + } -export interface Empty { } +export type U1 = +number + | +number +; + +export interface Empty { } export interface V1A { tag: 0 } @@ -584,386 +584,387 @@ export interface V1F { tag: 5 } export interface V1G { tag: 6, value: number } -export type V1 = - V1A | - V1B | - V1C | - V1D | - V1E | - V1F | - V1G +export type V1 = +V1A | +V1B | +V1C | +V1D | +V1E | +V1F | +V1G export interface Casts1A { tag: 0, value: number } export interface Casts1B { tag: 1, value: number } -export type Casts1 = - Casts1A | - Casts1B +export type Casts1 = +Casts1A | +Casts1B export interface Casts2A { tag: 0, value: number } export interface Casts2B { tag: 1, value: number } -export type Casts2 = - Casts2A | - Casts2B +export type Casts2 = +Casts2A | +Casts2B export interface Casts3A { tag: 0, value: number } export interface Casts3B { tag: 1, value: bigint } -export type Casts3 = - Casts3A | - Casts3B +export type Casts3 = +Casts3A | +Casts3B export interface Casts4A { tag: 0, value: number } export interface Casts4B { tag: 1, value: bigint } -export type Casts4 = - Casts4A | - Casts4B +export type Casts4 = +Casts4A | +Casts4B export interface Casts5A { tag: 0, value: number } export interface Casts5B { tag: 1, value: bigint } -export type Casts5 = - Casts5A | - Casts5B +export type Casts5 = +Casts5A | +Casts5B export interface Casts6A { tag: 0, value: [number, number] } export interface Casts6B { tag: 1, value: [number, number] } -export type Casts6 = - Casts6A | - Casts6B +export type Casts6 = +Casts6A | +Casts6B -export enum MyErrno { - Bad1, +export enum MyErrno { +Bad1, - Bad2, +Bad2, + } + +export interface IsClone { +v1: V1, + } + + + +export async function e1Arg (x: E1) : Promise { + const out = [] + serializeE1(out, x) + + fetch('ipc://localhost/variants/e1_arg', { method: "POST", body: Uint8Array.from(out) }) } + -export interface IsClone { - v1: V1, +export async function e1Result () : Promise { + const out = [] + + + return fetch('ipc://localhost/variants/e1_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) + + return deserializeE1(de) + }) as Promise } + +export async function u1Arg (x: U1) : Promise { + const out = [] + serializeU1(out, x) - -export async function e1Arg(x: E1): Promise { - const out = [] - serializeE1(out, x) - - fetch('ipc://localhost/variants/e1_arg', { method: "POST", body: Uint8Array.from(out) }) + fetch('ipc://localhost/variants/u1_arg', { method: "POST", body: Uint8Array.from(out) }) } + +export async function u1Result () : Promise { + const out = [] + -export async function e1Result(): Promise { - const out = [] + return fetch('ipc://localhost/variants/u1_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/e1_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeE1(de) - }) as Promise + return deserializeU1(de) + }) as Promise } + +export async function v1Arg (x: V1) : Promise { + const out = [] + serializeV1(out, x) -export async function u1Arg(x: U1): Promise { - const out = [] - serializeU1(out, x) - - fetch('ipc://localhost/variants/u1_arg', { method: "POST", body: Uint8Array.from(out) }) + fetch('ipc://localhost/variants/v1_arg', { method: "POST", body: Uint8Array.from(out) }) } + +export async function v1Result () : Promise { + const out = [] + -export async function u1Result(): Promise { - const out = [] + return fetch('ipc://localhost/variants/v1_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/u1_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeU1(de) - }) as Promise + return deserializeV1(de) + }) as Promise } + +export async function boolArg (x: boolean) : Promise { + const out = [] + serializeBool(out, x) -export async function v1Arg(x: V1): Promise { - const out = [] - serializeV1(out, x) - - fetch('ipc://localhost/variants/v1_arg', { method: "POST", body: Uint8Array.from(out) }) + fetch('ipc://localhost/variants/bool_arg', { method: "POST", body: Uint8Array.from(out) }) } + +export async function boolResult () : Promise { + const out = [] + -export async function v1Result(): Promise { - const out = [] + return fetch('ipc://localhost/variants/bool_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/v1_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeV1(de) - }) as Promise + return deserializeBool(de) + }) as Promise } + +export async function optionArg (a: boolean | null, b: [] | null, c: number | null, d: E1 | null, e: number | null, f: U1 | null, g: boolean | null | null) : Promise { + const out = [] + serializeOption(out, (out, v) => serializeBool(out, v), a); +serializeOption(out, (out, v) => {}, b); +serializeOption(out, (out, v) => serializeU32(out, v), c); +serializeOption(out, (out, v) => serializeE1(out, v), d); +serializeOption(out, (out, v) => serializeF32(out, v), e); +serializeOption(out, (out, v) => serializeU1(out, v), f); +serializeOption(out, (out, v) => serializeOption(out, (out, v) => serializeBool(out, v), v), g) -export async function boolArg(x: boolean): Promise { - const out = [] - serializeBool(out, x) - - fetch('ipc://localhost/variants/bool_arg', { method: "POST", body: Uint8Array.from(out) }) + fetch('ipc://localhost/variants/option_arg', { method: "POST", body: Uint8Array.from(out) }) } + +export async function optionResult () : Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> { + const out = [] + -export async function boolResult(): Promise { - const out = [] + return fetch('ipc://localhost/variants/option_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/bool_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeBool(de) - }) as Promise + return [deserializeOption(de, (de) => deserializeBool(de)), deserializeOption(de, (de) => []), deserializeOption(de, (de) => deserializeU32(de)), deserializeOption(de, (de) => deserializeE1(de)), deserializeOption(de, (de) => deserializeF32(de)), deserializeOption(de, (de) => deserializeU1(de)), deserializeOption(de, (de) => deserializeOption(de, (de) => deserializeBool(de)))] + }) as Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> } + +export async function casts (a: Casts1, b: Casts2, c: Casts3, d: Casts4, e: Casts5, f: Casts6) : Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> { + const out = [] + serializeCasts1(out, a); +serializeCasts2(out, b); +serializeCasts3(out, c); +serializeCasts4(out, d); +serializeCasts5(out, e); +serializeCasts6(out, f) -export async function optionArg(a: boolean | null, b: [] | null, c: number | null, d: E1 | null, e: number | null, f: U1 | null, g: boolean | null | null): Promise { - const out = [] - serializeOption(out, (out, v) => serializeBool(out, v), a); - serializeOption(out, (out, v) => { }, b); - serializeOption(out, (out, v) => serializeU32(out, v), c); - serializeOption(out, (out, v) => serializeE1(out, v), d); - serializeOption(out, (out, v) => serializeF32(out, v), e); - serializeOption(out, (out, v) => serializeU1(out, v), f); - serializeOption(out, (out, v) => serializeOption(out, (out, v) => serializeBool(out, v), v), g) + return fetch('ipc://localhost/variants/casts', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - fetch('ipc://localhost/variants/option_arg', { method: "POST", body: Uint8Array.from(out) }) + return [deserializeCasts1(de), deserializeCasts2(de), deserializeCasts3(de), deserializeCasts4(de), deserializeCasts5(de), deserializeCasts6(de)] + }) as Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> } + +export async function resultArg (a: Result, b: Result, c: Result, d: Result<[], []>, e: Result, f: Result) : Promise { + const out = [] + serializeResult(out, (out, v) => {}, (out, v) => {}, a); +serializeResult(out, (out, v) => {}, (out, v) => serializeE1(out, v), b); +serializeResult(out, (out, v) => serializeE1(out, v), (out, v) => {}, c); +serializeResult(out, (out, v) => {}, (out, v) => {}, d); +serializeResult(out, (out, v) => serializeU32(out, v), (out, v) => serializeV1(out, v), e); +serializeResult(out, (out, v) => serializeString(out, v), (out, v) => serializeBytes(out, v), f) -export async function optionResult(): Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> { - const out = [] - - - return fetch('ipc://localhost/variants/option_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return [deserializeOption(de, (de) => deserializeBool(de)), deserializeOption(de, (de) => []), deserializeOption(de, (de) => deserializeU32(de)), deserializeOption(de, (de) => deserializeE1(de)), deserializeOption(de, (de) => deserializeF32(de)), deserializeOption(de, (de) => deserializeU1(de)), deserializeOption(de, (de) => deserializeOption(de, (de) => deserializeBool(de)))] - }) as Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]> + fetch('ipc://localhost/variants/result_arg', { method: "POST", body: Uint8Array.from(out) }) } + +export async function resultResult () : Promise<[Result, Result, Result, Result<[], []>, Result, Result]> { + const out = [] + -export async function casts(a: Casts1, b: Casts2, c: Casts3, d: Casts4, e: Casts5, f: Casts6): Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> { - const out = [] - serializeCasts1(out, a); - serializeCasts2(out, b); - serializeCasts3(out, c); - serializeCasts4(out, d); - serializeCasts5(out, e); - serializeCasts6(out, f) + return fetch('ipc://localhost/variants/result_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - return fetch('ipc://localhost/variants/casts', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return [deserializeCasts1(de), deserializeCasts2(de), deserializeCasts3(de), deserializeCasts4(de), deserializeCasts5(de), deserializeCasts6(de)] - }) as Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]> + return [deserializeResult(de, () => {}, () => {}), deserializeResult(de, () => {}, (de) => deserializeE1(de)), deserializeResult(de, (de) => deserializeE1(de), () => {}), deserializeResult(de, (de) => [], (de) => []), deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeV1(de)), deserializeResult(de, (de) => deserializeString(de), (de) => deserializeBytes(de))] + }) as Promise<[Result, Result, Result, Result<[], []>, Result, Result]> } + +export async function returnResultSugar () : Promise> { + const out = [] + -export async function resultArg(a: Result, b: Result, c: Result, d: Result<[], []>, e: Result, f: Result): Promise { - const out = [] - serializeResult(out, (out, v) => { }, (out, v) => { }, a); - serializeResult(out, (out, v) => { }, (out, v) => serializeE1(out, v), b); - serializeResult(out, (out, v) => serializeE1(out, v), (out, v) => { }, c); - serializeResult(out, (out, v) => { }, (out, v) => { }, d); - serializeResult(out, (out, v) => serializeU32(out, v), (out, v) => serializeV1(out, v), e); - serializeResult(out, (out, v) => serializeString(out, v), (out, v) => serializeBytes(out, v), f) + return fetch('ipc://localhost/variants/return_result_sugar', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - fetch('ipc://localhost/variants/result_arg', { method: "POST", body: Uint8Array.from(out) }) + return deserializeResult(de, (de) => deserializeS32(de), (de) => deserializeMyErrno(de)) + }) as Promise> } + +export async function returnResultSugar2 () : Promise> { + const out = [] + -export async function resultResult(): Promise<[Result, Result, Result, Result<[], []>, Result, Result]> { - const out = [] + return fetch('ipc://localhost/variants/return_result_sugar2', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/result_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return [deserializeResult(de, () => { }, () => { }), deserializeResult(de, () => { }, (de) => deserializeE1(de)), deserializeResult(de, (de) => deserializeE1(de), () => { }), deserializeResult(de, (de) => [], (de) => []), deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeV1(de)), deserializeResult(de, (de) => deserializeString(de), (de) => deserializeBytes(de))] - }) as Promise<[Result, Result, Result, Result<[], []>, Result, Result]> + return deserializeResult(de, () => {}, (de) => deserializeMyErrno(de)) + }) as Promise> } + +export async function returnResultSugar3 () : Promise> { + const out = [] + -export async function returnResultSugar(): Promise> { - const out = [] + return fetch('ipc://localhost/variants/return_result_sugar3', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/return_result_sugar', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeResult(de, (de) => deserializeS32(de), (de) => deserializeMyErrno(de)) - }) as Promise> + return deserializeResult(de, (de) => deserializeMyErrno(de), (de) => deserializeMyErrno(de)) + }) as Promise> } + +export async function returnResultSugar4 () : Promise> { + const out = [] + -export async function returnResultSugar2(): Promise> { - const out = [] + return fetch('ipc://localhost/variants/return_result_sugar4', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/return_result_sugar2', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeResult(de, () => { }, (de) => deserializeMyErrno(de)) - }) as Promise> + return deserializeResult(de, (de) => [deserializeS32(de), deserializeU32(de)], (de) => deserializeMyErrno(de)) + }) as Promise> } + +export async function returnOptionSugar () : Promise { + const out = [] + -export async function returnResultSugar3(): Promise> { - const out = [] + return fetch('ipc://localhost/variants/return_option_sugar', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/return_result_sugar3', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeResult(de, (de) => deserializeMyErrno(de), (de) => deserializeMyErrno(de)) - }) as Promise> + return deserializeOption(de, (de) => deserializeS32(de)) + }) as Promise } + +export async function returnOptionSugar2 () : Promise { + const out = [] + -export async function returnResultSugar4(): Promise> { - const out = [] + return fetch('ipc://localhost/variants/return_option_sugar2', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/return_result_sugar4', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeResult(de, (de) => [deserializeS32(de), deserializeU32(de)], (de) => deserializeMyErrno(de)) - }) as Promise> + return deserializeOption(de, (de) => deserializeMyErrno(de)) + }) as Promise } + +export async function resultSimple () : Promise> { + const out = [] + -export async function returnOptionSugar(): Promise { - const out = [] + return fetch('ipc://localhost/variants/result_simple', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/return_option_sugar', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeOption(de, (de) => deserializeS32(de)) - }) as Promise + return deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeS32(de)) + }) as Promise> } + +export async function isCloneArg (a: IsClone) : Promise { + const out = [] + serializeIsClone(out, a) -export async function returnOptionSugar2(): Promise { - const out = [] - - - return fetch('ipc://localhost/variants/return_option_sugar2', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeOption(de, (de) => deserializeMyErrno(de)) - }) as Promise + fetch('ipc://localhost/variants/is_clone_arg', { method: "POST", body: Uint8Array.from(out) }) } + +export async function isCloneReturn () : Promise { + const out = [] + -export async function resultSimple(): Promise> { - const out = [] + return fetch('ipc://localhost/variants/is_clone_return', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/result_simple', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeResult(de, (de) => deserializeU32(de), (de) => deserializeS32(de)) - }) as Promise> + return deserializeIsClone(de) + }) as Promise } + +export async function returnNamedOption () : Promise { + const out = [] + -export async function isCloneArg(a: IsClone): Promise { - const out = [] - serializeIsClone(out, a) + return fetch('ipc://localhost/variants/return_named_option', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - fetch('ipc://localhost/variants/is_clone_arg', { method: "POST", body: Uint8Array.from(out) }) + return deserializeOption(de, (de) => deserializeU8(de)) + }) as Promise } + +export async function returnNamedResult () : Promise> { + const out = [] + -export async function isCloneReturn(): Promise { - const out = [] + return fetch('ipc://localhost/variants/return_named_result', { method: "POST", body: Uint8Array.from(out) }) + .then(r => r.arrayBuffer()) + .then(bytes => { + const de = new Deserializer(new Uint8Array(bytes)) - - return fetch('ipc://localhost/variants/is_clone_return', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeIsClone(de) - }) as Promise -} - - -export async function returnNamedOption(): Promise { - const out = [] - - - return fetch('ipc://localhost/variants/return_named_option', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeOption(de, (de) => deserializeU8(de)) - }) as Promise -} - - -export async function returnNamedResult(): Promise> { - const out = [] - - - return fetch('ipc://localhost/variants/return_named_result', { method: "POST", body: Uint8Array.from(out) }) - .then(r => r.arrayBuffer()) - .then(bytes => { - const de = new Deserializer(new Uint8Array(bytes)) - - return deserializeResult(de, (de) => deserializeU8(de), (de) => deserializeMyErrno(de)) - }) as Promise> + return deserializeResult(de, (de) => deserializeU8(de), (de) => deserializeMyErrno(de)) + }) as Promise> } + \ No newline at end of file diff --git a/crates/gen-host/src/lib.rs b/crates/gen-host/src/lib.rs index 09f2715..85cd0b9 100644 --- a/crates/gen-host/src/lib.rs +++ b/crates/gen-host/src/lib.rs @@ -34,7 +34,22 @@ pub struct Builder { impl GeneratorBuilder for Builder { fn build(self, interface: Interface) -> Box { - let infos = TypeInfos::collect_from_functions(&interface.typedefs, &interface.functions); + let methods = interface + .typedefs + .iter() + .filter_map(|(_, typedef)| { + if let TypeDefKind::Resource(methods) = &typedef.kind { + Some(methods.iter()) + } else { + None + } + }) + .flatten(); + + let infos = TypeInfos::collect_from_functions( + &interface.typedefs, + interface.functions.iter().chain(methods), + ); Box::new(Host { opts: self, @@ -85,6 +100,7 @@ impl RustGenerator for Host { fn print_resource( &self, + _mod_ident: &str, docs: &str, ident: &proc_macro2::Ident, functions: &[Function], diff --git a/crates/gen-rust/src/lib.rs b/crates/gen-rust/src/lib.rs index de95539..cf804d0 100644 --- a/crates/gen-rust/src/lib.rs +++ b/crates/gen-rust/src/lib.rs @@ -19,6 +19,7 @@ pub trait RustGenerator { fn default_param_mode(&self) -> BorrowMode; fn print_resource( &self, + print_resource: &str, docs: &str, ident: &Ident, functions: &[Function], @@ -63,7 +64,7 @@ pub trait RustGenerator { self.print_union(docs, &ident, cases, info, &borrow_mode) } TypeDefKind::Resource(functions) => { - self.print_resource(docs, &ident, functions, info) + self.print_resource(&self.interface().ident, docs, &ident, functions, info) } }; From 2b8bef5961920d73fb53ae76149b0ca87c99b47e Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Sun, 10 Sep 2023 14:30:27 +0200 Subject: [PATCH 07/13] Update resources.rs --- crates/gen-guest-rust/tests/resources.rs | 36 ++++++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/crates/gen-guest-rust/tests/resources.rs b/crates/gen-guest-rust/tests/resources.rs index fcd2c05..473d50b 100644 --- a/crates/gen-guest-rust/tests/resources.rs +++ b/crates/gen-guest-rust/tests/resources.rs @@ -7,17 +7,29 @@ pub mod resources { pub struct A(u32); impl A { pub async fn f1(&self) { - ::tauri_bindgen_guest_rust::invoke("resources;::resource::A", "f1", &()) + ::tauri_bindgen_guest_rust::invoke( + "resources::resource::a", + "f1", + &(self.0,), + ) .await .unwrap() } pub async fn f2(&self, a: u32) { - ::tauri_bindgen_guest_rust::invoke("resources;::resource::A", "f2", &(a)) + ::tauri_bindgen_guest_rust::invoke( + "resources::resource::a", + "f2", + &(self.0, a), + ) .await .unwrap() } pub async fn f3(&self, a: u32, b: u32) { - ::tauri_bindgen_guest_rust::invoke("resources;::resource::A", "f3", &(a, b)) + ::tauri_bindgen_guest_rust::invoke( + "resources::resource::a", + "f3", + &(self.0, a, b), + ) .await .unwrap() } @@ -26,17 +38,29 @@ pub mod resources { pub struct B(u32); impl B { pub async fn f1(&self) -> A { - ::tauri_bindgen_guest_rust::invoke("resources;::resource::B", "f1", &()) + ::tauri_bindgen_guest_rust::invoke( + "resources::resource::b", + "f1", + &(self.0,), + ) .await .unwrap() } pub async fn f2(&self, x: A) -> Result { - ::tauri_bindgen_guest_rust::invoke("resources;::resource::B", "f2", &(x)) + ::tauri_bindgen_guest_rust::invoke( + "resources::resource::b", + "f2", + &(self.0, x), + ) .await .unwrap() } pub async fn f3(&self, x: Option<&'_ [A]>) -> Result { - ::tauri_bindgen_guest_rust::invoke("resources;::resource::B", "f3", &(x)) + ::tauri_bindgen_guest_rust::invoke( + "resources::resource::b", + "f3", + &(self.0, x), + ) .await .unwrap() } From 474e4898c03736d8b07b3cd0e723ea79bb16e948 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Wed, 31 May 2023 16:09:08 +0200 Subject: [PATCH 08/13] feat: add markdown docs output to playground --- playground/Cargo.toml | 3 +- playground/editor/pnpm-lock.yaml | 6 ++- playground/editor/src/index.ts | 90 +++++++++++++++++--------------- playground/index.html | 13 ++++- playground/src/main.rs | 8 ++- 5 files changed, 72 insertions(+), 48 deletions(-) diff --git a/playground/Cargo.toml b/playground/Cargo.toml index 782d426..e5b0c32 100644 --- a/playground/Cargo.toml +++ b/playground/Cargo.toml @@ -19,4 +19,5 @@ tauri-bindgen-gen-markdown = { path = "../crates/gen-markdown" } tauri-bindgen-gen-guest-rust = { path = "../crates/gen-guest-rust" } tauri-bindgen-gen-guest-ts = { path = "../crates/gen-guest-ts" } tauri-bindgen-gen-guest-js = { path = "../crates/gen-guest-js" } -wit-parser = { path = "../crates/wit-parser" } \ No newline at end of file +wit-parser = { path = "../crates/wit-parser" } +pulldown-cmark = { version = "0.9", default-features = false } diff --git a/playground/editor/pnpm-lock.yaml b/playground/editor/pnpm-lock.yaml index d2bed06..28bf7ca 100644 --- a/playground/editor/pnpm-lock.yaml +++ b/playground/editor/pnpm-lock.yaml @@ -1,4 +1,8 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false dependencies: '@codemirror/lang-javascript': diff --git a/playground/editor/src/index.ts b/playground/editor/src/index.ts index 3a20faa..0306954 100644 --- a/playground/editor/src/index.ts +++ b/playground/editor/src/index.ts @@ -9,55 +9,59 @@ const default_content = `interface greet { }` const outputs = { - 'errors': new EditorView({ - parent: document.getElementById('errors')!, - extensions: [basicSetup, javascript(), EditorState.readOnly.of(true)], - }), - 'host': new EditorView({ - parent: document.getElementById('host')!, - extensions: [basicSetup, rust(), EditorState.readOnly.of(true)], - }), - 'guest-rust': new EditorView({ - parent: document.getElementById('guest_rust')!, - extensions: [basicSetup, rust(), EditorState.readOnly.of(true)], - }), - 'guest-js': new EditorView({ - parent: document.getElementById('guest_js')!, - extensions: [basicSetup, javascript(), EditorState.readOnly.of(true)], - }), - 'guest-ts': new EditorView({ - parent: document.getElementById('guest_ts')!, - extensions: [basicSetup, javascript(), EditorState.readOnly.of(true)], - }), + 'errors': new EditorView({ + parent: document.getElementById('errors')!, + extensions: [basicSetup, javascript(), EditorState.readOnly.of(true)], + }), + 'host': new EditorView({ + parent: document.getElementById('host')!, + extensions: [basicSetup, rust(), EditorState.readOnly.of(true)], + }), + 'guest-rust': new EditorView({ + parent: document.getElementById('guest_rust')!, + extensions: [basicSetup, rust(), EditorState.readOnly.of(true)], + }), + 'guest-js': new EditorView({ + parent: document.getElementById('guest_js')!, + extensions: [basicSetup, javascript(), EditorState.readOnly.of(true)], + }), + 'guest-ts': new EditorView({ + parent: document.getElementById('guest_ts')!, + extensions: [basicSetup, javascript(), EditorState.readOnly.of(true)], + }), } -export function updateOutput(id: 'errors' | 'host' | 'guest-rust' | 'guest-js' | 'guest-ts', data: string) { +export function updateOutput(id: 'errors' | 'host' | 'guest-rust' | 'guest-js' | 'guest-ts' | 'markdown', data: string) { + if (id === "markdown") { + document.getElementById('markdown')!.innerHTML = data + } else { outputs[id].dispatch({ - changes: { - from: 0, - to: outputs[id].state.doc.length, - insert: data, - }, + changes: { + from: 0, + to: outputs[id].state.doc.length, + insert: data, + }, }) + } } export function setup(onChange: (data: string) => void) { - const input = new EditorView({ - parent: document.getElementById('input')!, - extensions: [basicSetup, wit(), EditorView.updateListener.of((v) => { - if (v.docChanged) { - console.log(v.state.doc.toString()) + const input = new EditorView({ + parent: document.getElementById('input')!, + extensions: [basicSetup, wit(), EditorView.updateListener.of((v) => { + if (v.docChanged) { + console.log(v.state.doc.toString()) - onChange(v.state.doc.toString()) - } - })], - }) + onChange(v.state.doc.toString()) + } + })], + }) - input.dispatch({ - changes: { - from: 0, - to: input.state.doc.length, - insert: default_content, - }, - }) -} \ No newline at end of file + input.dispatch({ + changes: { + from: 0, + to: input.state.doc.length, + insert: default_content, + }, + }) +} diff --git a/playground/index.html b/playground/index.html index 065d41b..7384c3d 100644 --- a/playground/index.html +++ b/playground/index.html @@ -19,6 +19,7 @@ +

Welcome

-

This is the tauri-bindgen playground. You can enter any .wit interface definition file and inspect the generated code.

+

This is the tauri-bindgen playground. You can enter any .wit interface definition file and inspect + the generated code.

For more info see the repo.

+
@@ -55,6 +59,7 @@ grid-template-rows: 50vh 50vh; font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif; } + main { width: 100%; height: 100%; @@ -62,6 +67,7 @@ padding: 5px; box-sizing: border-box; } + aside figure { display: block; margin-left: 0; @@ -86,6 +92,7 @@ #iinfo:checked~figure #info, #ierrors:checked~figure #errors, + #imarkdown:checked~figure #markdown, #ihost:checked~figure #host, #iguest-rust:checked~figure #guest_rust, #iguest-js:checked~figure #guest_js, @@ -116,6 +123,7 @@ #iinfo:checked~nav label[for="iinfo"], #ierrors:checked~nav label[for="ierrors"], + #imarkdown:checked~nav label[for="imarkdown"], #ihost:checked~nav label[for="ihost"], #iguest-rust:checked~nav label[for="iguest-rust"], #iguest-js:checked~nav label[for="iguest-js"], @@ -128,6 +136,7 @@ #iinfo:checked~nav label[for="iinfo"]::after, #ierrors:checked~nav label[for="ierrors"]::after, + #imarkdown:checked~nav label[for="imarkdown"]::after, #ihost:checked~nav label[for="ihost"]::after, #iguest-rust:checked~nav label[for="iguest-rust"]::after, #iguest-js:checked~nav label[for="iguest-js"]::after, @@ -143,4 +152,4 @@ } - \ No newline at end of file + diff --git a/playground/src/main.rs b/playground/src/main.rs index f21a9de..2770f98 100644 --- a/playground/src/main.rs +++ b/playground/src/main.rs @@ -1,4 +1,5 @@ use miette::NamedSource; +use pulldown_cmark::{html, Parser}; use tauri_bindgen_core::GeneratorBuilder; use wasm_bindgen::prelude::*; use wit_parser::Interface; @@ -64,9 +65,14 @@ fn main() { prettier: false, romefmt: false, }, - iface, + iface.clone(), ), ); + let markdown = gen_interface(tauri_bindgen_gen_markdown::Builder {}, iface); + let parser = Parser::new(&markdown); + let mut html_output = String::new(); + html::push_html(&mut html_output, parser); + update_output("markdown", &html_output); } Err(err) => { update_output("errors", &format!("{:?}", err)); From 1fc5ca948356add2f20b5b7229a976edfbe2478f Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 1 Jun 2023 15:11:31 +0200 Subject: [PATCH 09/13] wip --- crates/gen-markdown/Cargo.toml | 3 +- crates/gen-markdown/src/lib.rs | 2 +- crates/wit-parser/src/typecheck.rs | 2 +- playground/index.html | 582 +++++++++++++++++++++++++++++ playground/src/main.rs | 10 +- 5 files changed, 594 insertions(+), 5 deletions(-) diff --git a/crates/gen-markdown/Cargo.toml b/crates/gen-markdown/Cargo.toml index 7db47be..e7383e4 100644 --- a/crates/gen-markdown/Cargo.toml +++ b/crates/gen-markdown/Cargo.toml @@ -15,6 +15,7 @@ heck.workspace = true pulldown-cmark = { version = "0.9", default-features = false } clap = { workspace = true, optional = true } wit-parser.workspace = true +log.workspace = true [features] -cli = ["clap"] \ No newline at end of file +cli = ["clap"] diff --git a/crates/gen-markdown/src/lib.rs b/crates/gen-markdown/src/lib.rs index 04ef0ad..7314bbf 100644 --- a/crates/gen-markdown/src/lib.rs +++ b/crates/gen-markdown/src/lib.rs @@ -183,7 +183,7 @@ impl Markdown { fn print_function(&self, func: &Function) -> String { format!( - "### Function {ident}\n\n`func {ident} ({params}){result}`\n\n{docs}", + "### Function {ident}\n\n` func {ident} ({params}){result}`\n\n{docs}", ident = func.ident, params = self.print_named_types(&func.params), result = func diff --git a/crates/wit-parser/src/typecheck.rs b/crates/wit-parser/src/typecheck.rs index eab1de8..afe26c4 100644 --- a/crates/wit-parser/src/typecheck.rs +++ b/crates/wit-parser/src/typecheck.rs @@ -69,7 +69,7 @@ impl<'a> Resolver<'a> { .map(|span| { let str = self.read_span(span); let str = str.strip_prefix("///").unwrap_or(str); - let str = str.strip_prefix("//*").unwrap_or(str); + let str = str.strip_prefix("/**").unwrap_or(str); let str = str.trim(); str diff --git a/playground/index.html b/playground/index.html index 7384c3d..e8fd86b 100644 --- a/playground/index.html +++ b/playground/index.html @@ -150,6 +150,588 @@ left: 0; bottom: -1px; } + + #markdown { + color-scheme: dark; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + margin: 0; + line-height: 1.5; + word-wrap: break-word; + } + + #markdown details, + #markdown figcaption, + #markdown figure { + display: block; + } + + #markdown summary { + display: list-item; + } + + #markdown [hidden] { + display: none !important; + } + + #markdown abbr[title] { + border-bottom: none; + text-decoration: underline dotted; + } + + #markdown b, + #markdown strong { + font-weight: 600; + } + + #markdown dfn { + font-style: italic; + } + + #markdown h1 { + margin: .67em 0; + font-weight: 600; + padding-bottom: .3em; + font-size: 2em; + /* border-bottom: 1px solid $white; */ + } + + #markdown mark { + /* background-color: rgba($bright-yellow, 0.5); */ + color: #c9d1d9; + } + + #markdown small { + font-size: 90%; + } + + #markdown sub, + #markdown sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + + #markdown sub { + bottom: -0.25em; + } + + #markdown sup { + top: -0.5em; + } + + #markdown img { + border-style: none; + max-width: 35%; + box-sizing: content-box; + /* background-color: $black; */ + } + + #markdown code, + #markdown kbd, + #markdown pre, + #markdown samp { + font-family: monospace; + font-size: 1em; + } + + #markdown figure { + margin: 1em 40px; + } + + #markdown hr { + box-sizing: content-box; + overflow: hidden; + background: transparent; + /* border-bottom: 1px solid darken(grayscale($white), 10%); */ + height: .25em; + padding: 0; + margin: 24px 0; + /* background-color: darken(grayscale($white), 10%); */ + border: 0; + } + + #markdown input { + font: inherit; + margin: 0; + overflow: visible; + font-family: inherit; + font-size: inherit; + line-height: inherit; + } + + #markdown [type=button], + #markdown [type=reset], + #markdown [type=submit] { + appearance: button; + -webkit-appearance: button; + } + + #markdown [type=checkbox], + #markdown [type=radio] { + box-sizing: border-box; + padding: 0; + } + + #markdown [type=number]::-webkit-inner-spin-button, + #markdown [type=number]::-webkit-outer-spin-button { + height: auto; + } + + #markdown [type=search]::-webkit-search-cancel-button, + #markdown [type=search]::-webkit-search-decoration { + -webkit-appearance: none; + } + + #markdown ::-webkit-input-placeholder { + color: inherit; + opacity: .54; + } + + #markdown ::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; + } + + #markdown ::placeholder { + color: #6e7681; + opacity: 1; + } + + #markdown hr::before { + display: table; + content: ""; + } + + #markdown hr::after { + display: table; + clear: both; + content: ""; + } + + #markdown table { + border-spacing: 0; + border-collapse: collapse; + display: block; + width: max-content; + max-width: 100%; + overflow: auto; + } + + #markdown td, + #markdown th { + padding: 0; + } + + #markdown details summary { + cursor: pointer; + } + + #markdown details:not([open])>*:not(summary) { + display: none !important; + } + + #markdown a:focus, + #markdown [role=button]:focus, + #markdown input[type=radio]:focus, + #markdown input[type=checkbox]:focus { + outline: 2px solid #58a6ff; + outline-offset: -2px; + box-shadow: none; + } + + #markdown a:focus:not(:focus-visible), + #markdown [role=button]:focus:not(:focus-visible), + #markdown input[type=radio]:focus:not(:focus-visible), + #markdown input[type=checkbox]:focus:not(:focus-visible) { + outline: solid 1px transparent; + } + + #markdown a:focus-visible, + #markdown [role=button]:focus-visible, + #markdown input[type=radio]:focus-visible, + #markdown input[type=checkbox]:focus-visible { + outline: 2px solid #58a6ff; + outline-offset: -2px; + box-shadow: none; + } + + #markdown a:not([class]):focus, + #markdown a:not([class]):focus-visible, + #markdown input[type=radio]:focus, + #markdown input[type=radio]:focus-visible, + #markdown input[type=checkbox]:focus, + #markdown input[type=checkbox]:focus-visible { + outline-offset: 0; + } + + #markdown kbd { + display: inline-block; + padding: 3px 5px; + /* font: 80% $font-mono; */ + line-height: 10px; + color: #c9d1d9; + vertical-align: middle; + /* background-color: $code-bg; */ + /* border: solid 1px grayscale(darken($white, 60%)); */ + /* border-bottom-color: grayscale(darken($white, 60%)); */ + border-radius: 6px; + /* box-shadow: inset 0 -1px 0 grayscale(darken($white, 60%)); */ + } + + #markdown h1, + #markdown h2, + #markdown h3, + #markdown h4, + #markdown h5, + #markdown h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: 600; + line-height: 1.25; + } + + #markdown h2 { + font-weight: 600; + padding-bottom: .3em; + font-size: 1.5em; + /* border-bottom: 1px solid grayscale(darken($white, 25%)); */ + } + + #markdown h3 { + font-weight: 600; + font-size: 1.25em; + } + + #markdown h4 { + font-weight: 600; + font-size: 1em; + } + + #markdown h5 { + font-weight: 600; + font-size: .875em; + } + + #markdown h6 { + font-weight: 600; + font-size: .85em; + /* color: grayscale(darken($white, 30%)); */ + } + + #markdown p { + margin-top: 0; + margin-bottom: 10px; + } + + #markdown blockquote { + margin: 0; + padding: 0 1em; + /* color: grayscale(darken($white, 30%)); */ + /* border-left: .25em solid grayscale(lighten($code-bg, 5%)); */ + } + + #markdown ul, + #markdown ol { + margin-top: 0; + margin-bottom: 0; + padding-left: 2em; + } + + #markdown ol ol, + #markdown ul ol { + list-style-type: lower-roman; + } + + #markdown ul ul ol, + #markdown ul ol ol, + #markdown ol ul ol, + #markdown ol ol ol { + list-style-type: lower-alpha; + } + + #markdown dd { + margin-left: 0; + } + + #markdown pre { + margin-top: 0; + margin-bottom: 0; + word-wrap: normal; + padding: 0.75rem; + } + + #markdown input::-webkit-outer-spin-button, + #markdown input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; + appearance: none; + } + + #markdown a:not([href]) { + color: inherit; + text-decoration: none; + } + + #markdown p, + #markdown blockquote, + #markdown ul, + #markdown ol, + #markdown dl, + #markdown table, + #markdown pre, + #markdown details { + margin-top: 0; + margin-bottom: 16px; + } + + #markdown blockquote>:first-child { + margin-top: 0; + } + + #markdown blockquote>:last-child { + margin-bottom: 0; + } + + #markdown h1 tt, + #markdown h1 code, + #markdown h2 tt, + #markdown h2 code, + #markdown h3 tt, + #markdown h3 code, + #markdown h4 tt, + #markdown h4 code, + #markdown h5 tt, + #markdown h5 code, + #markdown h6 tt, + #markdown h6 code { + padding: 0 .2em; + font-size: inherit; + } + + #markdown summary h1, + #markdown summary h2, + #markdown summary h3, + #markdown summary h4, + #markdown summary h5, + #markdown summary h6 { + display: inline-block; + } + + #markdown summary h1, + #markdown summary h2 { + padding-bottom: 0; + border-bottom: 0; + } + + #markdown ol[type=a] { + list-style-type: lower-alpha; + } + + #markdown ol[type=A] { + list-style-type: upper-alpha; + } + + #markdown ol[type=i] { + list-style-type: lower-roman; + } + + #markdown ol[type=I] { + list-style-type: upper-roman; + } + + #markdown ol[type="1"] { + list-style-type: decimal; + } + + #markdown div>ol:not([type]) { + list-style-type: decimal; + } + + #markdown ul ul, + #markdown ul ol, + #markdown ol ol, + #markdown ol ul { + margin-top: 0; + margin-bottom: 0; + } + + #markdown li>p { + margin-top: 16px; + } + + #markdown li+li { + margin-top: .25em; + } + + #markdown dl { + padding: 0; + } + + #markdown dl dt { + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: 600; + } + + #markdown dl dd { + padding: 0 16px; + margin-bottom: 16px; + } + + #markdown table th { + font-weight: 600; + } + + #markdown table th, + #markdown table td { + padding: 6px 13px; + /* border: 1px solid grayscale(darken($white, 60%)); */ + } + + /* #markdown table tr { + background-color: $code-bg; + } */ + + /* #markdown table tr:nth-child(2n) { + background-color: lighten($code-bg, 5%); + } */ + + #markdown table img { + background-color: transparent; + } + + #markdown code br, + #markdown tt br { + display: none; + } + + #markdown del code { + text-decoration: inherit; + } + + #markdown samp { + font-size: 85%; + } + + #markdown pre code { + font-size: 100%; + } + + #markdown pre>code { + padding: 0; + margin: 0; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; + } + + #markdown pre code, + #markdown pre tt { + display: inline; + max-width: auto; + padding: 0; + margin: 0; + overflow: visible; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; + } + + #markdown [data-footnote-ref]::before { + content: "["; + } + + #markdown [data-footnote-ref]::after { + content: "]"; + } + + #markdown .footnotes { + font-size: 12px; + /* color: grayscale(darken($white, 15%)); */ + /* border-top: 1px solid $white; */ + } + + #markdown .footnotes ol { + padding-left: 16px; + } + + #markdown .footnotes ol ul { + display: inline-block; + padding-left: 16px; + margin-top: 16px; + } + + #markdown .footnotes li { + position: relative; + } + + #markdown .footnotes li:target::before { + position: absolute; + top: -8px; + right: -8px; + bottom: -8px; + left: -24px; + pointer-events: none; + content: ""; + /* border: 2px solid $bright-yellow; */ + border-radius: 6px; + } + + /* #markdown .footnotes li:target { + color: $white; + } + + #markdown .footnotes .data-footnote-backref g-emoji { + font-family: $font-mono; + } */ + + #markdown .task-list-item { + list-style-type: none; + } + + #markdown .task-list-item label { + font-weight: 400; + } + + #markdown .task-list-item.enabled label { + cursor: pointer; + } + + #markdown .task-list-item+.task-list-item { + margin-top: 4px; + } + + #markdown .task-list-item .handle { + display: none; + } + + #markdown .task-list-item-checkbox { + margin: 0 .2em .25em -1.4em; + vertical-align: middle; + } + + #markdown .contains-task-list:dir(rtl) .task-list-item-checkbox { + margin: 0 -1.6em .25em .2em; + } + + #markdown .contains-task-list { + position: relative; + } + + #markdown .contains-task-list:hover .task-list-item-convert-container, + #markdown .contains-task-list:focus-within .task-list-item-convert-container { + display: block; + width: auto; + height: 24px; + overflow: visible; + clip: auto; + } diff --git a/playground/src/main.rs b/playground/src/main.rs index 2770f98..29bef19 100644 --- a/playground/src/main.rs +++ b/playground/src/main.rs @@ -1,5 +1,5 @@ use miette::NamedSource; -use pulldown_cmark::{html, Parser}; +use pulldown_cmark::{html, Options, Parser}; use tauri_bindgen_core::GeneratorBuilder; use wasm_bindgen::prelude::*; use wit_parser::Interface; @@ -69,7 +69,13 @@ fn main() { ), ); let markdown = gen_interface(tauri_bindgen_gen_markdown::Builder {}, iface); - let parser = Parser::new(&markdown); + let parser = Parser::new_ext( + &markdown, + Options::ENABLE_STRIKETHROUGH + | Options::ENABLE_FOOTNOTES + | Options::ENABLE_TABLES + | Options::ENABLE_TASKLISTS, + ); let mut html_output = String::new(); html::push_html(&mut html_output, parser); update_output("markdown", &html_output); From 60607d3821b06a11eea7bf7457b1e0f1238305cf Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 04:05:55 -0600 Subject: [PATCH 10/13] upgraded renovate config --- renovate.json | 6 --- renovate.json5 | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 6 deletions(-) delete mode 100644 renovate.json create mode 100644 renovate.json5 diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 39a2b6e..0000000 --- a/renovate.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base" - ] -} diff --git a/renovate.json5 b/renovate.json5 new file mode 100644 index 0000000..0e62e36 --- /dev/null +++ b/renovate.json5 @@ -0,0 +1,103 @@ +{ + // schedule: [ + // 'before 5am on the first day of the month', + //], + semanticCommits: 'enabled', + configMigration: true, + dependencyDashboard: true, + regexManagers: [ + { + customType: 'regex', + fileMatch: [ + '^rust-toolchain\\.toml$', + 'Cargo.toml$', + 'clippy.toml$', + '\\.clippy.toml$', + '^\\.github/workflows/ci.yml$', + '^\\.github/workflows/rust-next.yml$', + ], + matchStrings: [ + 'MSRV.*?(?\\d+\\.\\d+(\\.\\d+)?)', + '(?\\d+\\.\\d+(\\.\\d+)?).*?MSRV', + ], + depNameTemplate: 'rust', + packageNameTemplate: 'rust-lang/rust', + datasourceTemplate: 'github-releases', + }, + ], + packageRules: [ + { + commitMessageTopic: 'MSRV', + matchManagers: [ + 'regex', + ], + matchPackageNames: [ + 'rust', + ], + minimumReleaseAge: '252 days', // 6 releases * 6 weeks per release * 7 days per week + internalChecksFilter: 'strict', + }, + // Goals: + // - Keep version reqs low, ignoring compatible normal/build dependencies + // - Take advantage of latest dev-dependencies + // - Rollup safe upgrades to reduce CI runner load + // - Help keep number of versions down by always using latest breaking change + // - Have lockfile and manifest in-sync + { + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'build-dependencies', + 'dependencies', + ], + matchCurrentVersion: '>=0.1.0', + matchUpdateTypes: [ + 'patch', + ], + enabled: false, + }, + { + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'build-dependencies', + 'dependencies', + ], + matchCurrentVersion: '>=1.0.0', + matchUpdateTypes: [ + 'minor', + ], + enabled: false, + }, + { + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'dev-dependencies', + ], + matchCurrentVersion: '>=0.1.0', + matchUpdateTypes: [ + 'patch', + ], + automerge: true, + groupName: 'compatible (dev)', + }, + { + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'dev-dependencies', + ], + matchCurrentVersion: '>=1.0.0', + matchUpdateTypes: [ + 'minor', + ], + automerge: true, + groupName: 'compatible (dev)', + }, + ], +} From e41aae18d3476cf9b06a208b7850495519fa51fe Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 04:06:03 -0600 Subject: [PATCH 11/13] fix typos --- README.md | 2 +- crates/wit-parser/src/error.rs | 2 +- docs/WIT.md | 2 +- src/main.rs | 2 +- typos.toml | 4 ++++ 5 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 typos.toml diff --git a/README.md b/README.md index c2f8404..9371aaa 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Here are a few reasons why that is cool: - **Compile-time Checks** -When using strongly typed languages, such as Rust, TypeScript or ReScript the generated code will automatically ensure that you are calling the API correctly, as long as it passes the type checking youre golden. This is especially neat **when working in a team**, so your colleagues can't just change command signatures and pull the rug out from under you. +When using strongly typed languages, such as Rust, TypeScript or ReScript the generated code will automatically ensure that you are calling the API correctly, as long as it passes the type checking your golden. This is especially neat **when working in a team**, so your colleagues can't just change command signatures and pull the rug out from under you. - **Easily auditable** diff --git a/crates/wit-parser/src/error.rs b/crates/wit-parser/src/error.rs index d71cb93..0592f2d 100644 --- a/crates/wit-parser/src/error.rs +++ b/crates/wit-parser/src/error.rs @@ -76,7 +76,7 @@ pub enum Error { #[label("cannot be defined twice")] location: Span, }, - /// Types can't recursively refer to themselves as that would make then possibly infinitly-sized. + /// Types can't recursively refer to themselves as that would make then possibly infinitely-sized. /// In Rust the compiler would force you to use heap indirection, however such a thing doesn't exist in out type system. /// /// This wouldn't be a problem with the current JSON format, but a custom binary one would have this limitation so for future proofing we deny recursive types. diff --git a/docs/WIT.md b/docs/WIT.md index 363492b..847fc41 100644 --- a/docs/WIT.md +++ b/docs/WIT.md @@ -111,7 +111,7 @@ func greet(name: string) -> string At the top-level of each `wit` document lives the `interface` definition, file must contain exactly one such definition. The name you give to an interface will dictate the name of the generated module and printed debug output. -An interface may contain function declarations and type defintions. The order of declaration doesn't matter so you are free to define types after you have used them for example. +An interface may contain function declarations and type definitions. The order of declaration doesn't matter so you are free to define types after you have used them for example. ```wit interface empty {} diff --git a/src/main.rs b/src/main.rs index d616051..083b713 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ struct Cli { #[derive(Debug, Parser)] enum Command { - /// Check a defintion file for errors. + /// Check a definition file for errors. Check { #[clap(flatten)] world: WorldOpt, diff --git a/typos.toml b/typos.toml new file mode 100644 index 0000000..fd191eb --- /dev/null +++ b/typos.toml @@ -0,0 +1,4 @@ +[default.extend-words] +# Abbreviations +inout = "inout" +ser = "ser" From 081f9d8bc8b86678069189762343e700efaead8d Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 04:07:17 -0600 Subject: [PATCH 12/13] check spelling on PRs --- .github/workflows/spelling.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/spelling.yml diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml new file mode 100644 index 0000000..f31c7ed --- /dev/null +++ b/.github/workflows/spelling.yml @@ -0,0 +1,21 @@ +name: Spelling + +permissions: + contents: read + +on: [pull_request] + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + spelling: + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - name: Checkout Actions Repository + uses: actions/checkout@v3 + - name: Spell Check Repo + uses: crate-ci/typos@master From 7664df828e77751d2f9d3d4b095f0a48126a6c28 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 04:27:59 -0600 Subject: [PATCH 13/13] allow updating the msrv --- .github/workflows/ci.yml | 6 ++++-- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a16ecf2..181947b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: RUSTFLAGS: ${{matrix.rustflags}} ${{env.RUSTFLAGS}} msrv: - name: Rust 1.70.0 + name: Rust MSRV needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest @@ -55,7 +55,9 @@ jobs: run: | sudo apt-get update sudo apt-get install -y webkit2gtk-4.0 libgtk-3-dev - - uses: dtolnay/rust-toolchain@1.70.0 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.70.0 # MSRV - uses: Swatinem/rust-cache@v2 - run: cargo check --workspace --tests diff --git a/Cargo.toml b/Cargo.toml index 7d20be8..5531ca6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "tauri-bindgen" authors.workspace = true version.workspace = true edition.workspace = true -rust-version.workspace = true +rust-version.workspace = true # MSRV [workspace] members = ["crates/*"]