feat: port postcard deserialization to guest-js

This commit is contained in:
Jonas Kruckenberg
2023-05-21 20:26:14 +02:00
parent 1c526f2159
commit cac6903c3c
33 changed files with 2961 additions and 323 deletions

View File

@@ -9,4 +9,6 @@ rust-version.workspace = true
[dependencies]
wit-parser.workspace = true
proc-macro2 = "1.0.56"
proc-macro2 = "1.0.56"
bitflags.workspace = true
log.workspace = true

View File

@@ -1,14 +1,14 @@
use proc_macro2::TokenStream;
use std::path::PathBuf;
use wit_parser::Interface;
use std::{path::PathBuf, collections::HashMap, ops::Index};
use wit_parser::{Interface, TypeDefArena, Type, TypeDefId, FunctionResult, TypeDefKind, FlagsField, Int};
pub trait GeneratorBuilder {
fn build(self, interface: Interface) -> Box<dyn Generate>;
}
pub trait Generate {
fn to_file(&self) -> (PathBuf, String);
fn to_tokens(&self) -> TokenStream {
fn to_file(&mut self) -> (PathBuf, String);
fn to_tokens(&mut self) -> TokenStream {
unimplemented!("to_tokens is not implemented for this generator")
}
}
@@ -48,3 +48,141 @@ where
Ok(())
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct TypeInfo: u32 {
/// Whether or not this type is ever used (transitively) within the
/// parameter of a function.
const PARAM = 0b0000_0001;
/// Whether or not this type is ever used (transitively) within the
/// result of a function.
const RESULT = 0b0000_0010;
/// Whether or not this type (transitively) has a list.
const HAS_LIST = 0b0000_1000;
}
}
#[derive(Debug, Default)]
pub struct TypeInfos {
infos: HashMap<TypeDefId, TypeInfo>,
}
impl TypeInfos {
#[must_use]
pub fn new() -> Self {
TypeInfos::default()
}
pub fn collect_param_info(&mut self, typedefs: &TypeDefArena, params: &[(String, Type)]) {
for (_, ty) in params {
self.collect_type_info(typedefs, ty, TypeInfo::PARAM);
}
}
pub fn collect_result_info(&mut self, typedefs: &TypeDefArena, result: &FunctionResult) {
match result {
FunctionResult::Anon(ty) => {
self.collect_type_info(typedefs, ty, TypeInfo::RESULT);
}
FunctionResult::Named(results) => {
for (_, ty) in results {
self.collect_type_info(typedefs, ty, TypeInfo::RESULT);
}
}
}
}
fn collect_typedef_info(
&mut self,
typedefs: &TypeDefArena,
id: TypeDefId,
base_info: TypeInfo,
) -> TypeInfo {
let mut info = base_info;
match &typedefs[id].kind {
TypeDefKind::Alias(ty) => {
info |= self.collect_type_info(typedefs, ty, base_info);
}
TypeDefKind::Record(fields) => {
for field in fields {
info |= self.collect_type_info(typedefs, &field.ty, base_info);
}
}
TypeDefKind::Variant(cases) => {
for case in cases {
if let Some(ty) = &case.ty {
info |= self.collect_type_info(typedefs, ty, base_info);
}
}
}
TypeDefKind::Union(cases) => {
for case in cases {
info |= self.collect_type_info(typedefs, &case.ty, base_info);
}
}
_ => {}
}
log::debug!("collected info for {:?}: {:?}", typedefs[id].ident, info,);
self.infos
.entry(id)
.and_modify(|i| *i |= info)
.or_insert(info);
info
}
fn collect_type_info(
&mut self,
typedefs: &TypeDefArena,
ty: &Type,
base_info: TypeInfo,
) -> TypeInfo {
match ty {
Type::String => base_info | TypeInfo::HAS_LIST,
Type::List(ty) => self.collect_type_info(typedefs, ty, base_info) | TypeInfo::HAS_LIST,
Type::Option(ty) => self.collect_type_info(typedefs, ty, base_info),
Type::Tuple(types) => {
let mut info = base_info;
for ty in types {
info |= self.collect_type_info(typedefs, ty, base_info);
}
info
}
Type::Result { ok, err } => {
let mut info = base_info;
if let Some(ty) = &ok {
info |= self.collect_type_info(typedefs, ty, base_info);
}
if let Some(ty) = &err {
info |= self.collect_type_info(typedefs, ty, base_info);
}
info
}
Type::Id(id) => base_info | self.collect_typedef_info(typedefs, *id, base_info),
_ => base_info,
}
}
}
impl Index<TypeDefId> for TypeInfos {
type Output = TypeInfo;
fn index(&self, id: TypeDefId) -> &Self::Output {
&self.infos[&id]
}
}
#[must_use]
pub fn flags_repr(fields: &[FlagsField]) -> Int {
match fields.len() {
n if n <= 8 => Int::U8,
n if n <= 16 => Int::U16,
n if n <= 32 => Int::U32,
n if n <= 64 => Int::U64,
_ => panic!("too many flags to fit in a repr"),
}
}

View File

@@ -10,6 +10,8 @@ tauri-bindgen-core.workspace = true
wit-parser.workspace = true
heck.workspace = true
clap = { workspace = true, optional = true }
log.workspace = true
bitflags.workspace = true
[dev-dependencies]
pretty_assertions = "1.3.0"

View File

@@ -1,9 +1,14 @@
#![allow(clippy::must_use_candidate, clippy::unused_self)]
use heck::{ToKebabCase, ToLowerCamelCase, ToUpperCamelCase, ToSnakeCase};
use std::path::PathBuf;
use tauri_bindgen_core::{postprocess, Generate, GeneratorBuilder};
use wit_parser::{Function, FunctionResult, Interface, Type, TypeDefKind};
use heck::{ToKebabCase, ToLowerCamelCase, ToSnakeCase, ToUpperCamelCase};
use std::{collections::HashSet, fmt::Write, path::PathBuf, sync::atomic::{AtomicU32, Ordering}};
use tauri_bindgen_core::{
flags_repr, postprocess, Generate, GeneratorBuilder, TypeInfo, TypeInfos,
};
use wit_parser::{
EnumCase, FlagsField, Function, FunctionResult, Interface, RecordField, Type, TypeDefId,
TypeDefKind, UnionCase, VariantCase,
};
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "clap", derive(clap::Args))]
@@ -22,9 +27,24 @@ pub struct Builder {
impl GeneratorBuilder for Builder {
fn build(self, interface: Interface) -> Box<dyn Generate> {
let mut infos = TypeInfos::new();
for func in &interface.functions {
infos.collect_param_info(&interface.typedefs, &func.params);
if let Some(result) = &func.result {
infos.collect_result_info(&interface.typedefs, result);
}
}
for (id, typedef) in &interface.typedefs {
log::debug!("type info: {} {:#?}", typedef.ident, infos[id]);
}
Box::new(JavaScript {
opts: self,
interface,
infos,
serde_utils: 0.into(),
})
}
}
@@ -33,6 +53,9 @@ impl GeneratorBuilder for Builder {
pub struct JavaScript {
opts: Builder,
interface: Interface,
infos: TypeInfos,
// TODO: this is really awkward
serde_utils: AtomicU32,
}
impl JavaScript {
@@ -42,17 +65,67 @@ impl JavaScript {
let name = func.ident.to_snake_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();
format!(
r#"
{docs}
export async function {ident} ({params}) {{
return fetch('ipc://localhost/{intf_name}/{name}', {{ method: "POST", body: JSON.stringify([{params}]) }}).then(r => r.json())
return fetch('ipc://localhost/{intf_name}/{name}', {{ method: "POST", body: JSON.stringify([{params}]) }}){deserialize_result}
}}
"#
)
}
fn print_resource(&self, docs: &str, ident: &str, functions: &[Function]) -> String {
fn print_deserialize_function_result(&self, result: &FunctionResult) -> String {
match result.len() {
0 => String::new(),
1 => {
let inner = self.print_deserialize_ty(result.types().next().unwrap());
format!(
"
.then(r => r.arrayBuffer())
.then(bytes => {{
const de = new Deserializer(Uint8Array.from(bytes))
return {inner}
}})"
)
}
_ => {
let tys = result
.types()
.map(|ty| self.print_deserialize_ty(ty))
.collect::<Vec<_>>()
.join(", ");
format!(
"
.then(r => r.arrayBuffer())
.then(bytes => {{
const de = new Deserializer(Uint8Array.from(bytes))
return [{tys}]
}})"
)
}
}
}
fn print_resource(
&self,
docs: &str,
ident: &str,
functions: &[Function],
info: TypeInfo,
) -> String {
let ident = ident.to_upper_camel_case();
let functions: String = functions
.iter()
.map(|func| {
@@ -70,11 +143,23 @@ impl JavaScript {
})
.collect();
let deserialize = if info.contains(TypeInfo::RESULT) {
format!(
"deserialize(de) {{
const self = new {ident}();
self.#id = deserializeU64(de);
return self
}}"
)
} else {
String::new()
};
format!(
"{docs}\nclass {ident} {{
#id: number;
#id;
{functions}
{deserialize}
}}"
)
}
@@ -186,10 +271,271 @@ impl JavaScript {
| Type::String => None,
}
}
fn print_deserialize_ty(&self, ty: &Type) -> String {
match ty {
Type::Bool => {
self.serde_utils.fetch_or(SerdeUtils::DE_BOOl.bits(), Ordering::Relaxed);
"deserializeBoolean(de)".to_string()
}
Type::U8 => {
self.serde_utils.fetch_or(SerdeUtils::DE_U8.bits(), Ordering::Relaxed);
"deserializeU8(de)".to_string()
}
Type::U16 => {
self.serde_utils.fetch_or(SerdeUtils::DE_U16.bits(), Ordering::Relaxed);
"deserializeU16(de)".to_string()
}
Type::U32 => {
self.serde_utils.fetch_or(SerdeUtils::DE_U32.bits(), Ordering::Relaxed);
"deserializeU32(de)".to_string()
}
Type::U64 => {
self.serde_utils.fetch_or(SerdeUtils::DE_U64.bits(), Ordering::Relaxed);
"deserializeU64(de)".to_string()
}
Type::S8 => {
self.serde_utils.fetch_or(SerdeUtils::DE_S8.bits(), Ordering::Relaxed);
"deserializeS8(de)".to_string()
}
Type::S16 => {
self.serde_utils.fetch_or(SerdeUtils::DE_S16.bits(), Ordering::Relaxed);
"deserializeS16(de)".to_string()
}
Type::S32 => {
self.serde_utils.fetch_or(SerdeUtils::DE_S32.bits(), Ordering::Relaxed);
"deserializeS32(de)".to_string()
}
Type::S64 => {
self.serde_utils.fetch_or(SerdeUtils::DE_S64.bits(), Ordering::Relaxed);
"deserializeS64(de)".to_string()
}
Type::Float32 => {
self.serde_utils.fetch_or(SerdeUtils::DE_F32.bits(), Ordering::Relaxed);
"deserializeF32(de)".to_string()
}
Type::Float64 => {
self.serde_utils.fetch_or(SerdeUtils::DE_F64.bits(), Ordering::Relaxed);
"deserializeF64(de)".to_string()
}
Type::Char => {
self.serde_utils.fetch_or(SerdeUtils::DE_CHAR.bits(), Ordering::Relaxed);
"deserializeChar(de)".to_string()
}
Type::String => {
self.serde_utils.fetch_or(SerdeUtils::DE_STRING.bits(), Ordering::Relaxed);
"deserializeString(de)".to_string()
}
Type::Tuple(types) => {
let types = types
.iter()
.map(|ty| self.print_deserialize_ty(ty))
.collect::<Vec<_>>()
.join(", ");
format!("[{types}]")
}
Type::List(ty) if **ty == Type::U8 => {
self.serde_utils.fetch_or(SerdeUtils::DE_BYTES.bits(), Ordering::Relaxed);
"deserializeBytes(de)".to_string()
}
Type::List(ty) => {
self.serde_utils.fetch_or(SerdeUtils::DE_LIST.bits(), Ordering::Relaxed);
let ty = self.print_deserialize_ty(ty);
format!("deserializeList(de, (de) => {ty})")
}
Type::Option(ty) => {
self.serde_utils.fetch_or(SerdeUtils::DE_OPTION.bits(), Ordering::Relaxed);
let ty = self.print_deserialize_ty(ty);
format!("deserializeOption(de, (de) => {ty})")
}
Type::Result { ok, err } => {
self.serde_utils.fetch_or(SerdeUtils::DE_RESULT.bits(), Ordering::Relaxed);
let ok = ok
.as_ref()
.map_or("() => {}".to_string(), |ty| self.print_deserialize_ty(ty));
let err = err
.as_ref()
.map_or("() => {}".to_string(), |ty| self.print_deserialize_ty(ty));
format!("deserializeResult(de, {ok}, {err})")
}
Type::Id(id) => {
if let TypeDefKind::Resource(_) = self.interface.typedefs[*id].kind {
format!(
"{}.deserialize(de)",
self.interface.typedefs[*id].ident.to_upper_camel_case()
)
} else {
format!(
"deserialize{}(de)",
self.interface.typedefs[*id].ident.to_upper_camel_case()
)
}
}
}
}
fn print_deserialize_typedef(&self, id: TypeDefId) -> String {
let typedef = &self.interface.typedefs[id];
let ident = &typedef.ident.to_upper_camel_case();
match typedef.kind.clone() {
TypeDefKind::Alias(ty) => self.print_deserialize_alias(ident, ty),
TypeDefKind::Record(fields) => self.print_deserialize_record(ident, &fields),
TypeDefKind::Flags(fields) => self.print_deserialize_flags(ident, &fields),
TypeDefKind::Variant(cases) => self.print_deserialize_variant(ident, &cases),
TypeDefKind::Enum(cases) => self.print_deserialize_enum(ident, &cases),
TypeDefKind::Union(cases) => self.print_deserialize_union(ident, &cases),
TypeDefKind::Resource(_) => String::new(),
}
}
fn print_deserialize_alias(&self, ident: &str, ty: Type) -> String {
let inner = self.print_deserialize_ty(&ty);
format!(
r#"function deserialize{ident}(de) {{
return {inner}
}}"#
)
}
fn print_deserialize_record(&self, ident: &str, fields: &[RecordField]) -> String {
let fields = fields
.iter()
.map(|field| {
let ident = field.ident.to_lower_camel_case();
format!("{ident}: {}", self.print_deserialize_ty(&field.ty))
})
.collect::<Vec<_>>()
.join(",\n");
format!(
r#"function deserialize{ident}(de) {{
return {{
{fields}
}}
}}"#
)
}
fn print_deserialize_flags(&self, ident: &str, fields: &[FlagsField]) -> String {
let inner = match flags_repr(fields) {
wit_parser::Int::U8 => "U8",
wit_parser::Int::U16 => "U16",
wit_parser::Int::U32 => "U32",
wit_parser::Int::U64 => "U64",
};
format!(
r#"function deserialize{ident}(de) {{
return deserialize{inner}(de)
}}"#
)
}
fn print_deserialize_variant(&self, ident: &str, cases: &[VariantCase]) -> String {
let cases = cases
.iter()
.enumerate()
.map(|(tag, case)| {
let inner = case
.ty
.as_ref()
.map(|ty| self.print_deserialize_ty(&ty))
.unwrap_or("null".to_string());
format!(
"case {tag}:
return {{ tag: {tag}, value: {inner} }}
"
)
})
.collect::<String>();
format!(
r#"function deserialize{ident}(de) {{
const disc = deserializeU32(de)
switch (disc) {{
{cases}
default:
throw new Error("unknown variant case")
}}
}}"#
)
}
fn print_deserialize_enum(&self, ident: &str, cases: &[EnumCase]) -> String {
let cases = cases
.iter()
.enumerate()
.map(|(tag, case)| {
let ident = case.ident.to_upper_camel_case();
format!(
"case {tag}:
return \"{ident}\"
"
)
})
.collect::<String>();
format!(
r#"function deserialize{ident}(de) {{
const disc = deserializeU32(de)
switch (disc) {{
{cases}
default:
throw new Error("unknown enum case")
}}
}}"#
)
}
fn print_deserialize_union(&self, ident: &str, cases: &[UnionCase]) -> String {
let cases = cases
.iter()
.enumerate()
.map(|(tag, case)| {
let inner = self.print_deserialize_ty(&case.ty);
format!(
"case {tag}:
return {inner}
"
)
})
.collect::<String>();
format!(
r#"function deserialize{ident}(de) {{
const disc = deserializeU32(de)
switch (disc) {{
{cases}
default:
throw new Error("unknown union case")
}}
}}"#
)
}
}
impl Generate for JavaScript {
fn to_file(&self) -> (std::path::PathBuf, String) {
fn to_file(&mut self) -> (std::path::PathBuf, String) {
let mut deserializers = String::new();
for (id, _) in self.interface.typedefs.iter() {
let info = self.infos[id];
if info.contains(TypeInfo::RESULT) {
deserializers.push_str(&self.print_deserialize_typedef(id))
}
}
let functions: String = self
.interface
.functions
@@ -201,16 +547,23 @@ impl Generate for JavaScript {
.interface
.typedefs
.iter()
.filter_map(|(_, typedef)| {
.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))
Some(self.print_resource(&typedef.docs, &typedef.ident, functions, info))
} else {
None
}
})
.collect();
let mut contents = format!("{functions}\n{resources}");
let bits = self.serde_utils.load(Ordering::Acquire);
println!("{} {:?}", bits, SerdeUtils::from_bits_retain(bits));
let serde_util = print_serde_utils(&SerdeUtils::from_bits_retain(bits)).unwrap();
let mut contents = format!("{serde_util}{deserializers}\n{functions}\n{resources}");
if self.opts.prettier {
postprocess(&mut contents, "prettier", ["--parser=babel"])
@@ -238,3 +591,338 @@ fn print_function_params(params: &[(String, Type)]) -> String {
.collect::<Vec<_>>()
.join(", ")
}
bitflags::bitflags! {
#[derive(Debug)]
struct SerdeUtils: u32 {
const VARINT_TYPE = 1 << 0;
const VARINT_MAX = 1 << 1;
const MAX_OF_LAST_BYTE = 1 << 2;
const _TRY_TAKE_VARINT = 1 << 3;
const DE_BOOl = 1 << 4;
const DE_U8 = 1 << 5;
const _DE_U16 = 1 << 6;
const _DE_U32 = 1 << 7;
const _DE_U64 = 1 << 8;
const DE_S8 = 1 << 9;
const _DE_S16 = 1 << 10;
const _DE_S32 = 1 << 11;
const _DE_S64 = 1 << 12;
const DE_F32 = 1 << 13;
const DE_F64 = 1 << 14;
const _DE_CHAR = 1 << 15;
const _DE_STRING = 1 << 16;
const _DE_BYTES = 1 << 17;
const DE_OPTION = 1 << 18;
const DE_RESULT = 1 << 19;
const _DE_LIST = 1 << 20;
const TRY_TAKE_VARINT = Self::_TRY_TAKE_VARINT.bits() | Self::VARINT_TYPE.bits() | Self::VARINT_MAX.bits() | Self::MAX_OF_LAST_BYTE.bits();
const DE_U16 = Self::_DE_U16.bits() | Self::TRY_TAKE_VARINT.bits();
const DE_U32 = Self::_DE_U32.bits() | Self::TRY_TAKE_VARINT.bits();
const DE_U64 = Self::_DE_U64.bits() | Self::TRY_TAKE_VARINT.bits();
const DE_S16 = Self::_DE_S16.bits() | Self::TRY_TAKE_VARINT.bits();
const DE_S32 = Self::_DE_S32.bits() | Self::TRY_TAKE_VARINT.bits();
const DE_S64 = Self::_DE_S64.bits() | Self::TRY_TAKE_VARINT.bits();
const DE_CHAR = Self::_DE_CHAR.bits() | Self::DE_U64.bits();
const DE_STRING = Self::_DE_STRING.bits() | Self::DE_U64.bits();
const DE_BYTES = Self::_DE_BYTES.bits() | Self::DE_U64.bits();
const DE_LIST = Self::_DE_LIST.bits() | Self::DE_U64.bits();
}
}
fn print_serde_utils(serde_utils: &SerdeUtils) -> Result<String, std::fmt::Error> {
let mut out = "export class Deserializer {
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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
}
}
"
.to_string();
if serde_utils.contains(SerdeUtils::VARINT_MAX) {
out.write_str(
"function varint_max(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
",
)?;
}
if serde_utils.contains(SerdeUtils::MAX_OF_LAST_BYTE) {
out.write_str(
"function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_TRY_TAKE_VARINT) {
out.write_str(
"function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
",
)?;
}
if serde_utils.contains(SerdeUtils::DE_BOOl) {
out.write_str(
"function deserializeBool(de) {
const val = de.pop();
return val != 0
}
",
)?;
}
if serde_utils.contains(SerdeUtils::DE_U8) {
out.write_str(
"function deserializeU8(de) {
return de.pop()
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_U16) {
out.write_str(
"function deserializeU16(de) {
return try_take_varint(de, 16)
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_U32) {
out.write_str(
"function deserializeU32(de) {
return try_take_varint(de, 32)
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_U64) {
out.write_str(
"function deserializeU64(de) {
return try_take_varint(de, 64)
}
",
)?;
}
if serde_utils.contains(SerdeUtils::DE_S8) {
out.write_str(
"function deserializeI8(de) {
return de.pop()
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_S16) {
out.write_str(
"function deserializeI16(de) {
const n = try_take_varint(de, 16)
return Number(((n >> 1n) & 0xFFFFn) ^ (-((n & 0b1n) & 0xFFFFn)))
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_S32) {
out.write_str(
"function deserializeI32(de) {
const n = try_take_varint(de, 32)
return Number(((n >> 1n) as & 0xFFFFFFFFn) ^ (-((n & 0b1n) as & 0xFFFFFFFFn)))
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_S64) {
out.write_str(
"function deserializeI64(de) {
const n = try_take_varint(de, u64)
return Number(((n >> 1n) & 0xFFFFFFFFFFFFFFFFn) ^ (-((n & 0b1n) & 0xFFFFFFFFFFFFFFFFn)))
}
",
)?;
}
if serde_utils.contains(SerdeUtils::DE_F32) {
out.write_str(
"function deserializeF32(de) {
const bytes = de.try_take_n(4);
const buf = new ArrayBuffer(4);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat32(0);
}
",
)?;
}
if serde_utils.contains(SerdeUtils::DE_F64) {
out.write_str(
"function deserializeF64(de) {
const bytes = de.try_take_n(8);
const buf = new ArrayBuffer(8);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat64(0);
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_CHAR) {
out.write_str(
r#"function deserializeChar(de) {
const sz = deserializeU64(de);
if (sz > 4) {
throw new Error("Deserialize bad char");
}
const bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
"#,
)?;
}
if serde_utils.contains(SerdeUtils::_DE_STRING) {
out.write_str(
"function deserializeString(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_BYTES) {
out.write_str(
"function deserializeBytes(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
",
)?;
}
if serde_utils.contains(SerdeUtils::DE_OPTION) {
out.write_str(
"function deserializeOption(de, inner) {
const disc = de.pop()
switch (disc) {
case 0:
return null
case 1:
return inner(de)
default:
throw new Error('Deserialize bad option')
}
}
",
)?;
}
if serde_utils.contains(SerdeUtils::DE_RESULT) {
out.write_str(
"function function deserializeResult(de, ok, err) {
const disc = de.pop()
switch (disc) {
case 0:
return ok(de)
case 1:
return err(de)
default:
throw new Error('Deserialize bad result')
}
}
",
)?;
}
if serde_utils.contains(SerdeUtils::_DE_LIST) {
out.write_str(
"function deserializeList(de, inner) {
const len = deserializeU64(de);
let out: T[] = [];
for (let i = 0; i < len; i++) {
out.push(inner(de));
}
return out;
}
",
)?;
}
Ok(out)
}

View File

@@ -1,10 +1,77 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeChar(de) {
const sz = deserializeU64(de);
if (sz > 4) {
throw new Error("Deserialize bad char");
}
const bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
/**
* A function that accepts a character
* @param {string} x
*/
export async function takeChar (x) {
return fetch('ipc://localhost/chars/take_char', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/chars/take_char', { method: "POST", body: JSON.stringify([x]) })
}
/**
@@ -12,6 +79,12 @@
* @returns {Promise<string>}
*/
export async function returnChar () {
return fetch('ipc://localhost/chars/return_char', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/chars/return_char', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeChar(de)
})
}

View File

@@ -11,7 +11,7 @@ fn gen_interface(
) -> (String, String) {
let iface = wit_parser::parse_and_resolve_str(&input, |_| false).unwrap();
let gen = opts.build(iface);
let mut gen = opts.build(iface);
let (filename, contents) = gen.to_file();
(filename.to_str().unwrap().to_string(), contents)

View File

@@ -1,74 +1,94 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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
}
}
/**
*/
export async function kebabCase () {
return fetch('ipc://localhost/conventions/kebab_case', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/kebab_case', { method: "POST", body: JSON.stringify([]) })
}
/**
* @param {LudicrousSpeed} x
*/
export async function foo (x) {
return fetch('ipc://localhost/conventions/foo', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/foo', { method: "POST", body: JSON.stringify([x]) })
}
/**
*/
export async function functionWithUnderscores () {
return fetch('ipc://localhost/conventions/function_with_underscores', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/function_with_underscores', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function functionWithNoWeirdCharacters () {
return fetch('ipc://localhost/conventions/function_with_no_weird_characters', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/function_with_no_weird_characters', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function apple () {
return fetch('ipc://localhost/conventions/apple', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/apple', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function applePear () {
return fetch('ipc://localhost/conventions/apple_pear', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/apple_pear', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function applePearGrape () {
return fetch('ipc://localhost/conventions/apple_pear_grape', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/apple_pear_grape', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function a0 () {
return fetch('ipc://localhost/conventions/a0', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/a0', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function isXml () {
return fetch('ipc://localhost/conventions/is_xml', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/is_xml', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function explicit () {
return fetch('ipc://localhost/conventions/explicit', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/explicit', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function explicitSnake () {
return fetch('ipc://localhost/conventions/explicit_snake', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/explicit_snake', { method: "POST", body: JSON.stringify([]) })
}
/**
*/
export async function bool () {
return fetch('ipc://localhost/conventions/bool', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/conventions/bool', { method: "POST", body: JSON.stringify([]) })
}

View File

@@ -1 +1,21 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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
}
}

View File

@@ -1,10 +1,50 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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 deserializeFlag1(de) {
return deserializeU8(de)
}function deserializeFlag2(de) {
return deserializeU8(de)
}function deserializeFlag4(de) {
return deserializeU8(de)
}function deserializeFlag8(de) {
return deserializeU8(de)
}function deserializeFlag16(de) {
return deserializeU16(de)
}function deserializeFlag32(de) {
return deserializeU32(de)
}function deserializeFlag64(de) {
return deserializeU64(de)
}
/**
* @param {Flag1} x
* @returns {Promise<Flag1>}
*/
export async function roundtripFlag1 (x) {
return fetch('ipc://localhost/flegs/roundtrip_flag1', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/flegs/roundtrip_flag1', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeFlag1(de)
})
}
/**
@@ -12,7 +52,13 @@
* @returns {Promise<Flag2>}
*/
export async function roundtripFlag2 (x) {
return fetch('ipc://localhost/flegs/roundtrip_flag2', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/flegs/roundtrip_flag2', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeFlag2(de)
})
}
/**
@@ -20,7 +66,13 @@
* @returns {Promise<Flag4>}
*/
export async function roundtripFlag4 (x) {
return fetch('ipc://localhost/flegs/roundtrip_flag4', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/flegs/roundtrip_flag4', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeFlag4(de)
})
}
/**
@@ -28,7 +80,13 @@
* @returns {Promise<Flag8>}
*/
export async function roundtripFlag8 (x) {
return fetch('ipc://localhost/flegs/roundtrip_flag8', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/flegs/roundtrip_flag8', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeFlag8(de)
})
}
/**
@@ -36,7 +94,13 @@
* @returns {Promise<Flag16>}
*/
export async function roundtripFlag16 (x) {
return fetch('ipc://localhost/flegs/roundtrip_flag16', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/flegs/roundtrip_flag16', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeFlag16(de)
})
}
/**
@@ -44,7 +108,13 @@
* @returns {Promise<Flag32>}
*/
export async function roundtripFlag32 (x) {
return fetch('ipc://localhost/flegs/roundtrip_flag32', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/flegs/roundtrip_flag32', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeFlag32(de)
})
}
/**
@@ -52,6 +122,12 @@
* @returns {Promise<Flag64>}
*/
export async function roundtripFlag64 (x) {
return fetch('ipc://localhost/flegs/roundtrip_flag64', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/flegs/roundtrip_flag64', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeFlag64(de)
})
}

View File

@@ -1,29 +1,81 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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 deserializeF32(de) {
const bytes = de.try_take_n(4);
const buf = new ArrayBuffer(4);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat32(0);
}
function deserializeF64(de) {
const bytes = de.try_take_n(8);
const buf = new ArrayBuffer(8);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat64(0);
}
/**
* @param {number} x
*/
export async function float32Param (x) {
return fetch('ipc://localhost/floats/float32_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/floats/float32_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {number} x
*/
export async function float64Param (x) {
return fetch('ipc://localhost/floats/float64_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/floats/float64_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<number>}
*/
export async function float32Result () {
return fetch('ipc://localhost/floats/float32_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/floats/float32_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeF32(de)
})
}
/**
* @returns {Promise<number>}
*/
export async function float64Result () {
return fetch('ipc://localhost/floats/float64_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/floats/float64_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeF64(de)
})
}

View File

@@ -1,58 +1,141 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU8(de) {
return de.pop()
}
function deserializeU16(de) {
return try_take_varint(de, 16)
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeI8(de) {
return de.pop()
}
function deserializeI16(de) {
const n = try_take_varint(de, 16)
return Number(((n >> 1n) & 0xFFFFn) ^ (-((n & 0b1n) & 0xFFFFn)))
}
function deserializeI32(de) {
const n = try_take_varint(de, 32)
return Number(((n >> 1n) as & 0xFFFFFFFFn) ^ (-((n & 0b1n) as & 0xFFFFFFFFn)))
}
function deserializeI64(de) {
const n = try_take_varint(de, u64)
return Number(((n >> 1n) & 0xFFFFFFFFFFFFFFFFn) ^ (-((n & 0b1n) & 0xFFFFFFFFFFFFFFFFn)))
}
/**
* @param {number} x
*/
export async function a1 (x) {
return fetch('ipc://localhost/integers/a1', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a1', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {number} x
*/
export async function a2 (x) {
return fetch('ipc://localhost/integers/a2', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a2', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {number} x
*/
export async function a3 (x) {
return fetch('ipc://localhost/integers/a3', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a3', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {number} x
*/
export async function a4 (x) {
return fetch('ipc://localhost/integers/a4', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a4', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {number} x
*/
export async function a5 (x) {
return fetch('ipc://localhost/integers/a5', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a5', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {number} x
*/
export async function a6 (x) {
return fetch('ipc://localhost/integers/a6', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a6', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {bigint} x
*/
export async function a7 (x) {
return fetch('ipc://localhost/integers/a7', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a7', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {bigint} x
*/
export async function a8 (x) {
return fetch('ipc://localhost/integers/a8', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a8', { method: "POST", body: JSON.stringify([x]) })
}
/**
@@ -66,69 +149,123 @@
* @param {bigint} p8
*/
export async function a9 (p1, p2, p3, p4, p5, p6, p7, p8) {
return fetch('ipc://localhost/integers/a9', { method: "POST", body: JSON.stringify([p1, p2, p3, p4, p5, p6, p7, p8]) }).then(r => r.json())
return fetch('ipc://localhost/integers/a9', { method: "POST", body: JSON.stringify([p1, p2, p3, p4, p5, p6, p7, p8]) })
}
/**
* @returns {Promise<number>}
*/
export async function r1 () {
return fetch('ipc://localhost/integers/r1', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r1', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU8(de)
})
}
/**
* @returns {Promise<number>}
*/
export async function r2 () {
return fetch('ipc://localhost/integers/r2', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r2', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeS8(de)
})
}
/**
* @returns {Promise<number>}
*/
export async function r3 () {
return fetch('ipc://localhost/integers/r3', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r3', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU16(de)
})
}
/**
* @returns {Promise<number>}
*/
export async function r4 () {
return fetch('ipc://localhost/integers/r4', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r4', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeS16(de)
})
}
/**
* @returns {Promise<number>}
*/
export async function r5 () {
return fetch('ipc://localhost/integers/r5', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r5', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU32(de)
})
}
/**
* @returns {Promise<number>}
*/
export async function r6 () {
return fetch('ipc://localhost/integers/r6', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r6', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeS32(de)
})
}
/**
* @returns {Promise<bigint>}
*/
export async function r7 () {
return fetch('ipc://localhost/integers/r7', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r7', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU64(de)
})
}
/**
* @returns {Promise<bigint>}
*/
export async function r8 () {
return fetch('ipc://localhost/integers/r8', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/r8', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeS64(de)
})
}
/**
* @returns {Promise<[bigint, number]>}
*/
export async function pairRet () {
return fetch('ipc://localhost/integers/pair_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/integers/pair_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeS64(de), deserializeU8(de)]
})
}

View File

@@ -1,142 +1,380 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU8(de) {
return de.pop()
}
function deserializeU16(de) {
return try_take_varint(de, 16)
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeI8(de) {
return de.pop()
}
function deserializeI16(de) {
const n = try_take_varint(de, 16)
return Number(((n >> 1n) & 0xFFFFn) ^ (-((n & 0b1n) & 0xFFFFn)))
}
function deserializeI32(de) {
const n = try_take_varint(de, 32)
return Number(((n >> 1n) as & 0xFFFFFFFFn) ^ (-((n & 0b1n) as & 0xFFFFFFFFn)))
}
function deserializeI64(de) {
const n = try_take_varint(de, u64)
return Number(((n >> 1n) & 0xFFFFFFFFFFFFFFFFn) ^ (-((n & 0b1n) & 0xFFFFFFFFFFFFFFFFn)))
}
function deserializeF32(de) {
const bytes = de.try_take_n(4);
const buf = new ArrayBuffer(4);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat32(0);
}
function deserializeF64(de) {
const bytes = de.try_take_n(8);
const buf = new ArrayBuffer(8);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat64(0);
}
function deserializeChar(de) {
const sz = deserializeU64(de);
if (sz > 4) {
throw new Error("Deserialize bad char");
}
const bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeString(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeBytes(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeList(de, inner) {
const len = deserializeU64(de);
let out: T[] = [];
for (let i = 0; i < len; i++) {
out.push(inner(de));
}
return out;
}
function deserializeOtherRecord(de) {
return {
a1: deserializeU32(de),
a2: deserializeU64(de),
a3: deserializeS32(de),
a4: deserializeS64(de),
b: deserializeString(de),
c: deserializeBytes(de)
}
}function deserializeSomeRecord(de) {
return {
x: deserializeString(de),
y: deserializeOtherRecord(de),
z: deserializeList(de, (de) => deserializeOtherRecord(de)),
c1: deserializeU32(de),
c2: deserializeU64(de),
c3: deserializeS32(de),
c4: deserializeS64(de)
}
}function deserializeOtherVariant(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: null }
case 1:
return { tag: 1, value: deserializeU32(de) }
case 2:
return { tag: 2, value: deserializeString(de) }
default:
throw new Error("unknown variant case")
}
}function deserializeLoadStoreAllSizes(de) {
return deserializeList(de, (de) => [deserializeString(de), deserializeU8(de), deserializeS8(de), deserializeU16(de), deserializeS16(de), deserializeU32(de), deserializeS32(de), deserializeU64(de), deserializeS64(de), deserializeF32(de), deserializeF64(de), deserializeChar(de)])
}
/**
* @param {Uint8Array[]} x
*/
export async function listU8Param (x) {
return fetch('ipc://localhost/lists/list_u8_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u8_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {Uint16Array[]} x
*/
export async function listU16Param (x) {
return fetch('ipc://localhost/lists/list_u16_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u16_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {Uint32Array[]} x
*/
export async function listU32Param (x) {
return fetch('ipc://localhost/lists/list_u32_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u32_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {BigUint64Array[]} x
*/
export async function listU64Param (x) {
return fetch('ipc://localhost/lists/list_u64_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u64_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {Int8Array[]} x
*/
export async function listS8Param (x) {
return fetch('ipc://localhost/lists/list_s8_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s8_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {Int16Array[]} x
*/
export async function listS16Param (x) {
return fetch('ipc://localhost/lists/list_s16_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s16_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {Int32Array[]} x
*/
export async function listS32Param (x) {
return fetch('ipc://localhost/lists/list_s32_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s32_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {BigInt64Array[]} x
*/
export async function listS64Param (x) {
return fetch('ipc://localhost/lists/list_s64_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s64_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {Float32Array[]} x
*/
export async function listFloat32Param (x) {
return fetch('ipc://localhost/lists/list_float32_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_float32_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @param {Float64Array[]} x
*/
export async function listFloat64Param (x) {
return fetch('ipc://localhost/lists/list_float64_param', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_float64_param', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<Uint8Array[]>}
*/
export async function listU8Ret () {
return fetch('ipc://localhost/lists/list_u8_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u8_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeBytes(de)
})
}
/**
* @returns {Promise<Uint16Array[]>}
*/
export async function listU16Ret () {
return fetch('ipc://localhost/lists/list_u16_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u16_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeU16(de))
})
}
/**
* @returns {Promise<Uint32Array[]>}
*/
export async function listU32Ret () {
return fetch('ipc://localhost/lists/list_u32_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u32_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeU32(de))
})
}
/**
* @returns {Promise<BigUint64Array[]>}
*/
export async function listU64Ret () {
return fetch('ipc://localhost/lists/list_u64_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_u64_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeU64(de))
})
}
/**
* @returns {Promise<Int8Array[]>}
*/
export async function listS8Ret () {
return fetch('ipc://localhost/lists/list_s8_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s8_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeS8(de))
})
}
/**
* @returns {Promise<Int16Array[]>}
*/
export async function listS16Ret () {
return fetch('ipc://localhost/lists/list_s16_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s16_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeS16(de))
})
}
/**
* @returns {Promise<Int32Array[]>}
*/
export async function listS32Ret () {
return fetch('ipc://localhost/lists/list_s32_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s32_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeS32(de))
})
}
/**
* @returns {Promise<BigInt64Array[]>}
*/
export async function listS64Ret () {
return fetch('ipc://localhost/lists/list_s64_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_s64_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeS64(de))
})
}
/**
* @returns {Promise<Float32Array[]>}
*/
export async function listFloat32Ret () {
return fetch('ipc://localhost/lists/list_float32_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_float32_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeF32(de))
})
}
/**
* @returns {Promise<Float64Array[]>}
*/
export async function listFloat64Ret () {
return fetch('ipc://localhost/lists/list_float64_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/list_float64_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeF64(de))
})
}
/**
@@ -144,21 +382,33 @@
* @returns {Promise<[bigint, number][]>}
*/
export async function tupleList (x) {
return fetch('ipc://localhost/lists/tuple_list', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/tuple_list', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => [deserializeS64(de), deserializeU32(de)])
})
}
/**
* @param {string[]} a
*/
export async function stringListArg (a) {
return fetch('ipc://localhost/lists/string_list_arg', { method: "POST", body: JSON.stringify([a]) }).then(r => r.json())
return fetch('ipc://localhost/lists/string_list_arg', { method: "POST", body: JSON.stringify([a]) })
}
/**
* @returns {Promise<string[]>}
*/
export async function stringListRet () {
return fetch('ipc://localhost/lists/string_list_ret', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/lists/string_list_ret', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeString(de))
})
}
/**
@@ -166,7 +416,13 @@
* @returns {Promise<[string, number][]>}
*/
export async function tupleStringList (x) {
return fetch('ipc://localhost/lists/tuple_string_list', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/tuple_string_list', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => [deserializeString(de), deserializeU8(de)])
})
}
/**
@@ -174,7 +430,13 @@
* @returns {Promise<string[]>}
*/
export async function stringList (x) {
return fetch('ipc://localhost/lists/string_list', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/string_list', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeString(de))
})
}
/**
@@ -182,7 +444,13 @@
* @returns {Promise<OtherRecord[]>}
*/
export async function recordList (x) {
return fetch('ipc://localhost/lists/record_list', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/record_list', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeOtherRecord(de))
})
}
/**
@@ -190,7 +458,13 @@
* @returns {Promise<SomeRecord[]>}
*/
export async function recordListReverse (x) {
return fetch('ipc://localhost/lists/record_list_reverse', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/record_list_reverse', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeSomeRecord(de))
})
}
/**
@@ -198,7 +472,13 @@
* @returns {Promise<OtherVariant[]>}
*/
export async function variantList (x) {
return fetch('ipc://localhost/lists/variant_list', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/lists/variant_list', { method: "POST", body: JSON.stringify([x]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeOtherVariant(de))
})
}
/**
@@ -206,6 +486,12 @@
* @returns {Promise<LoadStoreAllSizes>}
*/
export async function loadStoreEverything (a) {
return fetch('ipc://localhost/lists/load_store_everything', { method: "POST", body: JSON.stringify([a]) }).then(r => r.json())
return fetch('ipc://localhost/lists/load_store_everything', { method: "POST", body: JSON.stringify([a]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeLoadStoreAllSizes(de)
})
}

View File

@@ -1,3 +1,23 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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
}
}
/**
* @param {bigint} a1
@@ -18,13 +38,13 @@
* @param {bigint} a16
*/
export async function manyArgs (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) {
return fetch('ipc://localhost/many_arguments/many_args', { method: "POST", body: JSON.stringify([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16]) }).then(r => r.json())
return fetch('ipc://localhost/many_arguments/many_args', { method: "POST", body: JSON.stringify([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16]) })
}
/**
* @param {BigStruct} x
*/
export async function bigArgument (x) {
return fetch('ipc://localhost/many_arguments/big_argument', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/many_arguments/big_argument', { method: "POST", body: JSON.stringify([x]) })
}

View File

@@ -1,35 +1,119 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
function deserializeF32(de) {
const bytes = de.try_take_n(4);
const buf = new ArrayBuffer(4);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat32(0);
}
/**
*/
export async function mra () {
return fetch('ipc://localhost/multi_return/mra', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/multi_return/mra', { method: "POST", body: JSON.stringify([]) })
}
/**
* @returns {Promise<[]>}
*/
export async function mrb () {
return fetch('ipc://localhost/multi_return/mrb', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/multi_return/mrb', { method: "POST", body: JSON.stringify([]) })
}
/**
* @returns {Promise<number>}
*/
export async function mrc () {
return fetch('ipc://localhost/multi_return/mrc', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/multi_return/mrc', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU32(de)
})
}
/**
* @returns {Promise<[number]>}
*/
export async function mrd () {
return fetch('ipc://localhost/multi_return/mrd', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/multi_return/mrd', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU32(de)
})
}
/**
* @returns {Promise<[number, number]>}
*/
export async function mre () {
return fetch('ipc://localhost/multi_return/mre', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/multi_return/mre', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeU32(de), deserializeF32(de)]
})
}

View File

@@ -1,72 +1,220 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeBool(de) {
const val = de.pop();
return val != 0
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeI32(de) {
const n = try_take_varint(de, 32)
return Number(((n >> 1n) as & 0xFFFFFFFFn) ^ (-((n & 0b1n) as & 0xFFFFFFFFn)))
}
function deserializeChar(de) {
const sz = deserializeU64(de);
if (sz > 4) {
throw new Error("Deserialize bad char");
}
const bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeString(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeEmpty(de) {
return {
}
}function deserializeScalars(de) {
return {
a: deserializeU32(de),
b: deserializeU32(de)
}
}function deserializeReallyFlags(de) {
return {
a: deserializeBoolean(de),
b: deserializeBoolean(de),
c: deserializeBoolean(de),
d: deserializeBoolean(de),
e: deserializeBoolean(de),
f: deserializeBoolean(de),
g: deserializeBoolean(de),
h: deserializeBoolean(de),
i: deserializeBoolean(de)
}
}function deserializeAggregates(de) {
return {
a: deserializeScalars(de),
b: deserializeU32(de),
c: deserializeEmpty(de),
d: deserializeString(de),
e: deserializeReallyFlags(de)
}
}
/**
* @param {[string, number]} x
*/
export async function tupleArg (x) {
return fetch('ipc://localhost/records/tuple_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/records/tuple_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<[string, number]>}
*/
export async function tupleResult () {
return fetch('ipc://localhost/records/tuple_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/records/tuple_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeChar(de), deserializeU32(de)]
})
}
/**
* @param {Empty} x
*/
export async function emptyArg (x) {
return fetch('ipc://localhost/records/empty_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/records/empty_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<Empty>}
*/
export async function emptyResult () {
return fetch('ipc://localhost/records/empty_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/records/empty_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeEmpty(de)
})
}
/**
* @param {Scalars} x
*/
export async function scalarArg (x) {
return fetch('ipc://localhost/records/scalar_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/records/scalar_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<Scalars>}
*/
export async function scalarResult () {
return fetch('ipc://localhost/records/scalar_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/records/scalar_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeScalars(de)
})
}
/**
* @param {ReallyFlags} x
*/
export async function flagsArg (x) {
return fetch('ipc://localhost/records/flags_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/records/flags_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<ReallyFlags>}
*/
export async function flagsResult () {
return fetch('ipc://localhost/records/flags_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/records/flags_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeReallyFlags(de)
})
}
/**
* @param {Aggregates} x
*/
export async function aggregateArg (x) {
return fetch('ipc://localhost/records/aggregate_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/records/aggregate_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<Aggregates>}
*/
export async function aggregateResult () {
return fetch('ipc://localhost/records/aggregate_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/records/aggregate_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeAggregates(de)
})
}
/**
@@ -74,6 +222,12 @@
* @returns {Promise<number>}
*/
export async function typedefInout (e) {
return fetch('ipc://localhost/records/typedef_inout', { method: "POST", body: JSON.stringify([e]) }).then(r => r.json())
return fetch('ipc://localhost/records/typedef_inout', { method: "POST", body: JSON.stringify([e]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeS32(de)
})
}

View File

@@ -1,22 +1,53 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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
}
}
/**
* @returns {Promise<A>}
*/
export async function constructorA () {
return fetch('ipc://localhost/resources/constructor_a', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/resources/constructor_a', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return A.deserialize(de)
})
}
/**
* @returns {Promise<B>}
*/
export async function constructorB () {
return fetch('ipc://localhost/resources/constructor_b', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/resources/constructor_b', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return B.deserialize(de)
})
}
class a {
#id: number;
class A {
#id;
/**
*/
@@ -36,10 +67,14 @@ class a {
async f3 (a, b) {
}
deserialize(de) {
const self = new A();
self.#id = deserializeU64(de);
return self
}
}
class b {
#id: number;
class B {
#id;
/**
* @returns {Promise<A>}
@@ -61,4 +96,9 @@ class b {
async f3 (x) {
}
deserialize(de) {
const self = new B();
self.#id = deserializeU64(de);
return self
}
}

View File

@@ -1,15 +1,71 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
/**
*/
export async function f1 () {
return fetch('ipc://localhost/simple_functions/f1', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/simple_functions/f1', { method: "POST", body: JSON.stringify([]) })
}
/**
* @param {number} a
*/
export async function f2 (a) {
return fetch('ipc://localhost/simple_functions/f2', { method: "POST", body: JSON.stringify([a]) }).then(r => r.json())
return fetch('ipc://localhost/simple_functions/f2', { method: "POST", body: JSON.stringify([a]) })
}
/**
@@ -17,21 +73,33 @@
* @param {number} b
*/
export async function f3 (a, b) {
return fetch('ipc://localhost/simple_functions/f3', { method: "POST", body: JSON.stringify([a, b]) }).then(r => r.json())
return fetch('ipc://localhost/simple_functions/f3', { method: "POST", body: JSON.stringify([a, b]) })
}
/**
* @returns {Promise<number>}
*/
export async function f4 () {
return fetch('ipc://localhost/simple_functions/f4', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/simple_functions/f4', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU32(de)
})
}
/**
* @returns {Promise<[number, number]>}
*/
export async function f5 () {
return fetch('ipc://localhost/simple_functions/f5', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/simple_functions/f5', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeU32(de), deserializeU32(de)]
})
}
/**
@@ -41,6 +109,12 @@
* @returns {Promise<[number, number, number]>}
*/
export async function f6 (a, b, c) {
return fetch('ipc://localhost/simple_functions/f6', { method: "POST", body: JSON.stringify([a, b, c]) }).then(r => r.json())
return fetch('ipc://localhost/simple_functions/f6', { method: "POST", body: JSON.stringify([a, b, c]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeU32(de), deserializeU32(de), deserializeU32(de)]
})
}

View File

@@ -1,16 +1,92 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeList(de, inner) {
const len = deserializeU64(de);
let out: T[] = [];
for (let i = 0; i < len; i++) {
out.push(inner(de));
}
return out;
}
/**
* @param {Uint32Array[]} l
*/
export async function simpleList1 (l) {
return fetch('ipc://localhost/simple_lists/simple_list1', { method: "POST", body: JSON.stringify([l]) }).then(r => r.json())
return fetch('ipc://localhost/simple_lists/simple_list1', { method: "POST", body: JSON.stringify([l]) })
}
/**
* @returns {Promise<Uint32Array[]>}
*/
export async function simpleList2 () {
return fetch('ipc://localhost/simple_lists/simple_list2', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/simple_lists/simple_list2', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeU32(de))
})
}
/**
@@ -19,7 +95,13 @@
* @returns {Promise<[Uint32Array[], Uint32Array[]]>}
*/
export async function simpleList3 (a, b) {
return fetch('ipc://localhost/simple_lists/simple_list3', { method: "POST", body: JSON.stringify([a, b]) }).then(r => r.json())
return fetch('ipc://localhost/simple_lists/simple_list3', { method: "POST", body: JSON.stringify([a, b]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeList(de, (de) => deserializeU32(de)), deserializeList(de, (de) => deserializeU32(de))]
})
}
/**
@@ -27,6 +109,12 @@
* @returns {Promise<Uint32Array[][]>}
*/
export async function simpleList4 (l) {
return fetch('ipc://localhost/simple_lists/simple_list4', { method: "POST", body: JSON.stringify([l]) }).then(r => r.json())
return fetch('ipc://localhost/simple_lists/simple_list4', { method: "POST", body: JSON.stringify([l]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeList(de, (de) => deserializeList(de, (de) => deserializeU32(de)))
})
}

View File

@@ -1,8 +1,115 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeString(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeOption(de, inner) {
const disc = de.pop()
switch (disc) {
case 0:
return null
case 1:
return inner(de)
default:
throw new Error('Deserialize bad option')
}
}
function function deserializeResult(de, ok, err) {
const disc = de.pop()
switch (disc) {
case 0:
return ok(de)
case 1:
return err(de)
default:
throw new Error('Deserialize bad result')
}
}
function deserializeError(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return "Success"
case 1:
return "Failure"
default:
throw new Error("unknown enum case")
}
}
/**
* @returns {Promise<Result<string | null, Error>>}
*/
export async function optionTest () {
return fetch('ipc://localhost/small_anonymous/option_test', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/small_anonymous/option_test', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeResult(de, deserializeOption(de, (de) => deserializeString(de)), deserializeError(de))
})
}

View File

@@ -1,16 +1,87 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeString(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
/**
* @param {string} x
*/
export async function a (x) {
return fetch('ipc://localhost/strings/a', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/strings/a', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<string>}
*/
export async function b () {
return fetch('ipc://localhost/strings/b', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/strings/b', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeString(de)
})
}
/**
@@ -19,6 +90,12 @@
* @returns {Promise<string>}
*/
export async function c (a, b) {
return fetch('ipc://localhost/strings/c', { method: "POST", body: JSON.stringify([a, b]) }).then(r => r.json())
return fetch('ipc://localhost/strings/c', { method: "POST", body: JSON.stringify([a, b]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeString(de)
})
}

View File

@@ -1,10 +1,220 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeBool(de) {
const val = de.pop();
return val != 0
}
function deserializeU8(de) {
return de.pop()
}
function deserializeU16(de) {
return try_take_varint(de, 16)
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeI8(de) {
return de.pop()
}
function deserializeI16(de) {
const n = try_take_varint(de, 16)
return Number(((n >> 1n) & 0xFFFFn) ^ (-((n & 0b1n) & 0xFFFFn)))
}
function deserializeI32(de) {
const n = try_take_varint(de, 32)
return Number(((n >> 1n) as & 0xFFFFFFFFn) ^ (-((n & 0b1n) as & 0xFFFFFFFFn)))
}
function deserializeI64(de) {
const n = try_take_varint(de, u64)
return Number(((n >> 1n) & 0xFFFFFFFFFFFFFFFFn) ^ (-((n & 0b1n) & 0xFFFFFFFFFFFFFFFFn)))
}
function deserializeF32(de) {
const bytes = de.try_take_n(4);
const buf = new ArrayBuffer(4);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat32(0);
}
function deserializeF64(de) {
const bytes = de.try_take_n(8);
const buf = new ArrayBuffer(8);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat64(0);
}
function deserializeChar(de) {
const sz = deserializeU64(de);
if (sz > 4) {
throw new Error("Deserialize bad char");
}
const bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeString(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeAllIntegers(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return deserializeBoolean(de)
case 1:
return deserializeU8(de)
case 2:
return deserializeU16(de)
case 3:
return deserializeU32(de)
case 4:
return deserializeU64(de)
case 5:
return deserializeS8(de)
case 6:
return deserializeS16(de)
case 7:
return deserializeS32(de)
case 8:
return deserializeS64(de)
default:
throw new Error("unknown union case")
}
}function deserializeAllFloats(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return deserializeF32(de)
case 1:
return deserializeF64(de)
default:
throw new Error("unknown union case")
}
}function deserializeAllText(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return deserializeChar(de)
case 1:
return deserializeString(de)
default:
throw new Error("unknown union case")
}
}function deserializeDuplicatedS32(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return deserializeS32(de)
case 1:
return deserializeS32(de)
case 2:
return deserializeS32(de)
default:
throw new Error("unknown union case")
}
}function deserializeDistinguishableNum(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return deserializeF64(de)
case 1:
return deserializeS64(de)
default:
throw new Error("unknown union case")
}
}
/**
* @param {AllIntegers} num
* @returns {Promise<AllIntegers>}
*/
export async function addOneInteger (num) {
return fetch('ipc://localhost/unions/add_one_integer', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/add_one_integer', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeAllIntegers(de)
})
}
/**
@@ -12,7 +222,13 @@
* @returns {Promise<AllFloats>}
*/
export async function addOneFloat (num) {
return fetch('ipc://localhost/unions/add_one_float', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/add_one_float', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeAllFloats(de)
})
}
/**
@@ -21,7 +237,13 @@
* @returns {Promise<AllText>}
*/
export async function replaceFirstChar (text, letter) {
return fetch('ipc://localhost/unions/replace_first_char', { method: "POST", body: JSON.stringify([text, letter]) }).then(r => r.json())
return fetch('ipc://localhost/unions/replace_first_char', { method: "POST", body: JSON.stringify([text, letter]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeAllText(de)
})
}
/**
@@ -29,7 +251,13 @@
* @returns {Promise<number>}
*/
export async function identifyInteger (num) {
return fetch('ipc://localhost/unions/identify_integer', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/identify_integer', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU8(de)
})
}
/**
@@ -37,7 +265,13 @@
* @returns {Promise<number>}
*/
export async function identifyFloat (num) {
return fetch('ipc://localhost/unions/identify_float', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/identify_float', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU8(de)
})
}
/**
@@ -45,7 +279,13 @@
* @returns {Promise<number>}
*/
export async function identifyText (text) {
return fetch('ipc://localhost/unions/identify_text', { method: "POST", body: JSON.stringify([text]) }).then(r => r.json())
return fetch('ipc://localhost/unions/identify_text', { method: "POST", body: JSON.stringify([text]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU8(de)
})
}
/**
@@ -53,7 +293,13 @@
* @returns {Promise<DuplicatedS32>}
*/
export async function addOneDuplicated (num) {
return fetch('ipc://localhost/unions/add_one_duplicated', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/add_one_duplicated', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeDuplicatedS32(de)
})
}
/**
@@ -61,7 +307,13 @@
* @returns {Promise<number>}
*/
export async function identifyDuplicated (num) {
return fetch('ipc://localhost/unions/identify_duplicated', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/identify_duplicated', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU8(de)
})
}
/**
@@ -69,7 +321,13 @@
* @returns {Promise<DistinguishableNum>}
*/
export async function addOneDistinguishableNum (num) {
return fetch('ipc://localhost/unions/add_one_distinguishable_num', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/add_one_distinguishable_num', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeDistinguishableNum(de)
})
}
/**
@@ -77,6 +335,12 @@
* @returns {Promise<number>}
*/
export async function identifyDistinguishableNum (num) {
return fetch('ipc://localhost/unions/identify_distinguishable_num', { method: "POST", body: JSON.stringify([num]) }).then(r => r.json())
return fetch('ipc://localhost/unions/identify_distinguishable_num', { method: "POST", body: JSON.stringify([num]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU8(de)
})
}

View File

@@ -1,58 +1,357 @@
export class Deserializer {
source
offset
constructor(bytes) {
this.source = bytes
this.offset = 0
}
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(type) {
const BITS_PER_BYTE = 8;
const BITS_PER_VARINT_BYTE = 7;
const bits = type * BITS_PER_BYTE;
const roundup_bits = bits + (BITS_PER_BYTE - 1);
return Math.floor(roundup_bits / BITS_PER_VARINT_BYTE);
}
function max_of_last_byte(type) {
let extra_bits = type % 7;
return (1 << extra_bits) - 1;
}
function try_take_varint(de, type) {
let out = 0n;
for (let i = 0; i < varint_max(type); i++) {
const val = de.pop();
const carry = BigInt(val & 0x7F);
out |= carry << (7n * BigInt(i));
if ((val & 0x80) === 0) {
if (i === varint_max(type) - 1 && val > max_of_last_byte(type)) {
throw new Error('deserialize bad variant')
} else {
return out
}
}
}
throw new Error('deserialize bad variant')
}
function deserializeBool(de) {
const val = de.pop();
return val != 0
}
function deserializeU8(de) {
return de.pop()
}
function deserializeU32(de) {
return try_take_varint(de, 32)
}
function deserializeU64(de) {
return try_take_varint(de, 64)
}
function deserializeI32(de) {
const n = try_take_varint(de, 32)
return Number(((n >> 1n) as & 0xFFFFFFFFn) ^ (-((n & 0b1n) as & 0xFFFFFFFFn)))
}
function deserializeI64(de) {
const n = try_take_varint(de, u64)
return Number(((n >> 1n) & 0xFFFFFFFFFFFFFFFFn) ^ (-((n & 0b1n) & 0xFFFFFFFFFFFFFFFFn)))
}
function deserializeF32(de) {
const bytes = de.try_take_n(4);
const buf = new ArrayBuffer(4);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat32(0);
}
function deserializeF64(de) {
const bytes = de.try_take_n(8);
const buf = new ArrayBuffer(8);
const view = new DataView(buf);
bytes.reverse().forEach((v, i) => view.setUint8(i, v));
return view.getFloat64(0);
}
function deserializeString(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeBytes(de) {
const sz = deserializeU64(de);
let bytes = de.try_take_n(Number(sz));
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
function deserializeOption(de, inner) {
const disc = de.pop()
switch (disc) {
case 0:
return null
case 1:
return inner(de)
default:
throw new Error('Deserialize bad option')
}
}
function function deserializeResult(de, ok, err) {
const disc = de.pop()
switch (disc) {
case 0:
return ok(de)
case 1:
return err(de)
default:
throw new Error('Deserialize bad result')
}
}
function deserializeE1(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return "A"
default:
throw new Error("unknown enum case")
}
}function deserializeU1(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return deserializeU32(de)
case 1:
return deserializeF32(de)
default:
throw new Error("unknown union case")
}
}function deserializeEmpty(de) {
return {
}
}function deserializeV1(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: null }
case 1:
return { tag: 1, value: deserializeU1(de) }
case 2:
return { tag: 2, value: deserializeE1(de) }
case 3:
return { tag: 3, value: deserializeString(de) }
case 4:
return { tag: 4, value: deserializeEmpty(de) }
case 5:
return { tag: 5, value: null }
case 6:
return { tag: 6, value: deserializeU32(de) }
default:
throw new Error("unknown variant case")
}
}function deserializeCasts1(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: deserializeS32(de) }
case 1:
return { tag: 1, value: deserializeF32(de) }
default:
throw new Error("unknown variant case")
}
}function deserializeCasts2(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: deserializeF64(de) }
case 1:
return { tag: 1, value: deserializeF32(de) }
default:
throw new Error("unknown variant case")
}
}function deserializeCasts3(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: deserializeF64(de) }
case 1:
return { tag: 1, value: deserializeU64(de) }
default:
throw new Error("unknown variant case")
}
}function deserializeCasts4(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: deserializeU32(de) }
case 1:
return { tag: 1, value: deserializeS64(de) }
default:
throw new Error("unknown variant case")
}
}function deserializeCasts5(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: deserializeF32(de) }
case 1:
return { tag: 1, value: deserializeS64(de) }
default:
throw new Error("unknown variant case")
}
}function deserializeCasts6(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return { tag: 0, value: [deserializeF32(de), deserializeU32(de)] }
case 1:
return { tag: 1, value: [deserializeU32(de), deserializeU32(de)] }
default:
throw new Error("unknown variant case")
}
}function deserializeMyErrno(de) {
const disc = deserializeU32(de)
switch (disc) {
case 0:
return "Bad1"
case 1:
return "Bad2"
default:
throw new Error("unknown enum case")
}
}function deserializeIsClone(de) {
return {
v1: deserializeV1(de)
}
}
/**
* @param {E1} x
*/
export async function e1Arg (x) {
return fetch('ipc://localhost/variants/e1_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/variants/e1_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<E1>}
*/
export async function e1Result () {
return fetch('ipc://localhost/variants/e1_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/e1_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeE1(de)
})
}
/**
* @param {U1} x
*/
export async function u1Arg (x) {
return fetch('ipc://localhost/variants/u1_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/variants/u1_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<U1>}
*/
export async function u1Result () {
return fetch('ipc://localhost/variants/u1_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/u1_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeU1(de)
})
}
/**
* @param {V1} x
*/
export async function v1Arg (x) {
return fetch('ipc://localhost/variants/v1_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/variants/v1_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<V1>}
*/
export async function v1Result () {
return fetch('ipc://localhost/variants/v1_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/v1_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeV1(de)
})
}
/**
* @param {boolean} x
*/
export async function boolArg (x) {
return fetch('ipc://localhost/variants/bool_arg', { method: "POST", body: JSON.stringify([x]) }).then(r => r.json())
return fetch('ipc://localhost/variants/bool_arg', { method: "POST", body: JSON.stringify([x]) })
}
/**
* @returns {Promise<boolean>}
*/
export async function boolResult () {
return fetch('ipc://localhost/variants/bool_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/bool_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeBoolean(de)
})
}
/**
@@ -65,14 +364,20 @@
* @param {boolean | null | null} g
*/
export async function optionArg (a, b, c, d, e, f, g) {
return fetch('ipc://localhost/variants/option_arg', { method: "POST", body: JSON.stringify([a, b, c, d, e, f, g]) }).then(r => r.json())
return fetch('ipc://localhost/variants/option_arg', { method: "POST", body: JSON.stringify([a, b, c, d, e, f, g]) })
}
/**
* @returns {Promise<[boolean | null, [] | null, number | null, E1 | null, number | null, U1 | null, boolean | null | null]>}
*/
export async function optionResult () {
return fetch('ipc://localhost/variants/option_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/option_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeOption(de, (de) => deserializeBoolean(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) => deserializeBoolean(de)))]
})
}
/**
@@ -85,7 +390,13 @@
* @returns {Promise<[Casts1, Casts2, Casts3, Casts4, Casts5, Casts6]>}
*/
export async function casts (a, b, c, d, e, f) {
return fetch('ipc://localhost/variants/casts', { method: "POST", body: JSON.stringify([a, b, c, d, e, f]) }).then(r => r.json())
return fetch('ipc://localhost/variants/casts', { method: "POST", body: JSON.stringify([a, b, c, d, e, f]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeCasts1(de), deserializeCasts2(de), deserializeCasts3(de), deserializeCasts4(de), deserializeCasts5(de), deserializeCasts6(de)]
})
}
/**
@@ -97,90 +408,156 @@
* @param {Result<string, Uint8Array[]>} f
*/
export async function resultArg (a, b, c, d, e, f) {
return fetch('ipc://localhost/variants/result_arg', { method: "POST", body: JSON.stringify([a, b, c, d, e, f]) }).then(r => r.json())
return fetch('ipc://localhost/variants/result_arg', { method: "POST", body: JSON.stringify([a, b, c, d, e, f]) })
}
/**
* @returns {Promise<[Result<_, _>, Result<_, E1>, Result<E1, _>, Result<[], []>, Result<number, V1>, Result<string, Uint8Array[]>]>}
*/
export async function resultResult () {
return fetch('ipc://localhost/variants/result_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/result_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return [deserializeResult(de, () => {}, () => {}), deserializeResult(de, () => {}, deserializeE1(de)), deserializeResult(de, deserializeE1(de), () => {}), deserializeResult(de, [], []), deserializeResult(de, deserializeU32(de), deserializeV1(de)), deserializeResult(de, deserializeString(de), deserializeBytes(de))]
})
}
/**
* @returns {Promise<Result<number, MyErrno>>}
*/
export async function returnResultSugar () {
return fetch('ipc://localhost/variants/return_result_sugar', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_result_sugar', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeResult(de, deserializeS32(de), deserializeMyErrno(de))
})
}
/**
* @returns {Promise<Result<_, MyErrno>>}
*/
export async function returnResultSugar2 () {
return fetch('ipc://localhost/variants/return_result_sugar2', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_result_sugar2', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeResult(de, () => {}, deserializeMyErrno(de))
})
}
/**
* @returns {Promise<Result<MyErrno, MyErrno>>}
*/
export async function returnResultSugar3 () {
return fetch('ipc://localhost/variants/return_result_sugar3', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_result_sugar3', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeResult(de, deserializeMyErrno(de), deserializeMyErrno(de))
})
}
/**
* @returns {Promise<Result<[number, number], MyErrno>>}
*/
export async function returnResultSugar4 () {
return fetch('ipc://localhost/variants/return_result_sugar4', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_result_sugar4', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeResult(de, [deserializeS32(de), deserializeU32(de)], deserializeMyErrno(de))
})
}
/**
* @returns {Promise<number | null>}
*/
export async function returnOptionSugar () {
return fetch('ipc://localhost/variants/return_option_sugar', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_option_sugar', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeOption(de, (de) => deserializeS32(de))
})
}
/**
* @returns {Promise<MyErrno | null>}
*/
export async function returnOptionSugar2 () {
return fetch('ipc://localhost/variants/return_option_sugar2', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_option_sugar2', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeOption(de, (de) => deserializeMyErrno(de))
})
}
/**
* @returns {Promise<Result<number, number>>}
*/
export async function resultSimple () {
return fetch('ipc://localhost/variants/result_simple', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/result_simple', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeResult(de, deserializeU32(de), deserializeS32(de))
})
}
/**
* @param {IsClone} a
*/
export async function isCloneArg (a) {
return fetch('ipc://localhost/variants/is_clone_arg', { method: "POST", body: JSON.stringify([a]) }).then(r => r.json())
return fetch('ipc://localhost/variants/is_clone_arg', { method: "POST", body: JSON.stringify([a]) })
}
/**
* @returns {Promise<IsClone>}
*/
export async function isCloneReturn () {
return fetch('ipc://localhost/variants/is_clone_return', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/is_clone_return', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeIsClone(de)
})
}
/**
* @returns {Promise<[number | null]>}
*/
export async function returnNamedOption () {
return fetch('ipc://localhost/variants/return_named_option', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_named_option', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeOption(de, (de) => deserializeU8(de))
})
}
/**
* @returns {Promise<[Result<number, MyErrno>]>}
*/
export async function returnNamedResult () {
return fetch('ipc://localhost/variants/return_named_result', { method: "POST", body: JSON.stringify([]) }).then(r => r.json())
return fetch('ipc://localhost/variants/return_named_result', { method: "POST", body: JSON.stringify([]) })
.then(r => r.arrayBuffer())
.then(bytes => {
const de = new Deserializer(Uint8Array.from(bytes))
return deserializeResult(de, deserializeU8(de), deserializeMyErrno(de))
})
}

View File

@@ -10,8 +10,10 @@ use quote::quote;
use syn::parse_quote;
use tauri_bindgen_core::Generate;
use tauri_bindgen_core::GeneratorBuilder;
use tauri_bindgen_core::TypeInfo;
use tauri_bindgen_core::TypeInfos;
use tauri_bindgen_gen_rust::FnSig;
use tauri_bindgen_gen_rust::{BorrowMode, RustGenerator, TypeInfo, TypeInfos};
use tauri_bindgen_gen_rust::{BorrowMode, RustGenerator};
use wit_parser::{Function, Interface};
#[derive(Default, Debug, Clone)]
@@ -170,7 +172,7 @@ impl RustGenerator for RustWasm {
}
impl tauri_bindgen_core::Generate for RustWasm {
fn to_tokens(&self) -> TokenStream {
fn to_tokens(&mut self) -> TokenStream {
let docs = self.print_docs(&self.interface.docs);
let ident = format_ident!("{}", self.interface.ident.to_snake_case());
@@ -200,7 +202,7 @@ impl tauri_bindgen_core::Generate for RustWasm {
}
}
fn to_file(&self) -> (PathBuf, String) {
fn to_file(&mut self) -> (PathBuf, String) {
let mut filename = PathBuf::from(self.interface.ident.to_kebab_case());
filename.set_extension("rs");

View File

@@ -11,7 +11,7 @@ fn gen_interface(
) -> (String, String) {
let iface = wit_parser::parse_and_resolve_str(&input, |_| false).unwrap();
let gen = opts.build(iface);
let mut gen = opts.build(iface);
let (filename, contents) = gen.to_file();
(filename.to_str().unwrap().to_string(), contents)

View File

@@ -342,7 +342,7 @@ fn print_docs(docs: &str) -> String {
}
impl Generate for TypeScript {
fn to_file(&self) -> (std::path::PathBuf, String) {
fn to_file(&mut self) -> (std::path::PathBuf, String) {
let result_ty = self
.interface
.functions

View File

@@ -8,7 +8,7 @@ fn gen_interface(
) -> (String, String) {
let iface = wit_parser::parse_and_resolve_str(&input, |_| false).unwrap();
let gen = opts.build(iface);
let mut gen = opts.build(iface);
let (filename, contents) = gen.to_file();
(filename.to_str().unwrap().to_string(), contents)

View File

@@ -13,9 +13,9 @@ use heck::{ToSnakeCase, ToUpperCamelCase};
use proc_macro2::TokenStream;
use quote::format_ident;
use quote::quote;
use tauri_bindgen_core::{Generate, GeneratorBuilder};
use tauri_bindgen_core::{Generate, GeneratorBuilder, TypeInfos, TypeInfo};
use tauri_bindgen_gen_rust::{
print_generics, BorrowMode, FnSig, RustGenerator, TypeInfo, TypeInfos,
print_generics, BorrowMode, FnSig, RustGenerator,
};
use wit_parser::{Function, Interface, Type, TypeDefKind, FunctionResult};
@@ -233,7 +233,7 @@ impl RustGenerator for Host {
}
impl Generate for Host {
fn to_tokens(&self) -> TokenStream {
fn to_tokens(&mut self) -> TokenStream {
let docs = self.print_docs(&self.interface.docs);
let ident = format_ident!("{}", self.interface.ident.to_snake_case());
@@ -286,7 +286,7 @@ impl Generate for Host {
}
}
fn to_file(&self) -> (PathBuf, String) {
fn to_file(&mut self) -> (PathBuf, String) {
let mut filename = PathBuf::from(self.interface.ident.to_kebab_case());
filename.set_extension("rs");

View File

@@ -11,7 +11,7 @@ fn gen_interface(
) -> (String, String) {
let iface = wit_parser::parse_and_resolve_str(&input, |_| false).unwrap();
let gen = opts.build(iface);
let mut gen = opts.build(iface);
let (filename, contents) = gen.to_file();
(filename.to_str().unwrap().to_string(), contents)

View File

@@ -222,7 +222,7 @@ fn print_docs(docs: &str) -> String {
}
impl Generate for Markdown {
fn to_file(&self) -> (std::path::PathBuf, String) {
fn to_file(&mut self) -> (std::path::PathBuf, String) {
let ident = &self.interface.ident;
let docs = print_docs(&self.interface.docs);
let typedefs = self

View File

@@ -8,10 +8,10 @@ rust-version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tauri-bindgen-core.workspace = true
wit-parser.workspace = true
heck.workspace = true
quote.workspace = true
proc-macro2.workspace = true
syn.workspace = true
bitflags.workspace = true
log.workspace = true

View File

@@ -5,6 +5,7 @@ use proc_macro2::{Ident, Literal, TokenStream};
use quote::{format_ident, quote};
use std::{collections::HashMap, ops::Index};
use syn::Lifetime;
use tauri_bindgen_core::{TypeInfos, TypeInfo, flags_repr};
use wit_parser::{
EnumCase, FlagsField, Function, FunctionResult, Int, Interface, RecordField, Type,
@@ -618,17 +619,6 @@ pub fn print_generics(info: TypeInfo, mode: &BorrowMode) -> Option<TokenStream>
})
}
#[must_use]
pub fn flags_repr(fields: &[FlagsField]) -> Int {
match fields.len() {
n if n <= 8 => Int::U8,
n if n <= 16 => Int::U16,
n if n <= 32 => Int::U32,
n if n <= 64 => Int::U64,
_ => panic!("too many flags to fit in a repr"),
}
}
#[derive(Clone, PartialEq, Eq)]
pub enum BorrowMode {
Owned,
@@ -651,136 +641,3 @@ pub struct TypeVariant {
pub ident: Ident,
pub borrow_mode: BorrowMode,
}
// #[must_use]
// pub fn uses_two_names(info: TypeInfo) -> bool {
// // info.contains(TypeInfo::HAS_LIST) && info.contains(TypeInfo::PARAM | TypeInfo::RESULT)
// }
bitflags::bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct TypeInfo: u32 {
/// Whether or not this type is ever used (transitively) within the
/// parameter of a function.
const PARAM = 0b0000_0001;
/// Whether or not this type is ever used (transitively) within the
/// result of a function.
const RESULT = 0b0000_0010;
/// Whether or not this type (transitively) has a list.
const HAS_LIST = 0b0000_1000;
}
}
#[derive(Debug, Default)]
pub struct TypeInfos {
infos: HashMap<TypeDefId, TypeInfo>,
}
impl TypeInfos {
#[must_use]
pub fn new() -> Self {
TypeInfos::default()
}
pub fn collect_param_info(&mut self, typedefs: &TypeDefArena, params: &[(String, Type)]) {
for (_, ty) in params {
self.collect_type_info(typedefs, ty, TypeInfo::PARAM);
}
}
pub fn collect_result_info(&mut self, typedefs: &TypeDefArena, result: &FunctionResult) {
match result {
FunctionResult::Anon(ty) => {
self.collect_type_info(typedefs, ty, TypeInfo::RESULT);
}
FunctionResult::Named(results) => {
for (_, ty) in results {
self.collect_type_info(typedefs, ty, TypeInfo::RESULT);
}
}
}
}
fn collect_typedef_info(
&mut self,
typedefs: &TypeDefArena,
id: TypeDefId,
base_info: TypeInfo,
) -> TypeInfo {
let mut info = base_info;
match &typedefs[id].kind {
TypeDefKind::Alias(ty) => {
info |= self.collect_type_info(typedefs, ty, base_info);
}
TypeDefKind::Record(fields) => {
for field in fields {
info |= self.collect_type_info(typedefs, &field.ty, base_info);
}
}
TypeDefKind::Variant(cases) => {
for case in cases {
if let Some(ty) = &case.ty {
info |= self.collect_type_info(typedefs, ty, base_info);
}
}
}
TypeDefKind::Union(cases) => {
for case in cases {
info |= self.collect_type_info(typedefs, &case.ty, base_info);
}
}
_ => {}
}
log::debug!("collected info for {:?}: {:?}", typedefs[id].ident, info,);
self.infos
.entry(id)
.and_modify(|i| *i |= info)
.or_insert(info);
info
}
fn collect_type_info(
&mut self,
typedefs: &TypeDefArena,
ty: &Type,
base_info: TypeInfo,
) -> TypeInfo {
match ty {
Type::String => base_info | TypeInfo::HAS_LIST,
Type::List(ty) => self.collect_type_info(typedefs, ty, base_info) | TypeInfo::HAS_LIST,
Type::Option(ty) => self.collect_type_info(typedefs, ty, base_info),
Type::Tuple(types) => {
let mut info = base_info;
for ty in types {
info |= self.collect_type_info(typedefs, ty, base_info);
}
info
}
Type::Result { ok, err } => {
let mut info = base_info;
if let Some(ty) = &ok {
info |= self.collect_type_info(typedefs, ty, base_info);
}
if let Some(ty) = &err {
info |= self.collect_type_info(typedefs, ty, base_info);
}
info
}
Type::Id(id) => base_info | self.collect_typedef_info(typedefs, *id, base_info),
_ => base_info,
}
}
}
impl Index<TypeDefId> for TypeInfos {
type Output = TypeInfo;
fn index(&self, id: TypeDefId) -> &Self::Output {
&self.infos[&id]
}
}

View File

@@ -22,7 +22,7 @@ where
let iface =
wit_parser::parse_and_resolve_file(&input.file, |t| input.skip.contains(t)).unwrap();
let gen = input.builder.build(iface);
let mut gen = input.builder.build(iface);
let mut tokens = gen.to_tokens();
let filepath = input.file.to_string_lossy();

View File

@@ -184,7 +184,7 @@ where
let iface = wit_parser::parse_and_resolve_file(&opts.wit, |t| skipset.contains(t))?;
let gen = builder.build(iface);
let mut gen = builder.build(iface);
Ok(gen.to_file())
}