feat(napi): improve symbol support

This commit is contained in:
LongYinan 2021-11-15 23:09:44 +08:00
parent c0a89834c2
commit 424c7805c4
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
10 changed files with 101 additions and 29 deletions

View file

@ -30,7 +30,9 @@ pub trait ToTypeDef {
static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| { static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
let mut map = HashMap::default(); let mut map = HashMap::default();
map.extend([ map.extend([
("JsUndefined", "undefined"),
("()", "undefined"), ("()", "undefined"),
("JsNumber", "number"),
("i8", "number"), ("i8", "number"),
("i16", "number"), ("i16", "number"),
("i32", "number"), ("i32", "number"),
@ -47,12 +49,15 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("isize", "BigInt"), ("isize", "BigInt"),
("JsBigInt", "BigInt"), ("JsBigInt", "BigInt"),
("BigInt", "BigInt"), ("BigInt", "BigInt"),
("JsBoolean", "boolean"),
("bool", "boolean"), ("bool", "boolean"),
("JsString", "string"),
("String", "string"), ("String", "string"),
("str", "string"), ("str", "string"),
("Latin1String", "string"), ("Latin1String", "string"),
("Utf16String", "string"), ("Utf16String", "string"),
("char", "string"), ("char", "string"),
("JsObject", "object"),
("Object", "object"), ("Object", "object"),
("Value", "any"), ("Value", "any"),
("Map", "Record<string, any>"), ("Map", "Record<string, any>"),
@ -71,7 +76,8 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("Either5", "{} | {} | {} | {} | {}"), ("Either5", "{} | {} | {} | {} | {}"),
("unknown", "unknown"), ("unknown", "unknown"),
("null", "null"), ("null", "null"),
("symbol", "symbol"), ("Symbol", "symbol"),
("JsSymbol", "symbol"),
("external", "object"), ("external", "object"),
("AbortSignal", "AbortSignal"), ("AbortSignal", "AbortSignal"),
("JsFunction", "(...args: any[]) => any"), ("JsFunction", "(...args: any[]) => any"),

View file

@ -17,6 +17,7 @@ mod promise;
#[cfg(feature = "serde-json")] #[cfg(feature = "serde-json")]
mod serde; mod serde;
mod string; mod string;
mod symbol;
mod task; mod task;
pub use array::*; pub use array::*;
@ -30,6 +31,7 @@ pub use nil::*;
pub use object::*; pub use object::*;
pub use promise::*; pub use promise::*;
pub use string::*; pub use string::*;
pub use symbol::*;
pub use task::*; pub use task::*;
#[cfg(feature = "latin1")] #[cfg(feature = "latin1")]

View file

@ -0,0 +1,48 @@
use std::{ffi::CString, ptr};
use crate::check_status;
use super::ToNapiValue;
pub struct Symbol {
desc: Option<String>,
}
impl Symbol {
pub fn new(desc: String) -> Self {
Self { desc: Some(desc) }
}
pub fn identity() -> Self {
Self { desc: None }
}
}
impl ToNapiValue for Symbol {
unsafe fn to_napi_value(
env: napi_sys::napi_env,
val: Self,
) -> crate::Result<napi_sys::napi_value> {
let mut symbol_value = ptr::null_mut();
check_status!(napi_sys::napi_create_symbol(
env,
match val.desc {
Some(desc) => {
let mut desc_string = ptr::null_mut();
let desc_len = desc.len();
let desc_c_string = CString::new(desc)?;
check_status!(napi_sys::napi_create_string_utf8(
env,
desc_c_string.as_ptr(),
desc_len,
&mut desc_string
))?;
desc_string
}
None => ptr::null_mut(),
},
&mut symbol_value
))?;
Ok(symbol_value)
}
}

View file

@ -260,12 +260,13 @@ macro_rules! impl_js_value_methods {
macro_rules! impl_object_methods { macro_rules! impl_object_methods {
($js_value:ident) => { ($js_value:ident) => {
impl $js_value { impl $js_value {
pub fn set_property<V>(&mut self, key: JsString, value: V) -> Result<()> pub fn set_property<K, V>(&mut self, key: K, value: V) -> Result<()>
where where
K: NapiRaw,
V: NapiRaw, V: NapiRaw,
{ {
check_status!(unsafe { check_status!(unsafe {
sys::napi_set_property(self.0.env, self.0.value, key.0.value, value.raw()) sys::napi_set_property(self.0.env, self.0.value, key.raw(), value.raw())
}) })
} }

View file

@ -35,7 +35,7 @@ Generated by [AVA](https://avajs.dev).
export function listObjKeys(obj: object): Array<string> export function listObjKeys(obj: object): Array<string>
export function createObj(): object␊ export function createObj(): object␊
export function getGlobal(): typeof global␊ export function getGlobal(): typeof global␊
export function getUndefined(): JsUndefined␊ export function getUndefined(): void␊
export function getNull(): JsNull␊ export function getNull(): JsNull␊
export function asyncPlus100(p: Promise<number>): Promise<number> export function asyncPlus100(p: Promise<number>): Promise<number>
interface PackageJson {␊ interface PackageJson {␊
@ -50,6 +50,8 @@ Generated by [AVA](https://avajs.dev).
export function concatStr(s: string): string␊ export function concatStr(s: string): string␊
export function concatUtf16(s: string): string␊ export function concatUtf16(s: string): string␊
export function concatLatin1(s: string): string␊ export function concatLatin1(s: string): string␊
export function setSymbolInObj(symbol: symbol): object␊
export function createSymbol(): symbol␊
export function withoutAbortController(a: number, b: number): Promise<number> export function withoutAbortController(a: number, b: number): Promise<number>
export function withAbortController(a: number, b: number, signal: AbortSignal): Promise<number> export function withAbortController(a: number, b: number, signal: AbortSignal): Promise<number>
export function callThreadsafeFunction(callback: (...args: any[]) => any): void␊ export function callThreadsafeFunction(callback: (...args: any[]) => any): void␊

View file

@ -44,6 +44,8 @@ import {
getGlobal, getGlobal,
getUndefined, getUndefined,
getNull, getNull,
setSymbolInObj,
createSymbol,
} from '../' } from '../'
test('number', (t) => { test('number', (t) => {
@ -156,6 +158,16 @@ test('get null', (t) => {
} }
}) })
test('pass symbol in', (t) => {
const sym = Symbol('test')
const obj = setSymbolInObj(sym)
t.is(obj[sym], 'a symbol')
})
test('create symbol', (t) => {
t.is(createSymbol().toString(), 'Symbol(a symbol)')
})
test('Option', (t) => { test('Option', (t) => {
t.is(mapOption(null), null) t.is(mapOption(null), null)
t.is(mapOption(3), 4) t.is(mapOption(3), 4)

View file

@ -7,9 +7,7 @@ export function bigintAdd(a: BigInt, b: BigInt): BigInt
export function createBigInt(): BigInt export function createBigInt(): BigInt
export function createBigIntI64(): BigInt export function createBigIntI64(): BigInt
export function getCwd(callback: (arg0: string) => void): void export function getCwd(callback: (arg0: string) => void): void
export function readFile( export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void
callback: (arg0: Error | undefined, arg1: string | null) => void,
): void
export function eitherStringOrNumber(input: string | number): number export function eitherStringOrNumber(input: string | number): number
export function returnEither(input: number): string | number export function returnEither(input: number): string | number
export function either3(input: string | number | boolean): number export function either3(input: string | number | boolean): number
@ -17,21 +15,8 @@ interface Obj {
v: string | number v: string | number
} }
export function either4(input: string | number | boolean | Obj): number export function either4(input: string | number | boolean | Obj): number
export enum Kind { export enum Kind { Dog = 0, Cat = 1, Duck = 2 }
Dog = 0, export enum CustomNumEnum { One = 1, Two = 2, Three = 3, Four = 4, Six = 6, Eight = 8, Nine = 9, Ten = 10 }
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 export function enumToI32(e: CustomNumEnum): number
export function throwError(): void export function throwError(): void
export function mapOption(val: number | null): number | null export function mapOption(val: number | null): number | null
@ -40,7 +25,7 @@ export function fibonacci(n: number): number
export function listObjKeys(obj: object): Array<string> export function listObjKeys(obj: object): Array<string>
export function createObj(): object export function createObj(): object
export function getGlobal(): typeof global export function getGlobal(): typeof global
export function getUndefined(): JsUndefined export function getUndefined(): void
export function getNull(): JsNull export function getNull(): JsNull
export function asyncPlus100(p: Promise<number>): Promise<number> export function asyncPlus100(p: Promise<number>): Promise<number>
interface PackageJson { interface PackageJson {
@ -55,12 +40,10 @@ export function contains(source: string, target: string): boolean
export function concatStr(s: string): string export function concatStr(s: string): string
export function concatUtf16(s: string): string export function concatUtf16(s: string): string
export function concatLatin1(s: string): string export function concatLatin1(s: string): string
export function setSymbolInObj(symbol: symbol): object
export function createSymbol(): symbol
export function withoutAbortController(a: number, b: number): Promise<number> export function withoutAbortController(a: number, b: number): Promise<number>
export function withAbortController( export function withAbortController(a: number, b: number, signal: AbortSignal): Promise<number>
a: number,
b: number,
signal: AbortSignal,
): Promise<number>
export function callThreadsafeFunction(callback: (...args: any[]) => any): void export function callThreadsafeFunction(callback: (...args: any[]) => any): void
export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void
export function getBuffer(): Buffer export function getBuffer(): Buffer
@ -74,10 +57,14 @@ export class Animal {
static getDogKind(): Kind static getDogKind(): Kind
} }
export class Blake2BHasher { export class Blake2BHasher {
static withKey(key: Blake2bKey): Blake2BHasher static withKey(key: Blake2bKey): Blake2BHasher
} }
export class Blake2BKey {} export class Blake2BKey {
}
export class Context { export class Context {
constructor() constructor()
static withData(data: string): Context static withData(data: string): Context
method(): string method(): string

View file

@ -18,6 +18,7 @@ mod object;
mod promise; mod promise;
mod serde; mod serde;
mod string; mod string;
mod symbol;
mod task; mod task;
mod threadsafe_function; mod threadsafe_function;
mod typed_array; mod typed_array;

View file

@ -0,0 +1,13 @@
use napi::{bindgen_prelude::*, Env, JsObject, JsSymbol};
#[napi]
pub fn set_symbol_in_obj(env: Env, symbol: JsSymbol) -> Result<JsObject> {
let mut obj = env.create_object()?;
obj.set_property(symbol, env.create_string("a symbol")?)?;
Ok(obj)
}
#[napi]
pub fn create_symbol() -> Symbol {
Symbol::new("a symbol".to_owned())
}