mirror of
https://github.com/tauri-apps/tauri-bindgen.git
synced 2026-01-31 00:45:21 +01:00
feat: port postcard deserialization to guest-js
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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([]) })
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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]) })
|
||||
}
|
||||
|
||||
|
||||
@@ -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)]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user