feat(napi): extends the Map types interoperability (#1950)
This commit is contained in:
parent
642cecc759
commit
d7dc4dc5a2
8 changed files with 175 additions and 2 deletions
|
@ -28,6 +28,7 @@ deferred_trace = ["napi4"]
|
|||
error_anyhow = ["anyhow"]
|
||||
experimental = ["napi-sys/experimental"]
|
||||
full = ["latin1", "napi9", "async", "serde-json", "experimental", "chrono_date"]
|
||||
object_indexmap = ["indexmap"]
|
||||
latin1 = ["encoding_rs"]
|
||||
napi1 = []
|
||||
napi2 = ["napi1", "napi-sys/napi2"]
|
||||
|
@ -40,6 +41,7 @@ napi8 = ["napi7", "napi-sys/napi8"]
|
|||
napi9 = ["napi8", "napi-sys/napi9"]
|
||||
noop = []
|
||||
serde-json = ["serde", "serde_json"]
|
||||
serde-json-ordered = ["serde-json", "serde_json/preserve_order"]
|
||||
tokio_fs = ["tokio/fs"]
|
||||
tokio_full = ["tokio/full"]
|
||||
tokio_io_std = ["tokio/io-std"]
|
||||
|
@ -93,3 +95,7 @@ version = "1"
|
|||
[dependencies.serde_json]
|
||||
optional = true
|
||||
version = "1"
|
||||
|
||||
[dependencies.indexmap]
|
||||
optional = true
|
||||
version = "2"
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
|
||||
#[cfg(feature = "object_indexmap")]
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::bindgen_prelude::{Env, Result, ToNapiValue, *};
|
||||
|
||||
impl<K, V, S> TypeName for HashMap<K, V, S> {
|
||||
|
@ -49,3 +52,101 @@ where
|
|||
Ok(map)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> TypeName for BTreeMap<K, V> {
|
||||
fn type_name() -> &'static str {
|
||||
"BTreeMap"
|
||||
}
|
||||
|
||||
fn value_type() -> ValueType {
|
||||
ValueType::Object
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: From<String> + Ord, V: FromNapiValue> ValidateNapiValue for BTreeMap<K, V> {}
|
||||
|
||||
impl<K, V> ToNapiValue for BTreeMap<K, V>
|
||||
where
|
||||
K: AsRef<str>,
|
||||
V: ToNapiValue,
|
||||
{
|
||||
unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||
let env = Env::from(raw_env);
|
||||
let mut obj = env.create_object()?;
|
||||
for (k, v) in val.into_iter() {
|
||||
obj.set(k.as_ref(), v)?;
|
||||
}
|
||||
|
||||
unsafe { Object::to_napi_value(raw_env, obj) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> FromNapiValue for BTreeMap<K, V>
|
||||
where
|
||||
K: From<String> + Ord,
|
||||
V: FromNapiValue,
|
||||
{
|
||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||
let obj = unsafe { Object::from_napi_value(env, napi_val)? };
|
||||
let mut map = BTreeMap::default();
|
||||
for key in Object::keys(&obj)?.into_iter() {
|
||||
if let Some(val) = obj.get(&key)? {
|
||||
map.insert(K::from(key), val);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "object_indexmap")]
|
||||
impl<K, V, S> TypeName for IndexMap<K, V, S> {
|
||||
fn type_name() -> &'static str {
|
||||
"IndexMap"
|
||||
}
|
||||
|
||||
fn value_type() -> ValueType {
|
||||
ValueType::Object
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "object_indexmap")]
|
||||
impl<K: From<String> + Hash + Eq, V: FromNapiValue> ValidateNapiValue for IndexMap<K, V> {}
|
||||
|
||||
#[cfg(feature = "object_indexmap")]
|
||||
impl<K, V, S> ToNapiValue for IndexMap<K, V, S>
|
||||
where
|
||||
K: AsRef<str>,
|
||||
V: ToNapiValue,
|
||||
S: Default + BuildHasher,
|
||||
{
|
||||
unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||
let env = Env::from(raw_env);
|
||||
let mut obj = env.create_object()?;
|
||||
for (k, v) in val.into_iter() {
|
||||
obj.set(k.as_ref(), v)?;
|
||||
}
|
||||
|
||||
unsafe { Object::to_napi_value(raw_env, obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "object_indexmap")]
|
||||
impl<K, V, S> FromNapiValue for IndexMap<K, V, S>
|
||||
where
|
||||
K: From<String> + Hash + Eq,
|
||||
V: FromNapiValue,
|
||||
S: Default + BuildHasher,
|
||||
{
|
||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||
let obj = unsafe { Object::from_napi_value(env, napi_val)? };
|
||||
let mut map = IndexMap::default();
|
||||
for key in Object::keys(&obj)?.into_iter() {
|
||||
if let Some(val) = obj.get(&key)? {
|
||||
map.insert(K::from(key), val);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ napi-shared = { path = "../napi-shared" }
|
|||
serde = "1"
|
||||
serde_derive = "1"
|
||||
serde_json = "1"
|
||||
indexmap = "2"
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
napi = { path = "../../crates/napi", default-features = false, features = [
|
||||
|
@ -27,6 +28,7 @@ napi = { path = "../../crates/napi", default-features = false, features = [
|
|||
"experimental",
|
||||
"latin1",
|
||||
"chrono_date",
|
||||
"object_indexmap",
|
||||
"tokio",
|
||||
"async",
|
||||
"tokio_rt",
|
||||
|
@ -43,6 +45,7 @@ napi = { path = "../../crates/napi", default-features = false, features = [
|
|||
"experimental",
|
||||
"latin1",
|
||||
"chrono_date",
|
||||
"object_indexmap",
|
||||
"tokio",
|
||||
"async",
|
||||
"tokio_rt",
|
||||
|
|
|
@ -392,6 +392,8 @@ Generated by [AVA](https://avajs.dev).
|
|||
␊
|
||||
export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void␊
|
||||
␊
|
||||
export function getBtreeMapping(): BTreeMap␊
|
||||
␊
|
||||
export function getBuffer(): Buffer␊
|
||||
␊
|
||||
export function getCwd(callback: (arg0: string) => void): void␊
|
||||
|
@ -402,6 +404,8 @@ Generated by [AVA](https://avajs.dev).
|
|||
␊
|
||||
export function getGlobal(): typeof global␊
|
||||
␊
|
||||
export function getIndexMapping(): IndexMap␊
|
||||
␊
|
||||
export function getMapping(): Record<string, number>␊
|
||||
␊
|
||||
export function getModuleFileName(): string␊
|
||||
|
@ -425,6 +429,8 @@ Generated by [AVA](https://avajs.dev).
|
|||
␊
|
||||
export function getWords(): Array<string>␊
|
||||
␊
|
||||
export function indexmapPassthrough(fixture: IndexMap): IndexMap␊
|
||||
␊
|
||||
/** default enum values are continuos i32s start from 0 */␊
|
||||
export const enum Kind {␊
|
||||
/** Barks */␊
|
||||
|
@ -544,6 +550,10 @@ Generated by [AVA](https://avajs.dev).
|
|||
name: string␊
|
||||
}␊
|
||||
␊
|
||||
export function sumBtreeMapping(nums: BTreeMap): number␊
|
||||
␊
|
||||
export function sumIndexMapping(nums: IndexMap): number␊
|
||||
␊
|
||||
export function sumMapping(nums: Record<string, number>): number␊
|
||||
␊
|
||||
export function sumNums(nums: Array<number>): number␊
|
||||
|
|
Binary file not shown.
|
@ -34,6 +34,11 @@ const {
|
|||
sumNums,
|
||||
getMapping,
|
||||
sumMapping,
|
||||
getBtreeMapping,
|
||||
sumBtreeMapping,
|
||||
getIndexMapping,
|
||||
sumIndexMapping,
|
||||
indexmapPassthrough,
|
||||
getCwd,
|
||||
Animal,
|
||||
Kind,
|
||||
|
@ -202,6 +207,11 @@ test('array', (t) => {
|
|||
test('map', (t) => {
|
||||
t.deepEqual(getMapping(), { a: 101, b: 102 })
|
||||
t.is(sumMapping({ a: 101, b: 102 }), 203)
|
||||
t.deepEqual(getBtreeMapping(), { a: 101, b: 102 })
|
||||
t.is(sumBtreeMapping({ a: 101, b: 102 }), 203)
|
||||
t.deepEqual(getIndexMapping(), { a: 101, b: 102 })
|
||||
t.is(sumIndexMapping({ a: 101, b: 102 }), 203)
|
||||
t.deepEqual(indexmapPassthrough({ a: 101, b: 102 }), { a: 101, b: 102 })
|
||||
})
|
||||
|
||||
test('enum', (t) => {
|
||||
|
|
10
examples/napi/index.d.ts
vendored
10
examples/napi/index.d.ts
vendored
|
@ -382,6 +382,8 @@ export function fibonacci(n: number): number
|
|||
|
||||
export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void
|
||||
|
||||
export function getBtreeMapping(): BTreeMap
|
||||
|
||||
export function getBuffer(): Buffer
|
||||
|
||||
export function getCwd(callback: (arg0: string) => void): void
|
||||
|
@ -392,6 +394,8 @@ export function getExternal(external: ExternalObject<number>): number
|
|||
|
||||
export function getGlobal(): typeof global
|
||||
|
||||
export function getIndexMapping(): IndexMap
|
||||
|
||||
export function getMapping(): Record<string, number>
|
||||
|
||||
export function getModuleFileName(): string
|
||||
|
@ -415,6 +419,8 @@ export function getUndefined(): void
|
|||
|
||||
export function getWords(): Array<string>
|
||||
|
||||
export function indexmapPassthrough(fixture: IndexMap): IndexMap
|
||||
|
||||
/** default enum values are continuos i32s start from 0 */
|
||||
export const enum Kind {
|
||||
/** Barks */
|
||||
|
@ -534,6 +540,10 @@ export interface StrictObject {
|
|||
name: string
|
||||
}
|
||||
|
||||
export function sumBtreeMapping(nums: BTreeMap): number
|
||||
|
||||
export function sumIndexMapping(nums: IndexMap): number
|
||||
|
||||
export function sumMapping(nums: Record<string, number>): number
|
||||
|
||||
export function sumNums(nums: Array<number>): number
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
#[napi]
|
||||
fn get_mapping() -> HashMap<String, u32> {
|
||||
|
@ -12,3 +14,34 @@ fn get_mapping() -> HashMap<String, u32> {
|
|||
fn sum_mapping(nums: HashMap<String, u32>) -> u32 {
|
||||
nums.into_values().sum()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn get_btree_mapping() -> BTreeMap<String, u32> {
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert("a".to_string(), 101);
|
||||
map.insert("b".to_string(), 102);
|
||||
map
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn sum_btree_mapping(nums: BTreeMap<String, u32>) -> u32 {
|
||||
nums.into_values().sum()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn get_index_mapping() -> IndexMap<String, u32> {
|
||||
let mut map = IndexMap::new();
|
||||
map.insert("a".to_string(), 101);
|
||||
map.insert("b".to_string(), 102);
|
||||
map
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn sum_index_mapping(nums: IndexMap<String, u32>) -> u32 {
|
||||
nums.into_values().sum()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn indexmap_passthrough(fixture: IndexMap<String, u32>) -> IndexMap<String, u32> {
|
||||
fixture
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue