From f26cd4aa7b879951c3a60afd20eb158edebba056 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Tue, 2 Nov 2021 00:34:19 +0800 Subject: [PATCH] feat(napi): implement `Either` type --- crates/backend/src/codegen/enum.rs | 4 + crates/backend/src/codegen/struct.rs | 8 + crates/backend/src/typegen.rs | 4 + crates/napi/src/bindgen_runtime/js_values.rs | 10 +- .../src/bindgen_runtime/js_values/array.rs | 8 + .../src/bindgen_runtime/js_values/boolean.rs | 4 + .../src/bindgen_runtime/js_values/buffer.rs | 4 + .../src/bindgen_runtime/js_values/either.rs | 359 ++++++++++++++++++ .../napi/src/bindgen_runtime/js_values/map.rs | 4 + .../napi/src/bindgen_runtime/js_values/nil.rs | 8 + .../src/bindgen_runtime/js_values/number.rs | 4 + .../src/bindgen_runtime/js_values/object.rs | 4 + .../src/bindgen_runtime/js_values/string.rs | 16 + examples/napi/__test__/typegen.spec.ts.md | 7 + examples/napi/__test__/typegen.spec.ts.snap | Bin 700 -> 763 bytes examples/napi/__test__/values.spec.ts | 30 ++ examples/napi/index.d.ts | 7 + examples/napi/src/either.rs | 57 +++ examples/napi/src/lib.rs | 1 + 19 files changed, 538 insertions(+), 1 deletion(-) create mode 100644 crates/napi/src/bindgen_runtime/js_values/either.rs create mode 100644 examples/napi/src/either.rs diff --git a/crates/backend/src/codegen/enum.rs b/crates/backend/src/codegen/enum.rs index a8857afe..b016b577 100644 --- a/crates/backend/src/codegen/enum.rs +++ b/crates/backend/src/codegen/enum.rs @@ -38,6 +38,10 @@ impl NapiEnum { fn type_name() -> &'static str { #name_str } + + fn value_type() -> napi::ValueType { + napi::ValueType::Object + } } impl ValidateNapiValue for #name { diff --git a/crates/backend/src/codegen/struct.rs b/crates/backend/src/codegen/struct.rs index e29cd9ba..c85d9dc7 100644 --- a/crates/backend/src/codegen/struct.rs +++ b/crates/backend/src/codegen/struct.rs @@ -16,6 +16,10 @@ fn gen_napi_value_map_impl(name: &Ident, to_napi_val_impl: TokenStream) -> Token fn type_name() -> &'static str { #name_str } + + fn value_type() -> napi::ValueType { + napi::ValueType::Function + } } #to_napi_val_impl @@ -255,6 +259,10 @@ impl NapiStruct { fn type_name() -> &'static str { #name_str } + + fn value_type() -> napi::ValueType { + napi::ValueType::Object + } } impl ToNapiValue for #name { diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index f2404e8f..7839c9f8 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -59,6 +59,10 @@ static KNOWN_TYPES: Lazy> = Lazy::new(|| { ("Vec", "Array<{}>"), ("Option", "{} | null"), ("Result", "Error | {}"), + ("Either", "{} | {}"), + ("Either3", "{} | {} | {}"), + ("Either4", "{} | {} | {} | {}"), + ("Either5", "{} | {} | {} | {} | {}"), ]); map diff --git a/crates/napi/src/bindgen_runtime/js_values.rs b/crates/napi/src/bindgen_runtime/js_values.rs index 5e296f7c..7f35f72c 100644 --- a/crates/napi/src/bindgen_runtime/js_values.rs +++ b/crates/napi/src/bindgen_runtime/js_values.rs @@ -4,6 +4,7 @@ use std::ptr; mod array; mod boolean; mod buffer; +mod either; mod map; mod nil; mod number; @@ -14,6 +15,7 @@ mod string; pub use array::*; pub use buffer::*; +pub use either::*; pub use nil::*; pub use object::*; pub use string::*; @@ -23,6 +25,8 @@ pub use string::latin1_string::*; pub trait TypeName { fn type_name() -> &'static str; + + fn value_type() -> ValueType; } pub trait ToNapiValue { @@ -114,10 +118,14 @@ pub trait ValidateNapiValue: FromNapiValue + TypeName { } } -impl TypeName for Option { +impl TypeName for Option { fn type_name() -> &'static str { "Option" } + + fn value_type() -> ValueType { + T::value_type() + } } impl FromNapiValue for Option diff --git a/crates/napi/src/bindgen_runtime/js_values/array.rs b/crates/napi/src/bindgen_runtime/js_values/array.rs index c2500df5..3d9587f4 100644 --- a/crates/napi/src/bindgen_runtime/js_values/array.rs +++ b/crates/napi/src/bindgen_runtime/js_values/array.rs @@ -74,6 +74,10 @@ impl TypeName for Array { fn type_name() -> &'static str { "Array" } + + fn value_type() -> ValueType { + ValueType::Object + } } impl ToNapiValue for Array { @@ -122,6 +126,10 @@ impl TypeName for Vec { fn type_name() -> &'static str { "Array" } + + fn value_type() -> ValueType { + ValueType::Object + } } impl ToNapiValue for Vec diff --git a/crates/napi/src/bindgen_runtime/js_values/boolean.rs b/crates/napi/src/bindgen_runtime/js_values/boolean.rs index ad061eca..b7398c8b 100644 --- a/crates/napi/src/bindgen_runtime/js_values/boolean.rs +++ b/crates/napi/src/bindgen_runtime/js_values/boolean.rs @@ -4,6 +4,10 @@ impl TypeName for bool { fn type_name() -> &'static str { "bool" } + + fn value_type() -> ValueType { + ValueType::Boolean + } } impl ValidateNapiValue for bool { diff --git a/crates/napi/src/bindgen_runtime/js_values/buffer.rs b/crates/napi/src/bindgen_runtime/js_values/buffer.rs index 64024d8a..66fd324a 100644 --- a/crates/napi/src/bindgen_runtime/js_values/buffer.rs +++ b/crates/napi/src/bindgen_runtime/js_values/buffer.rs @@ -52,6 +52,10 @@ impl TypeName for Buffer { fn type_name() -> &'static str { "Vec" } + + fn value_type() -> ValueType { + ValueType::Object + } } impl FromNapiValue for Buffer { diff --git a/crates/napi/src/bindgen_runtime/js_values/either.rs b/crates/napi/src/bindgen_runtime/js_values/either.rs new file mode 100644 index 00000000..192aa142 --- /dev/null +++ b/crates/napi/src/bindgen_runtime/js_values/either.rs @@ -0,0 +1,359 @@ +use super::{FromNapiValue, ToNapiValue, TypeName}; +use crate::{type_of, Status, ValueType}; + +const ERROR_MSG: &str = "The return value of typeof(T) should not be equal in Either"; + +#[derive(Debug, Clone, Copy)] +pub enum Either< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, +> { + A(A), + B(B), +} + +impl TypeName + for Either +{ + fn type_name() -> &'static str { + "Either" + } + + fn value_type() -> ValueType { + ValueType::Unknown + } +} + +impl + FromNapiValue for Either +{ + unsafe fn from_napi_value( + env: napi_sys::napi_env, + napi_val: napi_sys::napi_value, + ) -> crate::Result { + debug_assert!(A::value_type() != B::value_type(), "{}", ERROR_MSG); + let js_type = type_of!(env, napi_val)?; + if js_type == A::value_type() { + A::from_napi_value(env, napi_val).map(Self::A) + } else if js_type == B::value_type() { + B::from_napi_value(env, napi_val).map(Self::B) + } else { + Err(crate::Error::new( + Status::InvalidArg, + format!( + "Expect type {} or {}, but got {}", + A::value_type(), + B::value_type(), + js_type + ), + )) + } + } +} + +impl + ToNapiValue for Either +{ + unsafe fn to_napi_value( + env: napi_sys::napi_env, + value: Self, + ) -> crate::Result { + match value { + Self::A(a) => A::to_napi_value(env, a), + Self::B(b) => B::to_napi_value(env, b), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Either3< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, +> { + A(A), + B(B), + C(C), +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + > TypeName for Either3 +{ + fn type_name() -> &'static str { + "Either3" + } + + fn value_type() -> ValueType { + ValueType::Unknown + } +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + > FromNapiValue for Either3 +{ + unsafe fn from_napi_value( + env: napi_sys::napi_env, + napi_val: napi_sys::napi_value, + ) -> crate::Result { + debug_assert!( + { + let mut types = vec![A::value_type(), B::value_type(), C::value_type()]; + types.dedup(); + types.len() == 3 + }, + "{}", + ERROR_MSG + ); + let js_type = type_of!(env, napi_val)?; + if js_type == A::value_type() { + A::from_napi_value(env, napi_val).map(Self::A) + } else if js_type == B::value_type() { + B::from_napi_value(env, napi_val).map(Self::B) + } else if js_type == C::value_type() { + C::from_napi_value(env, napi_val).map(Self::C) + } else { + Err(crate::Error::new( + Status::InvalidArg, + format!( + "Expect type {} or {} or {}, but got {}", + A::value_type(), + B::value_type(), + C::value_type(), + js_type + ), + )) + } + } +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + > ToNapiValue for Either3 +{ + unsafe fn to_napi_value( + env: napi_sys::napi_env, + value: Self, + ) -> crate::Result { + match value { + Self::A(a) => A::to_napi_value(env, a), + Self::B(b) => B::to_napi_value(env, b), + Self::C(c) => C::to_napi_value(env, c), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Either4< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, +> { + A(A), + B(B), + C(C), + D(D), +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, + > TypeName for Either4 +{ + fn type_name() -> &'static str { + "Either4" + } + + fn value_type() -> ValueType { + ValueType::Unknown + } +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, + > FromNapiValue for Either4 +{ + unsafe fn from_napi_value( + env: napi_sys::napi_env, + napi_val: napi_sys::napi_value, + ) -> crate::Result { + debug_assert!( + { + let mut types = vec![ + A::value_type(), + B::value_type(), + C::value_type(), + D::value_type(), + ]; + types.dedup(); + types.len() == 4 + }, + "{}", + ERROR_MSG + ); + let js_type = type_of!(env, napi_val)?; + if js_type == A::value_type() { + A::from_napi_value(env, napi_val).map(Self::A) + } else if js_type == B::value_type() { + B::from_napi_value(env, napi_val).map(Self::B) + } else if js_type == C::value_type() { + C::from_napi_value(env, napi_val).map(Self::C) + } else if js_type == D::value_type() { + D::from_napi_value(env, napi_val).map(Self::D) + } else { + Err(crate::Error::new( + Status::InvalidArg, + format!( + "Expect type {} or {} or {} or {}, but got {}", + A::value_type(), + B::value_type(), + C::value_type(), + D::value_type(), + js_type + ), + )) + } + } +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, + > ToNapiValue for Either4 +{ + unsafe fn to_napi_value( + env: napi_sys::napi_env, + value: Self, + ) -> crate::Result { + match value { + Self::A(a) => A::to_napi_value(env, a), + Self::B(b) => B::to_napi_value(env, b), + Self::C(c) => C::to_napi_value(env, c), + Self::D(d) => D::to_napi_value(env, d), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Either5< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, + E: TypeName + FromNapiValue + ToNapiValue, +> { + A(A), + B(B), + C(C), + D(D), + E(E), +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, + E: TypeName + FromNapiValue + ToNapiValue, + > TypeName for Either5 +{ + fn type_name() -> &'static str { + "Either5" + } + + fn value_type() -> ValueType { + ValueType::Unknown + } +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, + E: TypeName + FromNapiValue + ToNapiValue, + > FromNapiValue for Either5 +{ + unsafe fn from_napi_value( + env: napi_sys::napi_env, + napi_val: napi_sys::napi_value, + ) -> crate::Result { + debug_assert!( + { + let mut types = vec![ + A::value_type(), + B::value_type(), + C::value_type(), + D::value_type(), + E::value_type(), + ]; + types.dedup(); + types.len() == 5 + }, + "{}", + ERROR_MSG + ); + let js_type = type_of!(env, napi_val)?; + if js_type == A::value_type() { + A::from_napi_value(env, napi_val).map(Self::A) + } else if js_type == B::value_type() { + B::from_napi_value(env, napi_val).map(Self::B) + } else if js_type == C::value_type() { + C::from_napi_value(env, napi_val).map(Self::C) + } else if js_type == D::value_type() { + D::from_napi_value(env, napi_val).map(Self::D) + } else if js_type == E::value_type() { + E::from_napi_value(env, napi_val).map(Self::E) + } else { + Err(crate::Error::new( + Status::InvalidArg, + format!( + "Expect type {} or {} or {} or {} or {}, but got {}", + A::value_type(), + B::value_type(), + C::value_type(), + D::value_type(), + E::value_type(), + js_type + ), + )) + } + } +} + +impl< + A: TypeName + FromNapiValue + ToNapiValue, + B: TypeName + FromNapiValue + ToNapiValue, + C: TypeName + FromNapiValue + ToNapiValue, + D: TypeName + FromNapiValue + ToNapiValue, + E: TypeName + FromNapiValue + ToNapiValue, + > ToNapiValue for Either5 +{ + unsafe fn to_napi_value( + env: napi_sys::napi_env, + value: Self, + ) -> crate::Result { + match value { + Self::A(a) => A::to_napi_value(env, a), + Self::B(b) => B::to_napi_value(env, b), + Self::C(c) => C::to_napi_value(env, c), + Self::D(d) => D::to_napi_value(env, d), + Self::E(e) => E::to_napi_value(env, e), + } + } +} diff --git a/crates/napi/src/bindgen_runtime/js_values/map.rs b/crates/napi/src/bindgen_runtime/js_values/map.rs index ddbd33e0..f91e7c51 100644 --- a/crates/napi/src/bindgen_runtime/js_values/map.rs +++ b/crates/napi/src/bindgen_runtime/js_values/map.rs @@ -7,6 +7,10 @@ impl TypeName for HashMap { fn type_name() -> &'static str { "HashMap" } + + fn value_type() -> ValueType { + ValueType::Object + } } impl ToNapiValue for HashMap diff --git a/crates/napi/src/bindgen_runtime/js_values/nil.rs b/crates/napi/src/bindgen_runtime/js_values/nil.rs index 50177192..11971b93 100644 --- a/crates/napi/src/bindgen_runtime/js_values/nil.rs +++ b/crates/napi/src/bindgen_runtime/js_values/nil.rs @@ -9,6 +9,10 @@ impl TypeName for Null { fn type_name() -> &'static str { "null" } + + fn value_type() -> ValueType { + ValueType::Null + } } impl ValidateNapiValue for Null { @@ -46,6 +50,10 @@ impl TypeName for Undefined { fn type_name() -> &'static str { "undefined" } + + fn value_type() -> ValueType { + ValueType::Undefined + } } impl ValidateNapiValue for Undefined { diff --git a/crates/napi/src/bindgen_runtime/js_values/number.rs b/crates/napi/src/bindgen_runtime/js_values/number.rs index 1c49a938..457b0ad4 100644 --- a/crates/napi/src/bindgen_runtime/js_values/number.rs +++ b/crates/napi/src/bindgen_runtime/js_values/number.rs @@ -8,6 +8,10 @@ macro_rules! impl_number_conversions { fn type_name() -> &'static str { $name } + + fn value_type() -> crate::ValueType { + crate::ValueType::Number + } } impl $crate::bindgen_prelude::ValidateNapiValue for $t { diff --git a/crates/napi/src/bindgen_runtime/js_values/object.rs b/crates/napi/src/bindgen_runtime/js_values/object.rs index 2d08c3af..4729b274 100644 --- a/crates/napi/src/bindgen_runtime/js_values/object.rs +++ b/crates/napi/src/bindgen_runtime/js_values/object.rs @@ -81,6 +81,10 @@ impl TypeName for Object { fn type_name() -> &'static str { "Object" } + + fn value_type() -> ValueType { + ValueType::Object + } } impl ToNapiValue for Object { diff --git a/crates/napi/src/bindgen_runtime/js_values/string.rs b/crates/napi/src/bindgen_runtime/js_values/string.rs index bad667bd..cc07a9db 100644 --- a/crates/napi/src/bindgen_runtime/js_values/string.rs +++ b/crates/napi/src/bindgen_runtime/js_values/string.rs @@ -11,6 +11,10 @@ impl TypeName for String { fn type_name() -> &'static str { "String" } + + fn value_type() -> ValueType { + ValueType::String + } } impl ToNapiValue for String { @@ -61,6 +65,10 @@ impl TypeName for &str { fn type_name() -> &'static str { "String" } + + fn value_type() -> ValueType { + ValueType::String + } } impl ToNapiValue for &str { @@ -96,6 +104,10 @@ impl TypeName for Utf16String { fn type_name() -> &'static str { "String(utf16)" } + + fn value_type() -> ValueType { + ValueType::String + } } impl FromNapiValue for Utf16String { @@ -181,6 +193,10 @@ pub mod latin1_string { fn type_name() -> &'static str { "String(latin1)" } + + fn value_type() -> ValueType { + ValueType::String + } } #[cfg(feature = "latin1")] diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index 4f4a206f..75aac183 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -14,6 +14,13 @@ Generated by [AVA](https://avajs.dev). export function readFileAsync(path: string): Promise␊ export function getCwd(callback: (arg0: string) => void): void␊ export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void␊ + export function eitherStringOrNumber(input: string | number): number␊ + export function returnEither(input: number): string | number␊ + export function either3(input: string | number | boolean): number␊ + interface Obj {␊ + v: string | number␊ + }␊ + export function either4(input: string | number | boolean | Obj): number␊ export enum Kind { Dog = 0, Cat = 1, Duck = 2 }␊ export enum CustomNumEnum { One = 1, Two = 2, Three = 3, Four = 4, Six = 6, Eight = 8, Nine = 9, Ten = 10 }␊ export function enumToI32(e: CustomNumEnum): number␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index d423c0652f5f2dd9568b6a563447a98af1e0cc69..bf6d133e5135c035b4c12a255d7c750a5a271770 100644 GIT binary patch literal 763 zcmVzcKO*h?S6VeC984(2j;N6Ff=U zTwF)Mxan?A9KhZ_477~NlmA<&U3JhfMjQA9nToL^6~-aZL9OsiCn`&lr2;5j56wl+ zX_;o80VY*Hb5oxD_Wv^EGNT%~tAae?%y?N4L4AQJ8Evf-=**C{9m0jYA!8?mhV1sd!mALPGUvV~3M%hp6Xx8JWG?k- zeT!iU)a~coIEiEHAN{b%o61nDGJ>LOWVoPaWCTiVGo` zS`JR6b@X0mII>K)uOgri3b%A<2evcP|)bQ*QU-?qx~X19y&OFEV}x{ek7El^U;@<^9E4qxJlQb5jI&* zaVO1M&6QS;OJ$j*5*3p~gy3lApexP8`yQI-L2yTNhNYRiC=nJb68^pG)OMJCEc`8Z zQq>-Vr=Z6Z+ox}A6&R6lYvDl2lqdPq`-E$ijNqD@Kgve{?UEw-&V-}3c{m8C3T1}j6LX{@7L3Gaudj@R&~c@TH&{{Z)`ey3sw000l;a>D=s literal 700 zcmV;t0z>^lRzVfJl>Zn?%JsmY{cE54YN$h=fvntTHJn}C&_J$lv;NZGr`j| z;$qka#!Y{H9sqVaFxE1rNd9jrcRj$KG1|Z<$W@GqR2YXqhE^GwEGkdaWdumI!l6_# zTtZLxVF%Vj=yFFwD}-Jyh9qsk)dIeoTc>>k_q=uq#|mfovx)X_5(WnS*=7j)IyWRe z3*l5=kgyfPp6m}i!^;qkWa0aYTu}KS>(^ZK;yvk^KG@t~*j^-Gepzl{^rYwwTh`Nz zkB&!PVq>0`fy#c}&}+^-ju|gOAw;FPJflQLT5%yHQ+IX}bNDu*WF0^x)PhxhS~CFErTK=BOAK_PXF#!`^VNsJ?;xl%$R?a4b7 zw1@w>Y0T8LQ?|!L$G!Wa>sRdOyON#HzM|f?O%?MIl|lPB*B5-7^Kxpv(#mnEEVDGC zV%~@l94!#K%5q0qr^xGRPz1rSd}DYq7OmCSfrT)l6&R_PRmwEXSj37}JAq}aJ|v^Lj { @@ -130,3 +134,29 @@ test('async', async (t) => { await t.throwsAsync(() => readFileAsync('some_nonexist_path.file')) }) + +test('either', (t) => { + t.is(eitherStringOrNumber(2), 2) + t.is(eitherStringOrNumber('hello'), 'hello'.length) +}) + +test('return either', (t) => { + t.is(returnEither(2), 2) + t.is(returnEither(42), '42') +}) + +test('either3', (t) => { + t.is(either3(2), 2) + t.is(either3('hello'), 'hello'.length) + t.is(either3(true), 1) + t.is(either3(false), 0) +}) + +test('either4', (t) => { + t.is(either4(2), 2) + t.is(either4('hello'), 'hello'.length) + t.is(either4(true), 1) + t.is(either4(false), 0) + t.is(either4({ v: 1 }), 1) + t.is(either4({ v: 'world' }), 'world'.length) +}) diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index d251a91d..54b6e118 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -4,6 +4,13 @@ export function sumNums(nums: Array): number export function readFileAsync(path: string): Promise export function getCwd(callback: (arg0: string) => void): void export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void +export function eitherStringOrNumber(input: string | number): number +export function returnEither(input: number): string | number +export function either3(input: string | number | boolean): number +interface Obj { + v: string | number +} +export function either4(input: string | number | boolean | Obj): number export enum Kind { Dog = 0, Cat = 1, Duck = 2 } export enum CustomNumEnum { One = 1, Two = 2, Three = 3, Four = 4, Six = 6, Eight = 8, Nine = 9, Ten = 10 } export function enumToI32(e: CustomNumEnum): number diff --git a/examples/napi/src/either.rs b/examples/napi/src/either.rs new file mode 100644 index 00000000..12ddccdc --- /dev/null +++ b/examples/napi/src/either.rs @@ -0,0 +1,57 @@ +use napi::bindgen_prelude::*; + +#[napi] +fn either_string_or_number(input: Either) -> u32 { + match input { + Either::A(s) => s.len() as u32, + Either::B(n) => n, + } +} + +#[napi] +fn return_either(input: u32) -> Either { + if input > 10 { + Either::A(format!("{}", input)) + } else { + Either::B(input) + } +} + +#[napi] +fn either3(input: Either3) -> u32 { + match input { + Either3::A(s) => s.len() as u32, + Either3::B(n) => n, + Either3::C(b) => { + if b { + 1 + } else { + 0 + } + } + } +} + +#[napi(object)] +struct Obj { + pub v: Either, +} + +#[napi] +fn either4(input: Either4) -> u32 { + match input { + Either4::A(s) => s.len() as u32, + Either4::B(n) => n, + Either4::C(b) => { + if b { + 1 + } else { + 0 + } + } + Either4::D(f) => match f.v { + Either::A(s) => s.len() as u32, + Either::B(n) => n, + }, + } +} diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs index 057d6756..b739a35f 100644 --- a/examples/napi/src/lib.rs +++ b/examples/napi/src/lib.rs @@ -7,6 +7,7 @@ mod array; mod r#async; mod callback; mod class; +mod either; mod r#enum; mod error; mod nullable;