use napi::{CallContext, JsObject, JsString, JsUndefined, JsUnknown, Result}; use serde_json::{from_str, to_string}; #[derive(Serialize, Debug, Deserialize)] struct AnObject { a: u32, b: Vec, c: String, } #[derive(Serialize, Debug, Deserialize, Eq, PartialEq)] struct Inner; #[derive(Serialize, Debug, Deserialize, Eq, PartialEq)] struct Inner2(i32, bool, String); #[derive(Serialize, Debug, Deserialize, Eq, PartialEq)] enum TypeEnum { Empty, Tuple(u32, String), Struct { a: u8, b: Vec }, Value(Vec), } #[derive(Serialize, Debug, Deserialize, PartialEq)] struct AnObjectTwo { a: u32, b: Vec, c: String, d: Option, e: Option, f: Inner, g: Inner2, h: char, i: TypeEnum, j: TypeEnum, k: TypeEnum, l: String, m: Vec, o: TypeEnum, p: Vec, q: u128, r: i128, } #[derive(Serialize, Debug, Deserialize)] struct BytesObject<'a> { #[serde(with = "serde_bytes")] code: &'a [u8], map: String, } macro_rules! make_test { ($name:ident, $val:expr) => { #[js_function] fn $name(ctx: CallContext) -> Result { let value = $val; ctx.env.to_js_value(&value) } }; } make_test!(make_num_77, 77i32); make_test!(make_num_32, 32u8); make_test!(make_str_hello, "Hello World"); make_test!(make_num_array, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); make_test!( make_obj, AnObject { a: 1, b: vec![0.1f64, 1.1, 2.2, 3.3], c: "Hi".into(), } ); make_test!(make_map, { use std::collections::HashMap; let mut map = HashMap::new(); map.insert("a", 1); map.insert("b", 2); map.insert("c", 3); map }); make_test!(make_object, { AnObjectTwo { a: 1, b: vec![1, 2], c: "abc".into(), d: Some(false), e: None, f: Inner, g: Inner2(9, false, "efg".into()), h: '🤷', i: TypeEnum::Empty, j: TypeEnum::Tuple(27, "hij".into()), k: TypeEnum::Struct { a: 128, b: vec![9, 8, 7], }, l: "jkl".into(), m: vec![0, 1, 2, 3, 4], o: TypeEnum::Value(vec!['z', 'y', 'x']), p: vec![1., 2., 3.5], q: 9998881288248882845242411222333, r: -3332323888900001232323022221345, } }); const NUMBER_BYTES: &[u8] = &[255u8, 254, 253]; make_test!(make_buff, { serde_bytes::Bytes::new(NUMBER_BYTES) }); make_test!(make_bytes_struct, { BytesObject { code: &[0, 1, 2, 3], map: "source map".to_owned(), } }); macro_rules! make_expect { ($name:ident, $val:expr, $val_type:ty) => { #[js_function(1)] fn $name(ctx: CallContext) -> Result { let value = $val; let arg0 = ctx.get::(0)?; let de_serialized: $val_type = ctx.env.from_js_value(arg0)?; assert_eq!(value, de_serialized); ctx.env.get_undefined() } }; } make_expect!(expect_hello_world, "hello world", String); make_expect!( expect_obj, AnObjectTwo { a: 1, b: vec![1, 2], c: "abc".into(), d: Some(false), e: None, f: Inner, g: Inner2(9, false, "efg".into()), h: '🤷', i: TypeEnum::Empty, j: TypeEnum::Tuple(27, "hij".into()), k: TypeEnum::Struct { a: 128, b: vec![9, 8, 7], }, l: "jkl".into(), m: vec![0, 1, 2, 3, 4], o: TypeEnum::Value(vec!['z', 'y', 'x']), p: vec![1., 2., 3.5], q: 9998881288248882845242411222333, r: -3332323888900001232323022221345, }, AnObjectTwo ); make_expect!(expect_num_array, vec![0, 1, 2, 3], Vec); make_expect!( expect_buffer, serde_bytes::ByteBuf::from(vec![252u8, 251, 250]), serde_bytes::ByteBuf ); #[js_function(1)] fn roundtrip_object(ctx: CallContext) -> Result { let arg0 = ctx.get::(0)?; let de_serialized: AnObjectTwo = ctx.env.from_js_value(arg0)?; ctx.env.to_js_value(&de_serialized) } #[js_function(1)] fn from_json_string(ctx: CallContext) -> Result { let arg0 = ctx.get::(0)?.into_utf8()?; let de_serialized: AnObject = from_str(arg0.as_str()?)?; ctx.env.to_js_value(&de_serialized) } #[js_function(1)] fn json_to_string(ctx: CallContext) -> Result { let arg0 = ctx.get::(0)?; let de_serialized: AnObject = ctx.env.from_js_value(arg0)?; let json_string = to_string(&de_serialized)?; ctx.env.create_string_from_std(json_string) } pub fn register_js(exports: &mut JsObject) -> Result<()> { exports.create_named_method("make_num_77", make_num_77)?; exports.create_named_method("make_num_32", make_num_32)?; exports.create_named_method("make_str_hello", make_str_hello)?; exports.create_named_method("make_num_array", make_num_array)?; exports.create_named_method("make_buff", make_buff)?; exports.create_named_method("make_obj", make_obj)?; exports.create_named_method("make_object", make_object)?; exports.create_named_method("make_map", make_map)?; exports.create_named_method("make_bytes_struct", make_bytes_struct)?; exports.create_named_method("expect_hello_world", expect_hello_world)?; exports.create_named_method("expect_obj", expect_obj)?; exports.create_named_method("expect_num_array", expect_num_array)?; exports.create_named_method("expect_buffer", expect_buffer)?; exports.create_named_method("roundtrip_object", roundtrip_object)?; exports.create_named_method("from_json_string", from_json_string)?; exports.create_named_method("json_to_string", json_to_string)?; Ok(()) }