OHOS_NAPI_RS 用户指南
ohos_napi_rs为用户提供了ArkTS和Rust交互的能力。用户通过#[napi]过程宏轻松完成ArkTS和Rust数据类型转换。
命名约定
Rust 和 ArkTS的代码风格有很大区别,Rust 社区喜欢 snake_case 风格,而 ArkTS社区延用JavaScript ,更喜欢 camelCase 风格。ohos_napi_rs 会自动将 Rust 代码的风格转换为 camelCase 风格。
#[napi]
fn rust_add(a: u32, b: u32) -> u32 {
a + b
}
#[napi(constructor)]
pub struct NapiStruct {
pub napi_name: String,
pub napi_kind: u32,
}
index.d.ts
export declare function rustAdd(a: number, b: number): number;
export declare class NapiStruct {
napiName: string
napiKind: number
constructor(napiName: string, napiKind: number)
}
Rust模块显式注册和隐式注册
ArkTS Runtime本身没有提供自动注册机制,需要主动调用napi_module_register进行注册,当前ohos_napi_rs提供显式注册和隐式注册两种方式,默认为隐式注册。
隐式注册
ohos_napi_rs默认机制,在#[napi] 宏展开时默认生成napi_module_register模块注册逻辑,模块名使用CARGO_PKG_NAME环境变量设置的名字。用户什么也不需要做。
显式注册
用户通过feature ohos-explicit-register关闭隐式注册功能,然后自己在代码中调用ohos_napi_rs提供的宏接口ohos_module_register进行显式注册,宏接口参数为模块名,例如。
//Cargo.toml
[dependencies]
napi-derive = { path = "../../crates/macro", features = ["ohos-explicit-register"] }
napi::ohos_module_register!("arkts_napi_sdv");
类型转化
Rust 和 ArkTS类型之间的转换。
| ArkTS 类型 | Rust类型 | 备注 |
|---|---|---|
| undefined | Undefined | 无 |
| null | Null | 无 |
| boolean | bool | 无 |
| number | u8、i8、u16、i16、u32、i32、i64、f64 | 无 |
| number | f32 | Rust f32可以转换成ArkTS number,反之不行 |
| bigint | BigInt | 无 |
| bigint | u64、u128、i128 | Rust u64、u128、i128可以转换成ArkTS bigint,反之不行 |
| string | String、&'a str | Rust &'a str可以转换成ArkTS string,反之不行 |
| string | Utf16String | 无 |
| string | Latin1String | 无 |
| object | Object | 无 |
| Array | Vec、Array | 无 |
| ArrayBuffer、ArrayBufferLike | Buffer | 无 |
| Uint8Array | Uint8Array | 无 |
| Uint8ClampedArray | Uint8ClampedArray | 无 |
| Int16Array | Int16Array | 无 |
| Uint16Array | Uint16Array | 无 |
| Int32Array | Int32Array | 无 |
| Uint32Array | Uint32Array | 无 |
| Float32Array | Float32Array | 无 |
| Float64Array | Float64Array | 无 |
| BigInt64Array | BigInt64Array | 无 |
| BigUint64Array | BigUint64Array | 无 |
| Record | HashMap | 无 |
| Promise | AsyncTask | 无 |
| Promise | async fn | 无 |
| function | Function | 无 |
Undefined
代表 ArkTS中的 undefined。
lib.rs
#[napi]
fn return_undefined() -> Undefined {}
index.d.ts
export declare function returnUndefined(): undefined
ets
expect(rustNapi.returnUndefined()).assertEqual(undefined)
Null
代表 ArkTS中的 null。
lib.rs
#[napi]
fn return_null() -> Null {
Null
}
index.d.ts
export declare function returnNull(): null
ets
expect(rustNapi.returnNull()).assertEqual(null)
Numbers
ArkTSNumber 等同于这些 Rust 整数/浮点数 类型: u8、i8、u16、i16、u32、i32、i64、f64。 Rust f32可以转换成ArkTS number,反之不行,会丢失精度。
lib.rs
#[napi]
fn add(a: u32, b: u32) -> u32 {
a + b
}
index.d.ts
export declare function add(a: number, b: number): number;
ets
let res1 = rustNapi.add(2, 4);
expect(res1).assertEqual(6);
BigInt
在 Rust 中传递 BigInt 的唯一方法是使用 BigInt 类型。Rust u64、u128、i128可以转换成ArkTS bigint,反之不行,转换时会丢失精度。
lib.rs
#[napi]
fn bigint_add(a: BigInt, b: BigInt) -> u128 {
a.get_u128().1 + b.get_u128().1
}
#[napi]
pub fn bigint_from_i64() -> BigInt {
BigInt::from(100i64)
}
index.d.ts
export declare function bigintAdd(a: bigint, b: bigint): bigint
export declare function bigintFromI64(): bigint
ets
expect(rustNapi.bigintAdd(BigInt('1111111111'), BigInt('2222222222'))).assertEqual(BigInt('3333333333'))
expect(rustNapi.bigintFromI64()).assertEqual(BigInt('100'))
String
代表 ArkTS的 String 类型。
lib.rs
#[napi]
fn concat_str(mut s: String) -> String {
s.push_str(" + Rust 🦀 string!");
s
}
index.d.ts
export declare function concatStr(s: string): string
ets
let res = rustNapi.concatStr('æ¶½¾DEL');
expect(res).assertEqual('æ¶½¾DEL + Rust 🦀 string!');
Boolean
代表 ArkTSBoolean 类型。
lib.rs
#[napi]
fn contains(source: String, target: String) -> bool {
source.contains(&target)
}
index.d.ts
export declare function contains(source: string, target: string): boolean
ets
let res = rustNapi.contains('hello', 'ell');
expect(res).assertTrue();
Buffer
lib.rs
#[napi]
fn get_buffer() -> Buffer {
String::from("Hello world").as_bytes().into()
}
#[napi]
fn append_buffer(buf: Buffer) -> Buffer {
let mut buf = Vec::<u8>::from(buf);
buf.push(b'!');
buf.into()
}
index.d.ts
export declare function getBuffer(): ArrayBuffer
export declare function appendBuffer(buf: ArrayBuffer): ArrayBuffer
ets
let buf = rustNapi.getBuffer()
expect(buf.toString()).assertEqual('Hello world')
let temp = buffer.from('Hello world').buffer
buf = rustNapi.appendBuffer(temp)
expect(buf.toString()).assertEqual('Hello world!')
Object
代表 Arkts匿名对象值。
lib.rs
#[napi]
fn list_obj_keys(obj: Object) -> Vec<String> {
Object::keys(&obj).unwrap()
}
#[napi]
fn create_obj(env: Env) -> Object {
let mut obj = env.create_object().unwrap();
obj.set("test", 1).unwrap();
obj
}
index.d.ts
export declare function listObjKeys(obj: object): Array<string>
export declare function createObj(): object
ets
let res1 = rustNapi.listObjKeys({ name: 'John Doe', age: 20 });
expect(res1).assertDeepEquals(['name', 'age']);
let res2 = rustNapi.createObj()
expect(res2).assertDeepEquals({ test: 1 });
如果您想要用 Rust 中定义的结构来转换 Arkts中的对象,您可以使用 #[napi] 宏里面的 object 属性。
lib.rs
/// #[napi(object)] 需要所有的结构体字段都是对外可见的
#[napi(object)]
pub struct StrictObject {
pub name: String,
}
#[napi]
pub fn receive_strict_object(strict_object: StrictObject) {
assert_eq!(strict_object.name, "strict");
}
index.d.ts
export interface StrictObject {
name: string
}
export declare function receiveStrictObject(strictObject: StrictObject): void
ets
rustNapi.receiveStrictObject({ name: 'strict' })
注意:Rust
fn中传入的#[napi(object)]结构体是从ArkTS克隆的, 对其的任何更改都不会影响到原始的ArkTS对象。
Array
lib.rs
#[napi]
fn sum_nums(nums: Vec<u32>) -> u32 {
nums.iter().sum()
}
#[napi]
pub fn get_words() -> Vec<&'static str> {
vec!["foo", "bar"]
}
index.d.ts
export declare function sumNums(nums: Array<number>): number
export declare function getWords(): Array<string>
ets
let res1 = rustNapi.sumNums([1, 2, 3, 4, 5])
expect(res1).assertEqual(15)
let res2 = rustNapi.getWords()
expect(res2).assertDeepEquals(['foo', 'bar'])
TypedArray
lib.rs
#[napi]
fn convert_u32_array(input: Uint32Array) -> Vec<u32> {
input.to_vec()
}
#[napi]
fn mutate_typed_array(mut input: Float32Array) {
for item in input.as_mut() {
*item *= 2.0;
}
}
#[napi]
fn create_external_typed_array() -> Uint32Array {
Uint32Array::new(vec![1, 2, 3, 4, 5])
}
#[napi]
fn u32_array_to_array(input: &[u32]) -> Vec<u32> {
input.to_vec()
}
index.d.ts
export declare function convertU32Array(input: Uint32Array): Array<number>
export declare function mutateTypedArray(input: Float32Array): void
export declare function createExternalTypedArray(): Uint32Array
export declare function u32ArrayToArray(input: Uint32Array): Array<number>
ets
const input = new Uint32Array([1, 2, 3, 4, 5])
expect(rustNapi.convertU32Array(input)).assertDeepEquals(Array.from(input))
let input: Float32Array = new Float32Array([1, 2, 3, 4, 5])
rustNapi.mutateTypedArray(input)
expect(input).assertDeepEquals(new Float32Array([2.0, 4.0, 6.0, 8.0, 10.0]))
expect(rustNapi.createExternalTypedArray()).assertDeepEquals(new Uint32Array([1, 2, 3, 4, 5]))
expect(rustNapi.u32ArrayToArray(new Uint32Array([1, 2, 3]))).assertDeepEquals([1, 2, 3])
与 object不同,传递给 Rust 的
TypedArray是一个 引用, 不会执行任何数据Copy或Clone,对TypedArray的每次更改都会反映到原始的 JavaScriptTypedArray。
HashMap
lib.rs
#[napi]
fn get_mapping() -> HashMap<String, u32> {
let mut map = HashMap::new();
map.insert("a".to_string(), 101);
map.insert("b".to_string(), 102);
map
}
#[napi]
fn sum_mapping(nums: HashMap<String, u32>) -> u32 {
nums.into_values().sum()
}
index.d.ts
export declare function getMapping(): Record<string, number>
export declare function sumMapping(nums: Record<string, number>): number
ets
let res1 = rustNapi.getMapping()
expect(res1).assertDeepEquals({ 'a': 101, 'b': 102 })
let res2 = rustNapi.sumMapping({ 'a': 101, 'b': 102 })
expect(res2).assertEqual(203)
类
默认 constructor
如果一个 Rust 结构体中的所有字段都是 pub,那么您可以使用 #[napi(constructor)] 来使 struct 有一个默认的 constructor。
lib.rs
#[napi(constructor)]
pub struct AnimalWithDefaultConstructor {
pub name: String,
pub kind: u32,
}
index.d.ts
export declare class AnimalWithDefaultConstructor {
name: string
kind: number
constructor(name: string, kind: number)
}
ets
let n = new rustNapi.AnimalWithDefaultConstructor('jony', rustNapi.Kind.Duck)
expect(n.name).assertEqual('jony')
expect(n.kind).assertEqual(rustNapi.Kind.Duck)
自定义 constructor
如果您想定义一个自定义的 constructor,您可以在结构体的 impl 块中的构造函数 fn 上面使用 #[napi(constructor)]。
lib.rs
#[napi]
pub struct Bird {
pub name: String,
}
#[napi]
impl Bird {
#[napi(constructor)]
pub fn new(name: String) -> Self {
Bird { name }
}
}
index.d.ts
export declare class Bird {
name: string
constructor(name: string)
}
ets
let bird = new rustNapi.Bird('Carolyn')
工厂
除了 constructor 之外,您还可以使用 #[napi(factory)] 在 Class 上定义工厂方法。
lib.rs
#[napi]
pub struct ClassWithFactory {
pub name: String,
}
#[napi]
impl ClassWithFactory {
#[napi(factory)]
pub fn with_name(name: String) -> Self {
Self { name }
}
#[napi]
pub fn set_name(&mut self, name: String) -> &Self {
self.name = name;
self
}
}
index.d.ts
export declare class ClassWithFactory {
name: string
static withName(name: string): ClassWithFactory
setName(name: string): this
}
ets
let duck = rustNapi.ClassWithFactory.withName('Default')
expect(duck.name).assertEqual('Default')
let ret = duck.setName('D')
expect(duck.name).assertEqual('D')
expect(ret).assertEqual(duck)
class Method、Getter和Setter
您可以在 Rust 的结构体方法上使用 #[napi] 定义一个 ArkTS 类方法。使用 #[napi(getter)] 定义ArkTS类的getter,使用 #[napi(setter)] 定义ArkTS类的setter。
lib.rs
#[napi]
pub struct Animal {
name: String,
}
#[napi]
impl Animal {
#[napi(constructor)]
pub fn new(name: String) -> Self {
Animal { name }
}
#[napi(getter)]
pub fn get_name(&self) -> &str {
self.name.as_str()
}
#[napi(setter)]
pub fn set_name(&mut self, name: String) {
self.name = name;
}
#[napi]
pub fn whoami(&self) -> String {
self.name
}
}
index.d.ts
export declare class Animal {
constructor(name: string)
get name(): string
set name(name: string)
whoami(): string
}
ets
let dog = new rustNapi.Animal('a')
expect(dog.name).assertEqual('a')
expect(dog.whoami()).assertEqual('a')
dog.name = 'b'
expect(dog.name).assertEqual('b')
类作为参数
Class 与Object不同, Class 可以有关联Rust 方法。Class 中的每个字段都可以在 ArkTS中被修改。
因此,当您创建类时,该类的所有权实际上已转移到 ArkTS端,它由 ArkTS GC 管理,您只能通过传递其引用将其传回。
lib.rs
#[napi]
impl RefBird {
#[napi(constructor)]
pub fn new(age: u32) -> Self {
RefBird { age }
}
#[napi]
pub fn get_age(&self) -> u32 {
self.age
}
#[napi]
pub fn set_age(&mut self, age: u32) {
self.age = age;
}
}
#[napi]
pub fn class_ref1(bird: &mut RefBird) {
bird.set_age(200)
}
#[napi]
pub fn class_ref2(bird: &RefBird) -> u32 {
bird.get_age()
}
index.d.ts
export declare class RefBird {
constructor(age: number)
getAge(): number
setAge(age: number): void
}
export declare function classRef1(bird: RefBird): void
export declare function classRef2(bird: RefBird): number
ets
let bird = new rustNapi.RefBird(10)
expect(bird.getAge()).assertEqual(10)
rustNapi.classRef1(bird)
expect(bird.getAge()).assertEqual(200)
let res = rustNapi.classRef2(bird)
expect(res).assertEqual(200)
自定义终结逻辑
当 ArkTS对象被垃圾回收时,会释放 ArkTS 对象中封装的 Rust 结构体,您还可以为 Rust 结构体指定自定义终结逻辑。
lib.rs
#[napi(custom_finalize)]
pub struct CustomFinalize {
width: u32,
height: u32,
inner: Vec<u8>,
}
#[napi]
impl CustomFinalize {
#[napi(constructor)]
pub fn new(width: u32, height: u32) -> Result<Self> {
let inner = vec![0; (width * height * 4) as usize];
Ok(Self {
width,
height,
inner,
})
}
}
impl ObjectFinalize for CustomFinalize {
fn finalize(self, _env: Env) -> Result<()> {
oh_log_info!("{:?}", self.inner);
Ok(())
}
}
index.d.ts
export declare class CustomFinalize {
constructor(width: number, height: number)
getSize(): number
}
ets
let c = new rustNapi.CustomFinalize(200, 200);
枚举
不支持将 Rust enum 的 impl 生成到 ArkTS中。
普通枚举
Rust enum 被转换为普通的 ArkTS对象。
lib.rs
#[napi]
pub enum Kind {
Dog,
Cat,
Duck,
}
index.d.ts
export declare const enum Kind {
Dog = 0,
Cat = 1,
Duck = 2
}
ets
let res = [rustNapi.Kind.Dog, rustNapi.Kind.Cat, rustNapi.Kind.Duck]
expect(res).assertDeepEquals([0, 1, 2])
字符串枚举
lib.rs
#[napi(string_enum)]
pub enum Status {
Pristine,
Loading,
Ready,
}
#[napi]
fn enum_to_status() -> Status {
Status::Loading
}
index.d.ts
export declare const enum Status {
Pristine = 'Pristine',
Loading = 'Loading',
Ready = 'Ready'
}
export declare function enumToStatus(): Status
ets
let res = rustNapi.enumToStatus();
expect(res).assertEqual(rustNapi.Status.Loading);
函数
ArkTS可以传递一个函数到Rust侧执行。
lib.rs
#[napi]
pub fn call_function(cb: Function<(), u32>) -> Result<u32> {
cb.call(())
}
#[napi]
pub fn call_function_with_arg(cb: Function<(u32, u32), u32>, arg0: u32, arg1: u32) -> Result<u32> {
cb.call((arg0, arg1))
}
index.d.ts
export declare function callFunction(cb: () => number): number
export declare function callFunctionWithArg(cb: (arg0: number, arg1: number) => number, arg0: number, arg1: number): number
ets
let res1 = rustNapi.callFunction(() => 42);
expect(res1).assertEqual(42);
let res2 = rustNapi.callFunctionWithArg((a, b) => a + b, 42, 10);
expect(res2).assertEqual(52);
线程安全函数
线程安全函数机制,允许用户将ArkTS函数传递给Rust侧,并且在Rust的任意线程中执行该ArkTS函数。
lib.rs
#[napi]
pub fn call_threadsafe_function(callback: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<u32, ErrorStrategy::CalleeHandled> =
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value + 1]))?;
for n in 0..100 {
let tsfn = tsfn.clone();
thread::spawn(move || {
tsfn.call(Ok(n), ThreadsafeFunctionCallMode::NonBlocking);
});
}
Ok(())
}
index.d.ts
export declare function callThreadsafeFunction(callback: (err: Error|null, arg: number) => void): void
ets
let i: number = 0
let value: number = 0
let p: Promise<number> = new Promise((resolve: Function) => {
rustNapi.callThreadsafeFunction((_, v) => {
i++
value += v
if (i === 100) {
resolve(value)
}
})
})
let res = await p;
expect(res).assertEqual(5050)
ErrorStrategy
Threadsafe Function 有两种不同的错误处理策略,您可以在 ThreadsafeFunction 的第二个泛型参数中定义策略:
lib.rs
let tsfn: ThreadsafeFunction<u32, ErrorStrategy::CalleeHandled> = ...
ErrorStrategy::CalleeHandled
Rust 代码中的 Err 将被传递到 ArkTS回调的参数中。使用 ErrorStrategy::CalleeHandled,您必须使用 Result 类型调用 ThreadsafeFunction, 这样 Error 才会被处理并传递回 ArkTS回调:
lib.rs
#[napi]
pub fn call_threadsafe_function(callback: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<u32, ErrorStrategy::CalleeHandled> =
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value + 1]))?;
for n in 0..100 {
let tsfn = tsfn.clone();
thread::spawn(move || {
tsfn.call(Ok(n), ThreadsafeFunctionCallMode::NonBlocking);
});
}
Ok(())
}
index.d.ts
export declare function callThreadsafeFunction(callback: (err: Error|null, arg: number) => void): void
ErrorStrategy::Fatal
不传递 Error 给 ArkTS端,如果您的代码不会返回 Err ,您可以使用这种策略来避免在 Rust 代码中使用 Ok 封装。
通过这种策略,ThreadsafeFunction 不需要使用 Result<T> 调用,并且ArkTS回调的参数是 Rust 中的值,而不是 Error | null。
lib.rs
#[napi]
pub fn threadsafe_function_fatal_mode(cb: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<bool, ErrorStrategy::Fatal> =
cb.create_threadsafe_function(0, |ctx| ctx.env.get_boolean(ctx.value).map(|v| vec![v]))?;
thread::spawn(move || {
tsfn.call(true, ThreadsafeFunctionCallMode::Blocking);
});
Ok(())
}
index.d.ts
export declare function threadsafeFunctionFatalMode(cb: (arg: boolean) => void): void
ets
let tsfnFatalMode = new Promise<boolean>((resolve) => {
rustNapi.threadsafeFunctionFatalMode((arg: boolean) => {
resolve(arg)
})
})
let res = await tsfnFatalMode;
expect(res).assertEqual(true)
异步任务
异步任务机制,允许用户创建一个异步工作对象,可以在需要执行耗时操作的场景中使用,以避免阻塞主线程。Task 特征提供了一种定义这样的异步任务的方法,该任务需要在 libuv 线程中运行,您可以实现 compute 方法,该方法将在 libuv 线程中调用。
fn compute 方法在 libuv 线程中运行,您可以在这里运行一些繁重的计算,这不会阻塞 ArkTS主线程。 Task 特征上有两个关联类型,type Output 和 type JsValue, Output 是 compute 方法的返回类型,Output会传递给resolve方法,JsValue 是 resolve 方法的返回类型。fn compute 函数中无法回调 ArkTS函数,因为它不在主线程上执行。
lib.rs
struct AsyncSum {
input: u32,
}
impl Task for AsyncSum {
type Output = u32;
type JsValue = JsNumber;
fn compute(&mut self) -> Result<Self::Output> {
Ok(task_sum(self.input))
}
fn resolve(&mut self, env: Env, output: u32) -> Result<Self::JsValue> {
env.create_uint32(output)
}
}
#[napi]
fn async_sum(input: u32) -> AsyncTask<AsyncSum> {
AsyncTask::new(AsyncSum { input })
}
index.d.ts
export declare function asyncSum(input: number): Promise<number>
ets
let res = await rustNapi.asyncSum(10);
expect(res).assertEqual(45)
除了 compute 和 resolve,您还可以提供 reject 方法,当 Task 的compute遇到错误时,可以执行一些清理工作。您还可以提供一个 finally 方法,在 Task 被 resolved 或 rejected 后执行一些操作。
struct AsyncFailed;
impl Task for AsyncFailed {
type Output = u32;
type JsValue = JsNumber;
fn compute(&mut self) -> Result<Self::Output> {
let err = Error::new(Status::Cancelled, "failed to call compute");
Err(err)
}
fn resolve(&mut self, env: Env, output: u32) -> Result<Self::JsValue> {
env.create_uint32(output)
}
fn reject(&mut self, _env: Env, err: Error) -> Result<Self::JsValue> {
oh_log_info!("in AsyncSum reject");
Err(err)
}
fn finally(&mut self, _env: Env) -> Result<()> {
oh_log_info!("in AsyncSum finally");
Ok(())
}
}
#[napi]
fn async_failed() -> AsyncTask<AsyncFailed> {
AsyncTask::new(AsyncFailed)
}
index.d.ts
export declare function asyncFailed(): Promise<number>
ets
try {
await rustNapi.asyncFailed();
expect(false).assertTrue();
} catch (err) {
expect(err.message).assertEqual('failed to call compute');
expect(err.code).assertEqual('Cancelled')
}
异步函数
为了使用 async fn ,您必须开启 napi 的 async 或 tokio_rt 特性:
Cargo.toml
[dependencies]
napi = { features = ["async"] }
ohos_napi_rs 默认支持 tokio 运行时,如果您在 async fn 中 await 一个 tokio future, ohos_napi_rs 将在 tokio 运行时中执行它,并将其转换为 ArkPromise。
lib.rs
use futures::prelude::*;
use tokio::fs;
#[napi]
async fn read_file_async(path: String) -> Result<Buffer> {
fs::read(path)
.map(|r| match r {
Ok(content) => Ok(content.into()),
Err(e) => Err(Error::new(
Status::GenericFailure,
format!("failed to read file, {}", e),
)),
})
.await
}
index.d.ts
export declare function readFileAsync(path: string): Promise<ArrayBuffer>
ets
import fs from '@ohos.file.fs';
let context = getContext()
let tempDir = context.tempDir;
// 新建并打开文件
let file = fs.openSync(tempDir + '/rust_test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
// 写入一段内容至文件
fs.writeSync(file.fd, 'Try to write str.');
// 关闭文件
fs.closeSync(file.fd)
let data = await rustNapi.readFileAsync(tempDir + '/rust_test.txt')
expect(data).assertDeepEquals(buffer.from('Try to write str.').buffer);
Await Promise
支持在 Rust 中 await 一个 ArkTS Promise 。
lib.rs
#[napi]
pub async fn async_plus_100(p: Promise<u32>) -> Result<u32> {
let v = p.await?;
Ok(v + 100)
}
index.d.ts
export declare function asyncPlus100(p: Promise<number>): Promise<number>
ets
let fx = 20
let p = rustNapi.asyncPlus100(
new Promise((resolve) => {
setTimeout(() => resolve(fx), 50)
}),
)
let res = await p;
expect(res).assertEqual(fx + 100)
注入 Env
#[napi] 宏是对 Node-API 的一个非常高级的抽象,大多数情况下,您使用 Rust 的原生 API 和包。但是有时候您仍然需要访问底层的 Node-API。
对于这种情况,ohos_napi_rs 允许您通过 #[napi] 装饰,将 Env 注入到您的 fn 中。
lib.rs
#[napi]
pub fn env_create_string(env: Env) -> Result<JsString> {
env.create_string("env crete string")
}
Env 将会被 ohos_napi_rs 自动注入,这不会影响 ArkTS端的参数类型:
index.d.ts
export declare function envCreateString(): string
ets
expect(rustNapi.envCreateString()).assertEqual('env crete string')
ohos_napi_rs当前不支持特性
ohos_napi_rs还有部分特性没有从napi_rs仓库继承过来,包括:
1、不支持Symbol。
2、不支持Generator。
3、AsyncTask不支持AbortSignal 。
4、compat-mode模式当前未支持。