fix(napi): type constraint for either types
This commit is contained in:
parent
fb8d8b97d6
commit
a5c19ce1da
6 changed files with 73 additions and 93 deletions
|
@ -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,
|
||||||
|
|
|
@ -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 */␊
|
||||||
|
|
Binary file not shown.
|
@ -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)
|
||||||
|
|
2
examples/napi/index.d.ts
vendored
2
examples/napi/index.d.ts
vendored
|
@ -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 */
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue