Skip to content

Commit

Permalink
Added support for VectorIntoWasmAbi and VectorFromWasmAbi (#41)
Browse files Browse the repository at this point in the history
Added vector support for using tsify to export types and auto-generate bindings for vectors of structs.
  • Loading branch information
eneoli authored Aug 5, 2024
1 parent 2492b09 commit 9277dd5
Show file tree
Hide file tree
Showing 12 changed files with 494 additions and 665 deletions.
6 changes: 1 addition & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ categories = ["wasm"]
[dependencies]
tsify-next-macros = { path = "tsify-next-macros", version = "0.5.3" }
wasm-bindgen = { version = "0.2.86", optional = true }
serde = { version = "1.0", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }
serde-wasm-bindgen = { version = "0.6", optional = true }
gloo-utils = { version = "0.2", optional = true }
Expand All @@ -26,10 +26,6 @@ indoc = "2.0.5"
js-sys = "0.3"
macrotest = "1.0"
pretty_assertions = "1.4.0"
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.6"
serde_json = "1.0"
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3"

[features]
Expand Down
23 changes: 23 additions & 0 deletions tests-e2e/reference_output/test4/test4.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* tslint:disable */
/* eslint-disable */
/**
* @param {Point} point
*/
export function consume(point: Point): void;
/**
* @returns {Point}
*/
export function into_js(): Point;
/**
* @param {(Point)[]} points
*/
export function consume_vector(points: (Point)[]): void;
/**
* @returns {(Point)[]}
*/
export function vector_into_js(): (Point)[];
export interface Point {
x: number;
y: number;
}

21 changes: 21 additions & 0 deletions tests-e2e/test4/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "test4"
publish = false
version = "0.1.0"
edition = "2021"

[dependencies]
wasm-bindgen = "0.2"
tsify-next = { path = "../..", version = "*" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[dev-dependencies]
wasm-bindgen-test = "0.3"

[lib]
path = "entry_point.rs"
crate-type = ["cdylib"]

[build-dependencies]
wasm-bindgen-cli = "0.2"
30 changes: 30 additions & 0 deletions tests-e2e/test4/entry_point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use serde::{Deserialize, Serialize};
use tsify_next::Tsify;
use wasm_bindgen::prelude::*;

#[derive(Tsify, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Point {
x: i32,
y: i32,
}

#[wasm_bindgen]
pub fn consume(point: Point) {}

#[wasm_bindgen]
pub fn into_js() -> Point {
Point { x: 0, y: 0 }
}

#[wasm_bindgen]
pub fn consume_vector(points: Vec<Point>) {}

#[wasm_bindgen]
pub fn vector_into_js() -> Vec<Point> {
vec![
Point { x: 1, y: 6 },
Point { x: 2, y: 5 },
Point { x: 3, y: 4 },
]
}
231 changes: 75 additions & 156 deletions tests/expand/borrow.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,164 +11,15 @@ const _: () = {
use tsify_next::Tsify;
use wasm_bindgen::{
convert::{
FromWasmAbi, IntoWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi,
RefFromWasmAbi,
FromWasmAbi, VectorFromWasmAbi, IntoWasmAbi, VectorIntoWasmAbi,
OptionFromWasmAbi, OptionIntoWasmAbi, RefFromWasmAbi,
},
describe::WasmDescribe, prelude::*,
describe::WasmDescribe, describe::WasmDescribeVector, prelude::*,
};
#[automatically_derived]
///
#[repr(transparent)]
pub struct JsType {
obj: wasm_bindgen::JsValue,
}
#[automatically_derived]
const _: () = {
use wasm_bindgen::convert::TryFromJsValue;
use wasm_bindgen::convert::{IntoWasmAbi, FromWasmAbi};
use wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
use wasm_bindgen::convert::{RefFromWasmAbi, LongRefFromWasmAbi};
use wasm_bindgen::describe::WasmDescribe;
use wasm_bindgen::{JsValue, JsCast, JsObject};
use wasm_bindgen::__rt::core;
impl WasmDescribe for JsType {
fn describe() {
use wasm_bindgen::describe::*;
inform(NAMED_EXTERNREF);
inform(6u32);
inform(66u32);
inform(111u32);
inform(114u32);
inform(114u32);
inform(111u32);
inform(119u32);
}
}
impl IntoWasmAbi for JsType {
type Abi = <JsValue as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self) -> Self::Abi {
self.obj.into_abi()
}
}
impl OptionIntoWasmAbi for JsType {
#[inline]
fn none() -> Self::Abi {
0
}
}
impl<'a> OptionIntoWasmAbi for &'a JsType {
#[inline]
fn none() -> Self::Abi {
0
}
}
impl FromWasmAbi for JsType {
type Abi = <JsValue as FromWasmAbi>::Abi;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
JsType {
obj: JsValue::from_abi(js).into(),
}
}
}
impl OptionFromWasmAbi for JsType {
#[inline]
fn is_none(abi: &Self::Abi) -> bool {
*abi == 0
}
}
impl<'a> IntoWasmAbi for &'a JsType {
type Abi = <&'a JsValue as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self) -> Self::Abi {
(&self.obj).into_abi()
}
}
impl RefFromWasmAbi for JsType {
type Abi = <JsValue as RefFromWasmAbi>::Abi;
type Anchor = core::mem::ManuallyDrop<JsType>;
#[inline]
unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
let tmp = <JsValue as RefFromWasmAbi>::ref_from_abi(js);
core::mem::ManuallyDrop::new(JsType {
obj: core::mem::ManuallyDrop::into_inner(tmp).into(),
})
}
}
impl LongRefFromWasmAbi for JsType {
type Abi = <JsValue as LongRefFromWasmAbi>::Abi;
type Anchor = JsType;
#[inline]
unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
let tmp = <JsValue as LongRefFromWasmAbi>::long_ref_from_abi(js);
JsType { obj: tmp.into() }
}
}
impl From<JsValue> for JsType {
#[inline]
fn from(obj: JsValue) -> JsType {
JsType { obj: obj.into() }
}
}
impl AsRef<JsValue> for JsType {
#[inline]
fn as_ref(&self) -> &JsValue {
self.obj.as_ref()
}
}
impl AsRef<JsType> for JsType {
#[inline]
fn as_ref(&self) -> &JsType {
self
}
}
impl From<JsType> for JsValue {
#[inline]
fn from(obj: JsType) -> JsValue {
obj.obj.into()
}
}
impl JsCast for JsType {
fn instanceof(val: &JsValue) -> bool {
#[cfg(
not(
all(
target_arch = "wasm32",
not(any(target_os = "emscripten", target_os = "wasi"))
)
)
)]
unsafe fn __wbg_instanceof_JsType_1641ac20ec916ae7(_: u32) -> u32 {
{
::std::rt::begin_panic(
"cannot check instanceof on non-wasm targets",
);
};
}
unsafe {
let idx = val.into_abi();
__wbg_instanceof_JsType_1641ac20ec916ae7(idx) != 0
}
}
#[inline]
fn unchecked_from_js(val: JsValue) -> Self {
JsType { obj: val.into() }
}
#[inline]
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
unsafe { &*(val as *const JsValue as *const JsType) }
}
}
impl JsObject for JsType {}
};
#[automatically_derived]
impl core::ops::Deref for JsType {
type Target = wasm_bindgen::JsValue;
#[inline]
fn deref(&self) -> &wasm_bindgen::JsValue {
&self.obj
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "Borrow")]
pub type JsType;
}
impl<'a> Tsify for Borrow<'a> {
type JsType = JsType;
Expand All @@ -179,12 +30,20 @@ const _: () = {
large_number_types_as_bigints: false,
};
}
#[wasm_bindgen(typescript_custom_section)]
const TS_APPEND_CONTENT: &'static str = "export interface Borrow {\n raw: string;\n cow: string;\n}";
impl<'a> WasmDescribe for Borrow<'a> {
#[inline]
fn describe() {
<Self as Tsify>::JsType::describe()
}
}
impl<'a> WasmDescribeVector for Borrow<'a> {
#[inline]
fn describe_vector() {
<Self as Tsify>::JsType::describe_vector()
}
}
impl<'a> IntoWasmAbi for Borrow<'a>
where
Borrow<'a>: _serde::Serialize,
Expand Down Expand Up @@ -267,6 +126,47 @@ const _: () = {
}
}
}
impl<'a> VectorIntoWasmAbi for Borrow<'a>
where
Borrow<'a>: _serde::Serialize,
{
type Abi = <JsType as VectorIntoWasmAbi>::Abi;
#[inline]
fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi {
let values = vector
.iter()
.map(|value| match value.into_js() {
Ok(js) => js.into(),
Err(err) => {
let loc = core::panic::Location::caller();
let msg = {
let res = ::alloc::fmt::format(
format_args!(
"(Converting type failed) {0} ({1}:{2}:{3})", err, loc
.file(), loc.line(), loc.column(),
),
);
res
};
{
#[cold]
#[track_caller]
#[inline(never)]
#[rustc_const_panic_str]
#[rustc_do_not_const_check]
const fn panic_cold_display<T: ::core::fmt::Display>(
arg: &T,
) -> ! {
::core::panicking::panic_display(arg)
}
panic_cold_display(&msg);
};
}
})
.collect();
JsValue::vector_into_abi(values)
}
}
impl<'a> FromWasmAbi for Borrow<'a>
where
Self: _serde::de::DeserializeOwned,
Expand Down Expand Up @@ -311,4 +211,23 @@ const _: () = {
SelfOwner(result.unwrap_throw())
}
}
impl<'a> VectorFromWasmAbi for Borrow<'a>
where
Self: _serde::de::DeserializeOwned,
{
type Abi = <JsType as VectorFromWasmAbi>::Abi;
#[inline]
unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]> {
JsValue::vector_from_abi(js)
.into_iter()
.map(|value| {
let result = Self::from_js(value);
if let Err(err) = result {
wasm_bindgen::throw_str(err.to_string().as_ref());
}
result.unwrap_throw()
})
.collect()
}
}
};
Loading

0 comments on commit 9277dd5

Please sign in to comment.