napi-rs/memory-testing/src/lib.rs
LongYinan 4719caa643
feat(napi): support Return generic of ThreadsafeFunction (#1997)
* feat(napi): support to use tuple with either (#1993)

`Either` uses `ValidateNapiValue` + `TypeName` to validate and report error on value not being matched. So there's no way to remove these super traits from it. So I implemented these types to `Tuple` types.

* feat(napi): support `Return` generic of ThreadsafeFunction

* depracate JsFunction

* CalleeHandled tsfn should handle Result in callback

* Pass env to call_with_return_value callback

* Fix compile

* clippy fix

* Fix electron test

* Function args

---------

Co-authored-by: Hana <andywangsy@gmail.com>
2024-03-20 21:37:08 +08:00

183 lines
4.1 KiB
Rust

use std::thread::spawn;
use napi::{
bindgen_prelude::*,
threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode},
};
#[macro_use]
extern crate napi_derive;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Welcome {
id: String,
name: String,
forename: String,
description: String,
email: String,
phone: String,
#[serde(rename = "arrivalDate")]
arrival_date: i64,
#[serde(rename = "departureDate")]
departure_date: i64,
price: i64,
advance: i64,
#[serde(rename = "advanceDueDate")]
advance_due_date: i64,
kids: i64,
adults: i64,
status: String,
nourishment: String,
#[serde(rename = "createdAt")]
created_at: String,
room: Room,
}
#[derive(Serialize, Deserialize)]
pub struct Room {
id: String,
name: String,
}
#[napi]
pub fn test_async(env: Env) -> napi::Result<napi::JsObject> {
let data = serde_json::json!({
"findFirstBooking": {
"id": "ckovh15xa104945sj64rdk8oas",
"name": "1883da9ff9152",
"forename": "221c99bedc6a4",
"description": "8bf86b62ce6a",
"email": "9d57a869661cc",
"phone": "7e0c58d147215",
"arrivalDate": -92229669,
"departureDate": 202138795,
"price": -1592700387,
"advance": -369294193,
"advanceDueDate": 925000428,
"kids": 520124290,
"adults": 1160258464,
"status": "NO_PAYMENT",
"nourishment": "BB",
"createdAt": "2021-05-19T12:58:37.246Z",
"room": { "id": "ckovh15xa104955sj6r2tqaw1c", "name": "38683b87f2664" }
}
});
env.execute_tokio_future(
async move { Ok(serde_json::to_string(&data).unwrap()) },
|env, res| {
env.adjust_external_memory(res.len() as i64)?;
env.create_string_from_std(res)
},
)
}
#[napi]
pub fn from_js(env: Env, input_object: Object) -> napi::Result<String> {
let a: Welcome = env.from_js_value(input_object)?;
Ok(serde_json::to_string(&a)?)
}
pub struct ChildHolder {
inner: &'static MemoryHolder,
}
impl ChildHolder {
fn count(&self) -> usize {
self.inner.0.len()
}
}
#[napi]
pub struct MemoryHolder(Vec<u8>);
#[napi]
impl MemoryHolder {
#[napi(constructor)]
pub fn new(mut env: Env, len: u32) -> Result<Self> {
env.adjust_external_memory(len as i64)?;
Ok(Self(vec![42; len as usize]))
}
#[napi]
pub fn create_reference(
&self,
env: Env,
holder_ref: Reference<MemoryHolder>,
) -> Result<ChildReference> {
let child_holder =
holder_ref.share_with(env, |holder_ref| Ok(ChildHolder { inner: holder_ref }))?;
Ok(ChildReference(child_holder))
}
}
#[napi]
pub struct ChildReference(SharedReference<MemoryHolder, ChildHolder>);
#[napi]
impl ChildReference {
#[napi]
pub fn count(&self) -> u32 {
self.0.count() as u32
}
}
#[napi]
pub fn leaking_func(env: Env, func: JsFunction) -> napi::Result<()> {
let mut tsfn: ThreadsafeFunction<String> =
func.create_threadsafe_function(|mut ctx: ThreadsafeCallContext<String>| {
ctx.env.adjust_external_memory(ctx.value.len() as i64)?;
ctx
.env
.create_string_from_std(ctx.value)
.map(|js_string| vec![js_string])
})?;
tsfn.unref(&env)?;
spawn(move || {
tsfn.call(Ok("foo".into()), ThreadsafeFunctionCallMode::Blocking);
});
Ok(())
}
#[napi]
pub fn buffer_convert(buffer: Buffer) -> Buffer {
Buffer::from(vec![0; buffer.len()])
}
#[napi]
pub fn buffer_len() -> u32 {
Buffer::from(vec![0; 1024 * 10240]).len() as u32
}
#[napi]
pub fn array_buffer_convert(array_buffer: Uint8Array) -> Uint8Array {
Uint8Array::new(vec![1; array_buffer.len()])
}
#[napi]
pub fn array_buffer_create_from_vec_with_spare_capacity() -> Uint8Array {
let mut v = vec![1; 1024 * 10240];
v.truncate(1);
Uint8Array::new(v)
}
#[napi]
pub fn array_buffer_len() -> u32 {
Uint8Array::new(vec![1; 1024 * 10240]).len() as u32
}
#[napi]
pub fn buffer_pass_through(buffer: Buffer) -> Buffer {
buffer
}
#[napi]
pub fn array_buffer_pass_through(array_buffer: Uint8Array) -> Uint8Array {
array_buffer
}
#[napi]
pub async fn returns_future() {}