fix(napi): type constraint for either types

This commit is contained in:
LongYinan 2022-05-12 15:11:47 +08:00
parent fb8d8b97d6
commit a5c19ce1da
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
6 changed files with 73 additions and 93 deletions

View file

@ -1,22 +1,18 @@
use super::{FromNapiValue, ToNapiValue, TypeName}; use super::{FromNapiValue, ToNapiValue, TypeName};
use crate::{sys, type_of, JsNull, JsUndefined, NapiRaw, Status, ValueType}; use crate::{
bindgen_runtime::{Null, Undefined},
sys, type_of, JsUndefined, NapiRaw, Status, ValueType,
};
const ERROR_MSG: &str = "The return value of typeof(T) should not be equal in Either"; const ERROR_MSG: &str = "The return value of typeof(T) should not be equal in Either";
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Either< pub enum Either<A, B> {
A: TypeName + FromNapiValue + ToNapiValue,
B: TypeName + FromNapiValue + ToNapiValue,
> {
A(A), A(A),
B(B), B(B),
} }
impl< impl<A: NapiRaw, B: NapiRaw> Either<A, B> {
A: TypeName + FromNapiValue + ToNapiValue + NapiRaw,
B: TypeName + FromNapiValue + ToNapiValue + NapiRaw,
> Either<A, B>
{
/// # Safety /// # Safety
/// Backward compatible with `Either` in **v1** /// Backward compatible with `Either` in **v1**
pub unsafe fn raw(&self) -> sys::napi_value { pub unsafe fn raw(&self) -> sys::napi_value {
@ -27,9 +23,7 @@ impl<
} }
} }
impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue> TypeName impl<A: TypeName, B: TypeName> TypeName for Either<A, B> {
for Either<A, B>
{
fn type_name() -> &'static str { fn type_name() -> &'static str {
"Either" "Either"
} }
@ -40,7 +34,7 @@ impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + To
} }
// Backwards compatibility with v1 // Backwards compatibility with v1
impl<T: TypeName + FromNapiValue + ToNapiValue> From<Either<T, JsUndefined>> for Option<T> { impl<T> From<Either<T, JsUndefined>> for Option<T> {
fn from(value: Either<T, JsUndefined>) -> Option<T> { fn from(value: Either<T, JsUndefined>) -> Option<T> {
match value { match value {
Either::A(v) => Some(v), Either::A(v) => Some(v),
@ -49,8 +43,17 @@ impl<T: TypeName + FromNapiValue + ToNapiValue> From<Either<T, JsUndefined>> for
} }
} }
impl<T: TypeName + FromNapiValue + ToNapiValue> From<Either<T, JsNull>> for Option<T> { impl<T> From<Option<T>> for Either<T, Undefined> {
fn from(value: Either<T, JsNull>) -> Option<T> { fn from(value: Option<T>) -> Self {
match value {
Some(v) => Either::A(v),
None => Either::B(()),
}
}
}
impl<T> From<Either<T, Null>> for Option<T> {
fn from(value: Either<T, Null>) -> Option<T> {
match value { match value {
Either::A(v) => Some(v), Either::A(v) => Some(v),
Either::B(_) => None, Either::B(_) => None,
@ -58,9 +61,7 @@ impl<T: TypeName + FromNapiValue + ToNapiValue> From<Either<T, JsNull>> for Opti
} }
} }
impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue> impl<A: TypeName + FromNapiValue, B: TypeName + FromNapiValue> FromNapiValue for Either<A, B> {
FromNapiValue for Either<A, B>
{
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
debug_assert!(A::value_type() != B::value_type(), "{}", ERROR_MSG); debug_assert!(A::value_type() != B::value_type(), "{}", ERROR_MSG);
let js_type = type_of!(env, napi_val)?; let js_type = type_of!(env, napi_val)?;
@ -82,9 +83,7 @@ impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + To
} }
} }
impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue> impl<A: ToNapiValue, B: ToNapiValue> ToNapiValue for Either<A, B> {
ToNapiValue for Either<A, B>
{
unsafe fn to_napi_value( unsafe fn to_napi_value(
env: sys::napi_env, env: sys::napi_env,
value: Self, value: Self,
@ -97,22 +96,13 @@ impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + To
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Either3< pub enum Either3<A, B, C> {
A: TypeName + FromNapiValue + ToNapiValue,
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
> {
A(A), A(A),
B(B), B(B),
C(C), C(C),
} }
impl< impl<A: TypeName, B: TypeName, C: TypeName> TypeName for Either3<A, B, C> {
A: TypeName + FromNapiValue + ToNapiValue,
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
> TypeName for Either3<A, B, C>
{
fn type_name() -> &'static str { fn type_name() -> &'static str {
"Either3" "Either3"
} }
@ -122,11 +112,8 @@ impl<
} }
} }
impl< impl<A: TypeName + FromNapiValue, B: TypeName + FromNapiValue, C: TypeName + FromNapiValue>
A: TypeName + FromNapiValue + ToNapiValue, FromNapiValue for Either3<A, B, C>
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
> FromNapiValue for Either3<A, B, C>
{ {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
debug_assert!( debug_assert!(
@ -160,12 +147,7 @@ impl<
} }
} }
impl< impl<A: ToNapiValue, B: ToNapiValue, C: ToNapiValue> ToNapiValue for Either3<A, B, C> {
A: TypeName + FromNapiValue + ToNapiValue,
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
> ToNapiValue for Either3<A, B, C>
{
unsafe fn to_napi_value( unsafe fn to_napi_value(
env: sys::napi_env, env: sys::napi_env,
value: Self, value: Self,
@ -179,25 +161,14 @@ impl<
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Either4< pub enum Either4<A, B, C, D> {
A: TypeName + FromNapiValue + ToNapiValue,
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
D: TypeName + FromNapiValue + ToNapiValue,
> {
A(A), A(A),
B(B), B(B),
C(C), C(C),
D(D), D(D),
} }
impl< impl<A: TypeName, B: TypeName, C: TypeName, D: TypeName> TypeName for Either4<A, B, C, D> {
A: TypeName + FromNapiValue + ToNapiValue,
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
D: TypeName + FromNapiValue + ToNapiValue,
> TypeName for Either4<A, B, C, D>
{
fn type_name() -> &'static str { fn type_name() -> &'static str {
"Either4" "Either4"
} }
@ -208,10 +179,10 @@ impl<
} }
impl< impl<
A: TypeName + FromNapiValue + ToNapiValue, A: TypeName + FromNapiValue,
B: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue,
C: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue,
D: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue,
> FromNapiValue for Either4<A, B, C, D> > FromNapiValue for Either4<A, B, C, D>
{ {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
@ -254,12 +225,8 @@ impl<
} }
} }
impl< impl<A: ToNapiValue, B: ToNapiValue, C: ToNapiValue, D: ToNapiValue> ToNapiValue
A: TypeName + FromNapiValue + ToNapiValue, for Either4<A, B, C, D>
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
D: TypeName + FromNapiValue + ToNapiValue,
> ToNapiValue for Either4<A, B, C, D>
{ {
unsafe fn to_napi_value( unsafe fn to_napi_value(
env: sys::napi_env, env: sys::napi_env,
@ -275,13 +242,7 @@ impl<
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Either5< pub enum Either5<A, B, C, D, E> {
A: TypeName + FromNapiValue + ToNapiValue,
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
D: TypeName + FromNapiValue + ToNapiValue,
E: TypeName + FromNapiValue + ToNapiValue,
> {
A(A), A(A),
B(B), B(B),
C(C), C(C),
@ -289,13 +250,8 @@ pub enum Either5<
E(E), E(E),
} }
impl< impl<A: TypeName, B: TypeName, C: TypeName, D: TypeName, E: TypeName> TypeName
A: TypeName + FromNapiValue + ToNapiValue, for Either5<A, B, C, D, E>
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
D: TypeName + FromNapiValue + ToNapiValue,
E: TypeName + FromNapiValue + ToNapiValue,
> TypeName for Either5<A, B, C, D, E>
{ {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"Either5" "Either5"
@ -307,11 +263,11 @@ impl<
} }
impl< impl<
A: TypeName + FromNapiValue + ToNapiValue, A: TypeName + FromNapiValue,
B: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue,
C: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue,
D: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue,
E: TypeName + FromNapiValue + ToNapiValue, E: TypeName + FromNapiValue,
> FromNapiValue for Either5<A, B, C, D, E> > FromNapiValue for Either5<A, B, C, D, E>
{ {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
@ -358,13 +314,8 @@ impl<
} }
} }
impl< impl<A: ToNapiValue, B: ToNapiValue, C: ToNapiValue, D: ToNapiValue, E: ToNapiValue> ToNapiValue
A: TypeName + FromNapiValue + ToNapiValue, for Either5<A, B, C, D, E>
B: TypeName + FromNapiValue + ToNapiValue,
C: TypeName + FromNapiValue + ToNapiValue,
D: TypeName + FromNapiValue + ToNapiValue,
E: TypeName + FromNapiValue + ToNapiValue,
> ToNapiValue for Either5<A, B, C, D, E>
{ {
unsafe fn to_napi_value( unsafe fn to_napi_value(
env: sys::napi_env, env: sys::napi_env,

View file

@ -57,6 +57,8 @@ Generated by [AVA](https://avajs.dev).
export function either4(input: string | number | boolean | Obj): number␊ export function either4(input: string | number | boolean | Obj): number␊
export function receiveClassOrNumber(either: number | JsClassForEither): number␊ export function receiveClassOrNumber(either: number | JsClassForEither): number␊
export function receiveMutClassOrNumber(either: number | JsClassForEither): number␊ export function receiveMutClassOrNumber(either: number | JsClassForEither): number␊
export function returnEitherClass(input: number): number | JsClassForEither␊
export function eitherFromOption(): JsClassForEither | undefined␊
/** default enum values are continuos i32s start from 0 */␊ /** default enum values are continuos i32s start from 0 */␊
export const enum Kind {␊ export const enum Kind {␊
/** Barks */␊ /** Barks */␊

View file

@ -93,6 +93,8 @@ import {
CssStyleSheet, CssStyleSheet,
asyncReduceBuffer, asyncReduceBuffer,
callbackReturnPromise, callbackReturnPromise,
returnEitherClass,
eitherFromOption,
} from '../' } from '../'
test('export const', (t) => { test('export const', (t) => {
@ -467,6 +469,15 @@ test('receive class reference in either', (t) => {
t.is(receiveMutClassOrNumber(c), 100) t.is(receiveMutClassOrNumber(c), 100)
}) })
test('return either class', (t) => {
t.is(returnEitherClass(1), 1)
t.true(returnEitherClass(-1) instanceof JsClassForEither)
})
test('either from option', (t) => {
t.true(eitherFromOption() instanceof JsClassForEither)
})
test('either3', (t) => { test('either3', (t) => {
t.is(either3(2), 2) t.is(either3(2), 2)
t.is(either3('hello'), 'hello'.length) t.is(either3('hello'), 'hello'.length)

View file

@ -47,6 +47,8 @@ export interface Obj {
export function either4(input: string | number | boolean | Obj): number export function either4(input: string | number | boolean | Obj): number
export function receiveClassOrNumber(either: number | JsClassForEither): number export function receiveClassOrNumber(either: number | JsClassForEither): number
export function receiveMutClassOrNumber(either: number | JsClassForEither): number export function receiveMutClassOrNumber(either: number | JsClassForEither): number
export function returnEitherClass(input: number): number | JsClassForEither
export function eitherFromOption(): JsClassForEither | undefined
/** default enum values are continuos i32s start from 0 */ /** default enum values are continuos i32s start from 0 */
export const enum Kind { export const enum Kind {
/** Barks */ /** Barks */

View file

@ -82,3 +82,17 @@ fn receive_mut_class_or_number(either: Either<u32, &mut JsClassForEither>) -> u3
Either::B(_) => 100, Either::B(_) => 100,
} }
} }
#[napi]
fn return_either_class(input: i32) -> Either<u32, JsClassForEither> {
if input > 0 {
Either::A(input as u32)
} else {
Either::B(JsClassForEither {})
}
}
#[napi]
fn either_from_option() -> Either<JsClassForEither, Undefined> {
Some(JsClassForEither {}).into()
}