From e93a3f6d0607f86e2e25133c32d28b792904fb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 11 May 2021 13:37:46 +0200 Subject: [PATCH 01/23] initial modifications --- nj-core/src/convert.rs | 4 +- nj-core/src/error.rs | 11 ++- nj-derive/src/ast/types.rs | 163 ++++++++++++++++++++++++------------- 3 files changed, 119 insertions(+), 59 deletions(-) diff --git a/nj-core/src/convert.rs b/nj-core/src/convert.rs index 25f3b0e5..0fca0413 100644 --- a/nj-core/src/convert.rs +++ b/nj-core/src/convert.rs @@ -62,12 +62,12 @@ impl TryIntoJs for () { impl TryIntoJs for Result where T: TryIntoJs, - E: ToString, + E: TryIntoJs, { fn try_to_js(self, js_env: &JsEnv) -> Result { match self { Ok(val) => val.try_to_js(&js_env), - Err(err) => Err(NjError::Other(err.to_string())), + Err(err) => Err(NjError::Native(err.try_to_js(&js_env)?)), } } } diff --git a/nj-core/src/error.rs b/nj-core/src/error.rs index 780a0b37..585731bd 100644 --- a/nj-core/src/error.rs +++ b/nj-core/src/error.rs @@ -17,6 +17,7 @@ pub enum NjError { NoPlainConstructor, Utf8Error(FromUtf8Error), Utf8ErrorSlice(Utf8Error), + Native(napi_value), Other(String), } @@ -32,8 +33,13 @@ impl IntoJs for NjError { impl NjError { /// convert to napi value pub fn as_js(&self, js_env: &JsEnv) -> napi_value { - let msg = self.to_string(); - js_env.create_error(&msg).expect("error cannot be created") + match self { + NjError::Native(err) => *err, + other => { + let msg = self.to_string(); + js_env.create_error(&msg).expect("error cannot be created") + } + } } } @@ -84,6 +90,7 @@ impl fmt::Display for NjError { expected_count, actual_count ), Self::NoPlainConstructor => write!(f, "Plain constructor not supported yet"), + Self::Native(_val) => write!(f, "Native error payload"), Self::Other(msg) => write!(f, "{}", msg), } } diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 86d4e0fc..078698f0 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -7,6 +7,8 @@ use syn::Result; use syn::spanned::Spanned; use syn::DeriveInput; use syn::Data; +use syn::DataEnum; +use syn::DataStruct; use syn::Fields; use syn::GenericParam; use syn::WhereClause; @@ -109,30 +111,66 @@ impl MyTupleType<'_> { #[derive(Debug)] pub enum MyStruct<'a> { - Named { - name: &'a Ident, - fields: Vec>, - generics: MyGenerics<'a>, - }, - Unnamed { - name: &'a Ident, - fields: Vec>, - generics: MyGenerics<'a>, - }, + fields: MyFields<'a> } #[derive(Debug)] -pub struct MyField<'a> { +pub struct MyNamedField<'a> { pub name: &'a Ident, pub ty: MyFieldType<'a>, } +#[derive(Debug)] +pub struct MyUnnamedField<'a> { + pub ty: MyFieldType<'a> +} + #[derive(Debug)] pub enum MyFieldType<'a> { Path(MyTypePath<'a>), Ref(MyReferenceType<'a>), } +#[derive(Debug)] +pub enum MyFields<'a> { + Named(Vec>), + Unnamed(Vec>) +} + +impl<'a> MyFields<'a> { + pub fn from_ast(input: &'a Fields) -> Result { + match &input { + Fields::Named(named_fields) => { + let fields = named_fields + .named + .iter() + .filter_map(|field| field.ident.as_ref().map(|ident| (ident, &field.ty))) + .map(|(ident, ty)| { + MyFieldType::from(&ty).map(|ty| MyNamedField { name: &ident, ty }) + }) + .collect::>>>()?; + + Ok(MyFields::Named(fields)) + } + Fields::Unnamed(unnamed_fields) => { + let fields = unnamed_fields + .unnamed + .iter() + .map(|field| MyUnnamedField {ty: MyFieldType::from(&field.ty)}) + .collect::>>>()?; + + Ok(MyFields::Unnamed(fields)) + } + Fields::Unit => Err(Error::new( + input.span(), + "Unit structs are not supported for automatic conversion yet. \ + If you would like to see them supported, please reach out.", + )), + } + } +} + + #[derive(Debug)] pub struct MyGenerics<'a> { pub params: Vec, @@ -153,63 +191,78 @@ impl<'a> MyFieldType<'a> { } } -impl<'a> MyStruct<'a> { - pub fn from_ast(input: &'a DeriveInput) -> Result { - let struct_data = match &input.data { - Data::Struct(inner_struct) => Ok(inner_struct), - Data::Enum(_) => Err(Error::new( - input.span(), - "Enums are not supported \ - for automatic conversion to JavaScript representation", - )), - Data::Union(_) => Err(Error::new( - input.span(), - "Unions are not supported \ - for automatic conversion to JavaScript representation", - )), - }?; +#[derive(Debug)] +pub struct MyEnum<'a> { + variants: Vec> +} + +#[derive(Debug)] +pub struct MyVariant<'a> { + attrs: &'a Vec, + name: &'a Ident, + fields: MyFields<'a>, + discriminant: Option<&'a Expr> +} +#[derive(Debug)] +pub struct MyDeriveInput<'a> { + name: &'a Ident, + generics: MyGenerics<'a>, + payload: MyDerivePayload<'a> +} + +#[derive(Debug)] +pub enum MyDerivePayload<'a> { + Struct(MyStruct<'a>), + Enum(MyEnum<'a>) +} + +impl<'a> MyDeriveInput<'a> { + pub fn from_ast(input: &'a DeriveInput) -> Result { + let name = &input.ident; let generic_params = input.generics.params.clone().into_iter().collect(); let generics = MyGenerics { params: generic_params, where_clause: &input.generics.where_clause, }; - match &struct_data.fields { - Fields::Named(named_fields) => { - let fields = named_fields - .named - .iter() - .filter_map(|field| field.ident.as_ref().map(|ident| (ident, &field.ty))) - .map(|(ident, ty)| { - MyFieldType::from(&ty).map(|ty| MyField { name: &ident, ty }) - }) - .collect::>>>()?; - - Ok(MyStruct::Named { - name: &input.ident, - fields, + match &input.data { + Data::Struct(inner_struct) => { + let parsed_struct = MyStruct::from_ast(&inner_struct)?; + Ok(MyDeriveInput { + name, generics, + payload: MyDerivePayload::Struct(parsed_struct) }) - } - Fields::Unnamed(unnamed_fields) => { - let fields = unnamed_fields - .unnamed - .iter() - .map(|field| MyFieldType::from(&field.ty)) - .collect::>>>()?; - - Ok(MyStruct::Unnamed { - name: &input.ident, - fields, + }, + Data::Enum(inner_enum) => { + let parsed_enum = MyEnum::from_ast(&inner_enum)?; + Ok(MyDeriveInput { + name, generics, + payload: MyDerivePayload::Struct(parsed_struct) }) - } - Fields::Unit => Err(Error::new( + }, + Data::Union(_) => Err(Error::new( input.span(), - "Unit structs are not supported for automatic conversion yet. \ - If you would like to see them supported, please reach out.", + "Unions are not supported \ + for automatic conversion to JavaScript representation", )), + }?; + } +} + +impl<'a> MyEnum<'a> { + pub fn from_ast(struct_data: &'a DataEnum) -> Result { + Ok(MyEnum { + variants + }) + } +} + +impl<'a> MyStruct<'a> { + pub fn from_ast(struct_data: &'a DataStruct) -> Result { + match &struct_data.fields { } } } From 70065a2696f02cb3b09202969b0319be53e9c8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Wed, 12 May 2021 13:42:33 +0200 Subject: [PATCH 02/23] looks like enum conversion works --- nj-derive/src/ast/types.rs | 69 ++++-- nj-derive/src/generator/derive.rs | 205 +++++++++++++++--- nj-derive/src/lib.rs | 2 +- .../ui-tests/{fail_enum.rs => pass_enum.rs} | 9 +- 4 files changed, 224 insertions(+), 61 deletions(-) rename nj-derive/ui-tests/{fail_enum.rs => pass_enum.rs} (50%) diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 078698f0..4f1a5446 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -6,9 +6,12 @@ use syn::Error; use syn::Result; use syn::spanned::Spanned; use syn::DeriveInput; +use syn::Attribute; +use syn::Expr; use syn::Data; use syn::DataEnum; use syn::DataStruct; +use syn::Variant; use syn::Fields; use syn::GenericParam; use syn::WhereClause; @@ -110,8 +113,8 @@ impl MyTupleType<'_> { } #[derive(Debug)] -pub enum MyStruct<'a> { - fields: MyFields<'a> +pub struct MyStruct<'a> { + pub fields: MyFields<'a> } #[derive(Debug)] @@ -156,14 +159,17 @@ impl<'a> MyFields<'a> { let fields = unnamed_fields .unnamed .iter() - .map(|field| MyUnnamedField {ty: MyFieldType::from(&field.ty)}) - .collect::>>>()?; + .map(|field| MyFieldType::from(&field.ty)) + .collect::>>>()? + .into_iter() + .map(|ty| MyUnnamedField { ty }) + .collect::>>(); Ok(MyFields::Unnamed(fields)) } Fields::Unit => Err(Error::new( input.span(), - "Unit structs are not supported for automatic conversion yet. \ + "Unit structs/enum variants are not supported for automatic conversion yet. \ If you would like to see them supported, please reach out.", )), } @@ -178,7 +184,7 @@ pub struct MyGenerics<'a> { } impl<'a> MyFieldType<'a> { - pub fn from(ty: &'a Type) -> Result { + pub fn from(ty: &'a Type) -> Result { match ty { Type::Path(type_path) => Ok(MyFieldType::Path(MyTypePath::from(type_path)?)), Type::Reference(reference) => Ok(MyFieldType::Ref(MyReferenceType::from(reference)?)), @@ -193,22 +199,13 @@ impl<'a> MyFieldType<'a> { #[derive(Debug)] pub struct MyEnum<'a> { - variants: Vec> + pub variants: Vec> } #[derive(Debug)] pub struct MyVariant<'a> { - attrs: &'a Vec, - name: &'a Ident, - fields: MyFields<'a>, - discriminant: Option<&'a Expr> -} - -#[derive(Debug)] -pub struct MyDeriveInput<'a> { - name: &'a Ident, - generics: MyGenerics<'a>, - payload: MyDerivePayload<'a> + pub name: &'a Ident, + pub fields: MyFields<'a> } #[derive(Debug)] @@ -217,6 +214,13 @@ pub enum MyDerivePayload<'a> { Enum(MyEnum<'a>) } +#[derive(Debug)] +pub struct MyDeriveInput<'a> { + pub name: &'a Ident, + pub generics: MyGenerics<'a>, + pub payload: MyDerivePayload<'a> +} + impl<'a> MyDeriveInput<'a> { pub fn from_ast(input: &'a DeriveInput) -> Result { let name = &input.ident; @@ -240,7 +244,7 @@ impl<'a> MyDeriveInput<'a> { Ok(MyDeriveInput { name, generics, - payload: MyDerivePayload::Struct(parsed_struct) + payload: MyDerivePayload::Enum(parsed_enum) }) }, Data::Union(_) => Err(Error::new( @@ -248,21 +252,40 @@ impl<'a> MyDeriveInput<'a> { "Unions are not supported \ for automatic conversion to JavaScript representation", )), - }?; + } } } impl<'a> MyEnum<'a> { - pub fn from_ast(struct_data: &'a DataEnum) -> Result { + pub fn from_ast(enum_data: &'a DataEnum) -> Result { + let variants = enum_data.variants.iter() + .map(|v| MyVariant::from_ast(v)) + .collect::>>()?; + + Ok(MyEnum { variants }) } } +impl<'a> MyVariant<'a> { + pub fn from_ast(variant_data: &'a Variant) -> Result { + let fields = MyFields::from_ast(&variant_data.fields)?; + + Ok(MyVariant { + name: &variant_data.ident, + fields + }) + } +} + impl<'a> MyStruct<'a> { pub fn from_ast(struct_data: &'a DataStruct) -> Result { - match &struct_data.fields { - } + let fields = MyFields::from_ast(&struct_data.fields)?; + + Ok(MyStruct { + fields + }) } } diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index f7f22899..24144f83 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -12,17 +12,23 @@ use syn::punctuated::Punctuated; use inflector::Inflector; use crate::ast::MyStruct; -use crate::ast::MyField; +use crate::ast::MyEnum; +use crate::ast::MyFields; use crate::ast::MyFieldType; +use crate::ast::MyNamedField; +use crate::ast::MyUnnamedField; use crate::ast::MyGenerics; +use crate::ast::MyDeriveInput; +use crate::ast::MyDerivePayload; +use crate::ast::MyVariant; -pub fn generate_datatype(input_struct: DeriveInput) -> TokenStream { - match MyStruct::from_ast(&input_struct) { +pub fn generate_datatype(input_data: DeriveInput) -> TokenStream { + match MyDeriveInput::from_ast(&input_data) { Err(err) => err.to_compile_error(), - Ok(parsed_struct) => { - let try_into_js = generate_try_into_js(&parsed_struct); + Ok(parsed_data) => { + let try_into_js = generate_try_into_js(&parsed_data); quote! { - #input_struct + #input_data #try_into_js } @@ -30,18 +36,126 @@ pub fn generate_datatype(input_struct: DeriveInput) -> TokenStream { } } -fn generate_try_into_js(parsed_struct: &MyStruct) -> TokenStream { - match parsed_struct { - MyStruct::Named { - name, - fields, - generics, - } => { - let impl_signature = generate_impl_signature(name, generics); - let output_obj = format_ident!("output_obj"); - let js_env = format_ident!("js_env"); - let field_conversions = generate_named_field_conversions(&output_obj, &js_env, fields); +fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { + let impl_signature = generate_impl_signature(&parsed_data.name, &parsed_data.generics); + + match &parsed_data.payload { + MyDerivePayload::Struct(struct_data) => { + generate_struct_try_into_js(&impl_signature, &struct_data) + }, + MyDerivePayload::Enum(enum_data) => { + generate_enum_try_into_js(&parsed_data.name, &impl_signature, &enum_data) + } + } +} + +fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { + let output_obj = format_ident!("output_obj"); + let js_env = format_ident!("js_env"); + + let variant_conversions = enum_data.variants.iter() + .map(|v| generate_variant_conversion(enum_name, &js_env, &output_obj, v)) + .collect::>(); + + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + use node_bindgen::core::{ + TryIntoJs, + val::JsObject + }; + + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + + match self { + #(#variant_conversions),* + }; + + #output_obj.try_to_js(#js_env) + } + } + } +} + +fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &Ident, variant: &MyVariant) -> TokenStream { + let variant_name = variant.name; + let variant_name_camelcase = format!("{}", variant.name).to_camel_case(); + let fields_scope = quote! {}; + + match &variant.fields { + MyFields::Named(named_fields) => { + let variant_output_obj = format_ident!("variant_output_obj"); + let field_bindings = named_fields.iter() + .map(|field| field.name) + .collect::>(); + + let field_conversions = generate_named_field_conversions(&variant_output_obj, + &fields_scope, + &js_env, + &named_fields); + + quote! { + #enum_name::#variant_name { #(#field_bindings),* } => { + let mut #variant_output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + + #(#field_conversions)* + + #output_obj.set_property( + #variant_name_camelcase, + #variant_output_obj.try_to_js(#js_env)? + )?; + } + } + }, + MyFields::Unnamed(unnamed_fields) => { + let variant_output_arr = format_ident!("variant_output_arr"); + let fields_count = unnamed_fields.len(); + let field_bindings = (0..fields_count) + .into_iter() + .map(|field_idx| format_ident!("field_{}", field_idx)) + .collect::>(); + + let field_conversions = generate_bound_unnamed_field_conversions(&variant_output_arr, + &js_env, + &field_bindings); + + quote! { + #enum_name::#variant_name( #(#field_bindings),* ) => { + let #variant_output_arr = #js_env.create_array_with_len(#fields_count)?; + + #(#field_conversions)* + + #output_obj.set_property( + #variant_name_camelcase, + #variant_output_arr.try_to_js(#js_env)? + )?; + } + } + } + } +} + +fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { + let js_env = format_ident!("js_env"); + let fields_scope = quote! { + self. + }; + + + match &struct_data.fields { + MyFields::Named(named_fields) => { + let output_obj = format_ident!("output_obj"); + let field_conversions = + generate_named_field_conversions(&output_obj, + &fields_scope, + &js_env, + &named_fields); quote! { #impl_signature { @@ -63,18 +177,14 @@ fn generate_try_into_js(parsed_struct: &MyStruct) -> TokenStream { } } } - } - MyStruct::Unnamed { - name, - fields, - generics, - } => { - let impl_signature = generate_impl_signature(name, generics); - let fields_count = fields.len(); + }, + MyFields::Unnamed(unnamed_fields) => { + let fields_count = unnamed_fields.len(); let output_arr = format_ident!("output_arr"); - let js_env = format_ident!("js_env"); let field_conversions = - generate_unnamed_field_conversions(&output_arr, &js_env, fields); + generate_unnamed_field_conversions(&output_arr, + &js_env, + &unnamed_fields); quote! { #impl_signature { @@ -86,7 +196,7 @@ fn generate_try_into_js(parsed_struct: &MyStruct) -> TokenStream { TryIntoJs }; - let #output_arr = js_env.create_array_with_len(#fields_count)?; + let #output_arr = #js_env.create_array_with_len(#fields_count)?; #(#field_conversions)* @@ -140,19 +250,20 @@ fn generate_impl_signature<'a>(name: &'a Ident, generics: &'a MyGenerics<'a>) -> fn generate_named_field_conversions<'a>( output_obj: &Ident, + fields_scope: &TokenStream, js_env: &Ident, - fields: &'a [MyField<'a>], + fields: &'a [MyNamedField<'a>], ) -> Vec { fields .iter() - .map(|MyField { name, ty }| { + .map(|MyNamedField { name, ty }| { let field_name = format!("{}", name).to_camel_case(); // References needs to be cloned for try_to_js // to take their ownership. Values can be passed as is let field_access = match ty { - MyFieldType::Path(_) => quote! { self.#name }, - MyFieldType::Ref(_) => quote! {self.#name.clone()}, + MyFieldType::Path(_) => quote! { #fields_scope #name }, + MyFieldType::Ref(_) => quote! { #fields_scope #name.clone() }, }; quote! { @@ -167,12 +278,12 @@ fn generate_named_field_conversions<'a>( fn generate_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, - fields: &'a [MyFieldType<'a>], + fields: &'a [MyUnnamedField<'a>], ) -> Vec { fields .iter() .enumerate() - .map(|(field_idx, ty)| { + .map(|(field_idx, MyUnnamedField { ty })| { let index = Index { index: field_idx as u32, span: output_array.span(), @@ -180,7 +291,7 @@ fn generate_unnamed_field_conversions<'a>( let field_access = match ty { MyFieldType::Path(_) => quote! { self.#index }, - MyFieldType::Ref(_) => quote! {self.#index.clone()}, + MyFieldType::Ref(_) => quote! { self.#index.clone() }, }; quote! { @@ -192,3 +303,27 @@ fn generate_unnamed_field_conversions<'a>( }) .collect() } + +fn generate_bound_unnamed_field_conversions<'a>( + output_array: &Ident, + js_env: &Ident, + field_bindings: &'a [Ident] +) -> Vec { + field_bindings + .iter() + .enumerate() + .map(|(field_idx, field_ident)| { + let index = Index { + index: field_idx as u32, + span: output_array.span(), + }; + + quote! { + #js_env.set_element( + #output_array, + #field_ident.try_to_js(#js_env)?, + #index)?; + } + }) + .collect() +} \ No newline at end of file diff --git a/nj-derive/src/lib.rs b/nj-derive/src/lib.rs index 3864df01..8241a5c0 100644 --- a/nj-derive/src/lib.rs +++ b/nj-derive/src/lib.rs @@ -56,7 +56,7 @@ pub fn node_bindgen(args: TokenStream, item: TokenStream) -> TokenStream { }; // used for debugging, if error occurs println do not work so should uncomment express - // println!("{}", out_express); + println!("{}", out_express); //let out_express = quote::quote! {}; out_express.into() diff --git a/nj-derive/ui-tests/fail_enum.rs b/nj-derive/ui-tests/pass_enum.rs similarity index 50% rename from nj-derive/ui-tests/fail_enum.rs rename to nj-derive/ui-tests/pass_enum.rs index 23ea45a9..bf67edb9 100644 --- a/nj-derive/ui-tests/fail_enum.rs +++ b/nj-derive/ui-tests/pass_enum.rs @@ -2,6 +2,11 @@ use node_bindgen::derive::node_bindgen; #[node_bindgen] enum TestEnum { - Something, - Else + Something(usize), + Else { + val: String + } +} + +fn main() { } \ No newline at end of file From 8475d7f160ea2a29ed1ead1a56503a134ecc074c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Wed, 12 May 2021 14:03:26 +0200 Subject: [PATCH 03/23] unit variants work --- nj-derive/src/ast/types.rs | 9 +++---- nj-derive/src/generator/derive.rs | 42 ++++++++++++++++++++++++------- nj-derive/ui-tests/pass_enum.rs | 3 ++- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 4f1a5446..ae8f77b3 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -137,7 +137,8 @@ pub enum MyFieldType<'a> { #[derive(Debug)] pub enum MyFields<'a> { Named(Vec>), - Unnamed(Vec>) + Unnamed(Vec>), + Unit } impl<'a> MyFields<'a> { @@ -167,11 +168,7 @@ impl<'a> MyFields<'a> { Ok(MyFields::Unnamed(fields)) } - Fields::Unit => Err(Error::new( - input.span(), - "Unit structs/enum variants are not supported for automatic conversion yet. \ - If you would like to see them supported, please reach out.", - )), + Fields::Unit => Ok(MyFields::Unit) } } } diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index 24144f83..b2701f3f 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -51,11 +51,10 @@ fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { } fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { - let output_obj = format_ident!("output_obj"); let js_env = format_ident!("js_env"); let variant_conversions = enum_data.variants.iter() - .map(|v| generate_variant_conversion(enum_name, &js_env, &output_obj, v)) + .map(|v| generate_variant_conversion(enum_name, &js_env, v)) .collect::>(); quote! { @@ -69,23 +68,19 @@ fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, en val::JsObject }; - let mut #output_obj = JsObject::new(#js_env.clone(), - #js_env.create_object()?); - match self { #(#variant_conversions),* - }; - - #output_obj.try_to_js(#js_env) + } } } } } -fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &Ident, variant: &MyVariant) -> TokenStream { +fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVariant) -> TokenStream { let variant_name = variant.name; let variant_name_camelcase = format!("{}", variant.name).to_camel_case(); let fields_scope = quote! {}; + let output_obj = format_ident!("output_obj"); match &variant.fields { MyFields::Named(named_fields) => { @@ -101,6 +96,9 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I quote! { #enum_name::#variant_name { #(#field_bindings),* } => { + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + let mut #variant_output_obj = JsObject::new(#js_env.clone(), #js_env.create_object()?); @@ -110,6 +108,8 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I #variant_name_camelcase, #variant_output_obj.try_to_js(#js_env)? )?; + + #output_obj.try_to_js(#js_env) } } }, @@ -127,6 +127,9 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I quote! { #enum_name::#variant_name( #(#field_bindings),* ) => { + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + let #variant_output_arr = #js_env.create_array_with_len(#fields_count)?; #(#field_conversions)* @@ -135,6 +138,15 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I #variant_name_camelcase, #variant_output_arr.try_to_js(#js_env)? )?; + + #output_obj.try_to_js(#js_env) + } + } + }, + MyFields::Unit => { + quote! { + #enum_name::#variant_name => { + #js_env.create_string_utf8(#variant_name_camelcase) } } } @@ -205,6 +217,18 @@ fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStr } } } + MyFields::Unit => { + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + #js_env.get_null() + } + } + } + } } } diff --git a/nj-derive/ui-tests/pass_enum.rs b/nj-derive/ui-tests/pass_enum.rs index bf67edb9..9c412027 100644 --- a/nj-derive/ui-tests/pass_enum.rs +++ b/nj-derive/ui-tests/pass_enum.rs @@ -5,7 +5,8 @@ enum TestEnum { Something(usize), Else { val: String - } + }, + UnitVariant } fn main() { From 0b7c4c723d94be9f9e20e083d4342e75810f94cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:28:13 +0200 Subject: [PATCH 04/23] feature complete --- CHANGELOG.md | 6 + Cargo.lock | 6 +- Cargo.toml | 2 +- README.md | 49 +++++++- examples/Cargo.lock | 186 +++++++++++++++++++++++++++++- examples/json/src/lib.rs | 26 +++++ examples/json/test.js | 20 +++- nj-core/Cargo.toml | 2 +- nj-derive/Cargo.toml | 2 +- nj-derive/src/ast/types.rs | 139 +++++++++++----------- nj-derive/src/generator/derive.rs | 165 +++++++++++++------------- nj-derive/src/lib.rs | 4 +- nj-derive/ui-tests/pass_enum.rs | 6 + 13 files changed, 445 insertions(+), 168 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd944574..6d319299 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ ## Unreleased ### Improvements +## [4.5.0] - TBD +### Improvements +- Added support for automatic conversion of enums into the JS representation by decorating their definition with `#[node_bindgen]` +- Defined a `NjError::Native` Error payload, which allows errors to return structured data to JS +- `Result` converts the error value to JS using `TryIntoJs` for structured error payloads + ## [4.4.0] - TBD ### Improvements - Added support for automatic conversion of structs into the JS representation by decorating their definition with `#[node_bindgen]` diff --git a/Cargo.lock b/Cargo.lock index e1dcf425..999cdd25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -676,7 +676,7 @@ dependencies = [ [[package]] name = "nj-core" -version = "4.4.0" +version = "4.5.0" dependencies = [ "async-trait", "ctor", @@ -692,7 +692,7 @@ dependencies = [ [[package]] name = "nj-derive" -version = "3.3.0" +version = "3.4.0" dependencies = [ "Inflector", "fluvio-future", @@ -709,7 +709,7 @@ version = "3.0.0" [[package]] name = "node-bindgen" -version = "4.4.0" +version = "4.5.0" dependencies = [ "nj-build", "nj-core", diff --git a/Cargo.toml b/Cargo.toml index 4b2849f8..eab3376f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-bindgen" -version = "4.4.0" +version = "4.5.0" authors = ["Fluvio Contributors "] edition = "2018" description = "easy way to write nodejs module using rust" diff --git a/README.md b/README.md index 5b1f5440..fa7e1db3 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ fn my_json() -> MyJson { ```js let addon = require('./dist'); -assert.deepEqual(addon.my_json(), { +assert.deepStrictEqual(addon.my_json(), { someName: "John", aNumber: 1337 }); @@ -281,6 +281,53 @@ Note that the fields must implement Any references must also implement `Clone`. Field names will be converted to camelCase. +## Enums + +Enums will also have their JS representation autogenerated with the help of `node_bindgen`: + +```rust +#[node_bindgen] +enum ErrorType { + WithMessage(String, usize), + WithFields { + val: usize + }, + UnitErrorType +} + +#[node_bindgen] +fn with_message() -> ErrorType { + ErrorType::WithMessage("test".to_owned(), 321) +} + +#[node_bindgen] +fn with_fields() -> ErrorType { + ErrorType::WithFields { + val: 123 + } +} + +#[node_bindgen] +fn with_unit() -> ErrorType { + ErrorType::UnitErrorType +} +``` + +```js +assert.deepStrictEqual(addon.withMessage(), { + withMessage: ["test", 321n] +}); +assert.deepStrictEqual(addon.withFields(), { + withFields: { + val: 123n + } +}); +assert.deepStrictEqual(addon.withUnit(), "UnitErrorType") +``` + +Unnamed variants will be converted to lists, named to objects and unit variants to strings equal to their name in PascalCase. +Generics and references are supported, with the same caveats as for structs. + ## JavaScript class JavaScript class is supported. diff --git a/examples/Cargo.lock b/examples/Cargo.lock index ce99b117..86c019a5 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -109,6 +109,23 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-process" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f38756dd9ac84671c428afbf7c9f7495feff9ec5b0710f17100098e5b354ac" +dependencies = [ + "async-io", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "libc", + "once_cell", + "signal-hook", + "winapi", +] + [[package]] name = "async-std" version = "1.9.0" @@ -119,6 +136,7 @@ dependencies = [ "async-global-executor", "async-io", "async-lock", + "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -296,9 +314,9 @@ dependencies = [ [[package]] name = "fluvio-future" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b5b2317b98bf0fa3653cdadaca2acb5d0cfbb4712f4396545db39c01e4eed9" +checksum = "61587e440c936984e7dab40903de1c9adc39ab13e8446b52c50852da5cd6fbcb" dependencies = [ "async-io", "async-std", @@ -308,6 +326,7 @@ dependencies = [ "thiserror", "tracing", "tracing-subscriber", + "wasm-timer", ] [[package]] @@ -325,6 +344,21 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "futures" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.13" @@ -332,6 +366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -340,6 +375,17 @@ version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" +[[package]] +name = "futures-executor" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.13" @@ -361,6 +407,50 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-macro" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" + +[[package]] +name = "futures-task" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" + +[[package]] +name = "futures-util" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + [[package]] name = "getrandom" version = "0.2.2" @@ -482,6 +572,15 @@ version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -545,7 +644,7 @@ dependencies = [ [[package]] name = "nj-core" -version = "4.3.0" +version = "4.5.0" dependencies = [ "async-trait", "ctor", @@ -561,7 +660,7 @@ dependencies = [ [[package]] name = "nj-derive" -version = "3.2.0" +version = "3.4.0" dependencies = [ "Inflector", "proc-macro2", @@ -695,7 +794,7 @@ version = "3.0.0" [[package]] name = "node-bindgen" -version = "4.3.0" +version = "4.5.0" dependencies = [ "nj-build", "nj-core", @@ -788,6 +887,31 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "pin-project" version = "1.0.5" @@ -845,6 +969,18 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + [[package]] name = "proc-macro2" version = "1.0.24" @@ -964,6 +1100,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "security-framework" version = "2.1.2" @@ -1027,6 +1169,25 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signal-hook" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.2" @@ -1306,6 +1467,21 @@ version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.48" diff --git a/examples/json/src/lib.rs b/examples/json/src/lib.rs index 4850df59..c447b349 100644 --- a/examples/json/src/lib.rs +++ b/examples/json/src/lib.rs @@ -20,6 +20,15 @@ struct Outer { #[node_bindgen] struct Inner(String); +#[node_bindgen] +enum ErrorType { + WithMessage(String, usize), + WithFields { + val: usize + }, + UnitErrorType +} + struct CustomJson { val: f64 } @@ -56,4 +65,21 @@ fn multilevel_json() -> Outer { Outer { val: Inner("hello".to_owned()) } +} + +#[node_bindgen] +fn with_message() -> ErrorType { + ErrorType::WithMessage("test".to_owned(), 321) +} + +#[node_bindgen] +fn with_fields() -> ErrorType { + ErrorType::WithFields { + val: 123 + } +} + +#[node_bindgen] +fn with_unit() -> ErrorType { + ErrorType::UnitErrorType } \ No newline at end of file diff --git a/examples/json/test.js b/examples/json/test.js index d9e3bc68..bcad0599 100644 --- a/examples/json/test.js +++ b/examples/json/test.js @@ -2,13 +2,25 @@ const assert = require('assert'); let addon = require('./dist'); -assert.deepEqual(addon.customJson(), { +assert.deepStrictEqual(addon.customJson(), { customFieldName: 10 }, "verify custom json"); -assert.deepEqual(addon.standardJson(), { +assert.deepStrictEqual(addon.standardJson(), { someName: "John", aNumber: 1337 }, "verify standard json"); -assert.deepEqual(addon.multilevelJson(), { +assert.deepStrictEqual(addon.multilevelJson(), { val: ["hello"] -}, "verify multilevel json"); \ No newline at end of file +}, "verify multilevel json"); + +assert.deepStrictEqual(addon.withMessage(), { + withMessage: ["test", 321n] +}, "simple unnamed enum variant"); +assert.deepStrictEqual(addon.withFields(), { + withFields: { + val: 123n + } +}, "named enum variant"); +assert.deepStrictEqual(addon.withUnit(), + "UnitErrorType", + "unit enum variant") \ No newline at end of file diff --git a/nj-core/Cargo.toml b/nj-core/Cargo.toml index 7e6a68b4..fb819a86 100644 --- a/nj-core/Cargo.toml +++ b/nj-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nj-core" -version = "4.4.0" +version = "4.5.0" authors = ["fluvio.io"] edition = "2018" description = "high level wrapper for Node N-API" diff --git a/nj-derive/Cargo.toml b/nj-derive/Cargo.toml index e6439355..b4f7a333 100644 --- a/nj-derive/Cargo.toml +++ b/nj-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nj-derive" -version = "3.3.0" +version = "3.4.0" authors = ["fluvio.io"] edition = "2018" description = "procedure macro for node-bindgen" diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index ae8f77b3..898eab06 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -113,8 +113,58 @@ impl MyTupleType<'_> { } #[derive(Debug)] -pub struct MyStruct<'a> { - pub fields: MyFields<'a> +pub struct MyDeriveInput<'a> { + pub name: &'a Ident, + pub generics: MyGenerics<'a>, + pub payload: MyDerivePayload<'a> +} + +#[derive(Debug)] +pub enum MyDerivePayload<'a> { + Struct(MyStruct<'a>), + Enum(MyEnum<'a>) +} + +impl<'a> MyDeriveInput<'a> { + pub fn from_ast(input: &'a DeriveInput) -> Result { + let name = &input.ident; + let generic_params = input.generics.params.clone().into_iter().collect(); + let generics = MyGenerics { + params: generic_params, + where_clause: &input.generics.where_clause, + }; + + match &input.data { + Data::Struct(inner_struct) => { + let parsed_struct = MyStruct::from_ast(&inner_struct)?; + Ok(MyDeriveInput { + name, + generics, + payload: MyDerivePayload::Struct(parsed_struct) + }) + }, + Data::Enum(inner_enum) => { + let parsed_enum = MyEnum::from_ast(&inner_enum)?; + Ok(MyDeriveInput { + name, + generics, + payload: MyDerivePayload::Enum(parsed_enum) + }) + }, + Data::Union(_) => Err(Error::new( + input.span(), + "Unions are not supported \ + for automatic conversion to JavaScript representation", + )), + } + } +} + +#[derive(Debug)] +pub enum MyFields<'a> { + Named(Vec>), + Unnamed(Vec>), + Unit } #[derive(Debug)] @@ -134,13 +184,6 @@ pub enum MyFieldType<'a> { Ref(MyReferenceType<'a>), } -#[derive(Debug)] -pub enum MyFields<'a> { - Named(Vec>), - Unnamed(Vec>), - Unit -} - impl<'a> MyFields<'a> { pub fn from_ast(input: &'a Fields) -> Result { match &input { @@ -173,13 +216,6 @@ impl<'a> MyFields<'a> { } } - -#[derive(Debug)] -pub struct MyGenerics<'a> { - pub params: Vec, - pub where_clause: &'a Option, -} - impl<'a> MyFieldType<'a> { pub fn from(ty: &'a Type) -> Result { match ty { @@ -199,60 +235,6 @@ pub struct MyEnum<'a> { pub variants: Vec> } -#[derive(Debug)] -pub struct MyVariant<'a> { - pub name: &'a Ident, - pub fields: MyFields<'a> -} - -#[derive(Debug)] -pub enum MyDerivePayload<'a> { - Struct(MyStruct<'a>), - Enum(MyEnum<'a>) -} - -#[derive(Debug)] -pub struct MyDeriveInput<'a> { - pub name: &'a Ident, - pub generics: MyGenerics<'a>, - pub payload: MyDerivePayload<'a> -} - -impl<'a> MyDeriveInput<'a> { - pub fn from_ast(input: &'a DeriveInput) -> Result { - let name = &input.ident; - let generic_params = input.generics.params.clone().into_iter().collect(); - let generics = MyGenerics { - params: generic_params, - where_clause: &input.generics.where_clause, - }; - - match &input.data { - Data::Struct(inner_struct) => { - let parsed_struct = MyStruct::from_ast(&inner_struct)?; - Ok(MyDeriveInput { - name, - generics, - payload: MyDerivePayload::Struct(parsed_struct) - }) - }, - Data::Enum(inner_enum) => { - let parsed_enum = MyEnum::from_ast(&inner_enum)?; - Ok(MyDeriveInput { - name, - generics, - payload: MyDerivePayload::Enum(parsed_enum) - }) - }, - Data::Union(_) => Err(Error::new( - input.span(), - "Unions are not supported \ - for automatic conversion to JavaScript representation", - )), - } - } -} - impl<'a> MyEnum<'a> { pub fn from_ast(enum_data: &'a DataEnum) -> Result { let variants = enum_data.variants.iter() @@ -266,6 +248,12 @@ impl<'a> MyEnum<'a> { } } +#[derive(Debug)] +pub struct MyVariant<'a> { + pub name: &'a Ident, + pub fields: MyFields<'a> +} + impl<'a> MyVariant<'a> { pub fn from_ast(variant_data: &'a Variant) -> Result { let fields = MyFields::from_ast(&variant_data.fields)?; @@ -277,6 +265,11 @@ impl<'a> MyVariant<'a> { } } +#[derive(Debug)] +pub struct MyStruct<'a> { + pub fields: MyFields<'a> +} + impl<'a> MyStruct<'a> { pub fn from_ast(struct_data: &'a DataStruct) -> Result { let fields = MyFields::from_ast(&struct_data.fields)?; @@ -286,3 +279,9 @@ impl<'a> MyStruct<'a> { }) } } + +#[derive(Debug)] +pub struct MyGenerics<'a> { + pub params: Vec, + pub where_clause: &'a Option, +} diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index b2701f3f..16cac79c 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -50,6 +50,85 @@ fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { } } +fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { + let js_env = format_ident!("js_env"); + let fields_scope = quote! { + self. + }; + + + match &struct_data.fields { + MyFields::Named(named_fields) => { + let output_obj = format_ident!("output_obj"); + let field_conversions = + generate_named_field_conversions(&output_obj, + &fields_scope, + &js_env, + &named_fields); + + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + use node_bindgen::core::{ + TryIntoJs, + val::JsObject + }; + + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + + #(#field_conversions)* + + #output_obj.try_to_js(#js_env) + } + } + } + }, + MyFields::Unnamed(unnamed_fields) => { + let fields_count = unnamed_fields.len(); + let output_arr = format_ident!("output_arr"); + let field_conversions = + generate_unnamed_field_conversions(&output_arr, + &js_env, + &unnamed_fields); + + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + use node_bindgen::core::{ + TryIntoJs + }; + + let #output_arr = #js_env.create_array_with_len(#fields_count)?; + + #(#field_conversions)* + + Ok(#output_arr) + } + } + } + } + MyFields::Unit => { + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + #js_env.get_null() + } + } + } + } + } +} + fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { let js_env = format_ident!("js_env"); @@ -144,88 +223,11 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVa } }, MyFields::Unit => { - quote! { - #enum_name::#variant_name => { - #js_env.create_string_utf8(#variant_name_camelcase) - } - } - } - } -} - -fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { - let js_env = format_ident!("js_env"); - let fields_scope = quote! { - self. - }; - - - match &struct_data.fields { - MyFields::Named(named_fields) => { - let output_obj = format_ident!("output_obj"); - let field_conversions = - generate_named_field_conversions(&output_obj, - &fields_scope, - &js_env, - &named_fields); + let variant_name_pascalcase = format!("{}", variant.name).to_pascal_case(); quote! { - #impl_signature { - fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> - Result - { - use node_bindgen::core::{ - TryIntoJs, - val::JsObject - }; - - let mut #output_obj = JsObject::new(#js_env.clone(), - #js_env.create_object()?); - - #(#field_conversions)* - - #output_obj.try_to_js(#js_env) - } - } - } - }, - MyFields::Unnamed(unnamed_fields) => { - let fields_count = unnamed_fields.len(); - let output_arr = format_ident!("output_arr"); - let field_conversions = - generate_unnamed_field_conversions(&output_arr, - &js_env, - &unnamed_fields); - - quote! { - #impl_signature { - fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> - Result - { - use node_bindgen::core::{ - TryIntoJs - }; - - let #output_arr = #js_env.create_array_with_len(#fields_count)?; - - #(#field_conversions)* - - Ok(#output_arr) - } - } - } - } - MyFields::Unit => { - quote! { - #impl_signature { - fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> - Result - { - #js_env.get_null() - } + #enum_name::#variant_name => { + #js_env.create_string_utf8(#variant_name_pascalcase) } } } @@ -272,6 +274,7 @@ fn generate_impl_signature<'a>(name: &'a Ident, generics: &'a MyGenerics<'a>) -> } } +// Named fields, already bound to their field names fn generate_named_field_conversions<'a>( output_obj: &Ident, fields_scope: &TokenStream, @@ -299,6 +302,7 @@ fn generate_named_field_conversions<'a>( .collect() } +// Unnamed fields, stored in a tuple and accessed by index fn generate_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, @@ -328,6 +332,7 @@ fn generate_unnamed_field_conversions<'a>( .collect() } +// Unnamed fields, bound ahead of time to named variables fn generate_bound_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, diff --git a/nj-derive/src/lib.rs b/nj-derive/src/lib.rs index 8241a5c0..85a39c8a 100644 --- a/nj-derive/src/lib.rs +++ b/nj-derive/src/lib.rs @@ -56,8 +56,8 @@ pub fn node_bindgen(args: TokenStream, item: TokenStream) -> TokenStream { }; // used for debugging, if error occurs println do not work so should uncomment express - println!("{}", out_express); - //let out_express = quote::quote! {}; + // println!("{}", out_express); + // let out_express = quote::quote! {}; out_express.into() } diff --git a/nj-derive/ui-tests/pass_enum.rs b/nj-derive/ui-tests/pass_enum.rs index 9c412027..cd49b219 100644 --- a/nj-derive/ui-tests/pass_enum.rs +++ b/nj-derive/ui-tests/pass_enum.rs @@ -1,4 +1,5 @@ use node_bindgen::derive::node_bindgen; +use node_bindgen::core::TryIntoJs; #[node_bindgen] enum TestEnum { @@ -9,5 +10,10 @@ enum TestEnum { UnitVariant } +#[node_bindgen] +enum Generic { + Container(T) +} + fn main() { } \ No newline at end of file From 64c80e14978df518b11c47daa5fda9ce2682794a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:32:05 +0200 Subject: [PATCH 05/23] added the unit struct to the examples --- examples/json/src/lib.rs | 8 ++++++++ examples/json/test.js | 2 ++ 2 files changed, 10 insertions(+) diff --git a/examples/json/src/lib.rs b/examples/json/src/lib.rs index c447b349..d32fbcc5 100644 --- a/examples/json/src/lib.rs +++ b/examples/json/src/lib.rs @@ -20,6 +20,9 @@ struct Outer { #[node_bindgen] struct Inner(String); +#[node_bindgen] +struct UnitStruct; + #[node_bindgen] enum ErrorType { WithMessage(String, usize), @@ -67,6 +70,11 @@ fn multilevel_json() -> Outer { } } +#[node_bindgen] +fn unit_struct() -> UnitStruct { + UnitStruct +} + #[node_bindgen] fn with_message() -> ErrorType { ErrorType::WithMessage("test".to_owned(), 321) diff --git a/examples/json/test.js b/examples/json/test.js index bcad0599..09c99834 100644 --- a/examples/json/test.js +++ b/examples/json/test.js @@ -13,6 +13,8 @@ assert.deepStrictEqual(addon.multilevelJson(), { val: ["hello"] }, "verify multilevel json"); +assert.strictEqual(addon.unitStruct(), null); + assert.deepStrictEqual(addon.withMessage(), { withMessage: ["test", 321n] }, "simple unnamed enum variant"); From 3991935dae36ea00f832c19085b833a907051643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:38:56 +0200 Subject: [PATCH 06/23] formatter ran --- nj-derive/src/ast/types.rs | 39 ++++++++-------- nj-derive/src/generator/derive.rs | 77 ++++++++++++++++++------------- 2 files changed, 64 insertions(+), 52 deletions(-) diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 898eab06..fa1385c5 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -116,13 +116,13 @@ impl MyTupleType<'_> { pub struct MyDeriveInput<'a> { pub name: &'a Ident, pub generics: MyGenerics<'a>, - pub payload: MyDerivePayload<'a> + pub payload: MyDerivePayload<'a>, } #[derive(Debug)] pub enum MyDerivePayload<'a> { Struct(MyStruct<'a>), - Enum(MyEnum<'a>) + Enum(MyEnum<'a>), } impl<'a> MyDeriveInput<'a> { @@ -140,17 +140,17 @@ impl<'a> MyDeriveInput<'a> { Ok(MyDeriveInput { name, generics, - payload: MyDerivePayload::Struct(parsed_struct) + payload: MyDerivePayload::Struct(parsed_struct), }) - }, + } Data::Enum(inner_enum) => { let parsed_enum = MyEnum::from_ast(&inner_enum)?; Ok(MyDeriveInput { name, generics, - payload: MyDerivePayload::Enum(parsed_enum) + payload: MyDerivePayload::Enum(parsed_enum), }) - }, + } Data::Union(_) => Err(Error::new( input.span(), "Unions are not supported \ @@ -164,7 +164,7 @@ impl<'a> MyDeriveInput<'a> { pub enum MyFields<'a> { Named(Vec>), Unnamed(Vec>), - Unit + Unit, } #[derive(Debug)] @@ -175,7 +175,7 @@ pub struct MyNamedField<'a> { #[derive(Debug)] pub struct MyUnnamedField<'a> { - pub ty: MyFieldType<'a> + pub ty: MyFieldType<'a>, } #[derive(Debug)] @@ -211,7 +211,7 @@ impl<'a> MyFields<'a> { Ok(MyFields::Unnamed(fields)) } - Fields::Unit => Ok(MyFields::Unit) + Fields::Unit => Ok(MyFields::Unit), } } } @@ -232,26 +232,25 @@ impl<'a> MyFieldType<'a> { #[derive(Debug)] pub struct MyEnum<'a> { - pub variants: Vec> + pub variants: Vec>, } impl<'a> MyEnum<'a> { pub fn from_ast(enum_data: &'a DataEnum) -> Result { - let variants = enum_data.variants.iter() + let variants = enum_data + .variants + .iter() .map(|v| MyVariant::from_ast(v)) .collect::>>()?; - - Ok(MyEnum { - variants - }) + Ok(MyEnum { variants }) } } #[derive(Debug)] pub struct MyVariant<'a> { pub name: &'a Ident, - pub fields: MyFields<'a> + pub fields: MyFields<'a>, } impl<'a> MyVariant<'a> { @@ -260,23 +259,21 @@ impl<'a> MyVariant<'a> { Ok(MyVariant { name: &variant_data.ident, - fields + fields, }) } } #[derive(Debug)] pub struct MyStruct<'a> { - pub fields: MyFields<'a> + pub fields: MyFields<'a>, } impl<'a> MyStruct<'a> { pub fn from_ast(struct_data: &'a DataStruct) -> Result { let fields = MyFields::from_ast(&struct_data.fields)?; - Ok(MyStruct { - fields - }) + Ok(MyStruct { fields }) } } diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index 16cac79c..1805e8de 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -36,35 +36,37 @@ pub fn generate_datatype(input_data: DeriveInput) -> TokenStream { } } - fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { let impl_signature = generate_impl_signature(&parsed_data.name, &parsed_data.generics); match &parsed_data.payload { MyDerivePayload::Struct(struct_data) => { generate_struct_try_into_js(&impl_signature, &struct_data) - }, + } MyDerivePayload::Enum(enum_data) => { generate_enum_try_into_js(&parsed_data.name, &impl_signature, &enum_data) } } } -fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { +fn generate_struct_try_into_js( + impl_signature: &TokenStream, + struct_data: &MyStruct, +) -> TokenStream { let js_env = format_ident!("js_env"); let fields_scope = quote! { self. }; - match &struct_data.fields { MyFields::Named(named_fields) => { let output_obj = format_ident!("output_obj"); - let field_conversions = - generate_named_field_conversions(&output_obj, - &fields_scope, - &js_env, - &named_fields); + let field_conversions = generate_named_field_conversions( + &output_obj, + &fields_scope, + &js_env, + &named_fields, + ); quote! { #impl_signature { @@ -86,14 +88,12 @@ fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStr } } } - }, + } MyFields::Unnamed(unnamed_fields) => { let fields_count = unnamed_fields.len(); let output_arr = format_ident!("output_arr"); let field_conversions = - generate_unnamed_field_conversions(&output_arr, - &js_env, - &unnamed_fields); + generate_unnamed_field_conversions(&output_arr, &js_env, &unnamed_fields); quote! { #impl_signature { @@ -129,10 +129,16 @@ fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStr } } -fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { +fn generate_enum_try_into_js( + enum_name: &Ident, + impl_signature: &TokenStream, + enum_data: &MyEnum, +) -> TokenStream { let js_env = format_ident!("js_env"); - let variant_conversions = enum_data.variants.iter() + let variant_conversions = enum_data + .variants + .iter() .map(|v| generate_variant_conversion(enum_name, &js_env, v)) .collect::>(); @@ -155,23 +161,30 @@ fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, en } } -fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVariant) -> TokenStream { - let variant_name = variant.name; +fn generate_variant_conversion( + enum_name: &Ident, + js_env: &Ident, + variant: &MyVariant, +) -> TokenStream { + let variant_name = variant.name; let variant_name_camelcase = format!("{}", variant.name).to_camel_case(); - let fields_scope = quote! {}; + let fields_scope = quote! {}; let output_obj = format_ident!("output_obj"); match &variant.fields { MyFields::Named(named_fields) => { let variant_output_obj = format_ident!("variant_output_obj"); - let field_bindings = named_fields.iter() + let field_bindings = named_fields + .iter() .map(|field| field.name) .collect::>(); - let field_conversions = generate_named_field_conversions(&variant_output_obj, - &fields_scope, - &js_env, - &named_fields); + let field_conversions = generate_named_field_conversions( + &variant_output_obj, + &fields_scope, + &js_env, + &named_fields, + ); quote! { #enum_name::#variant_name { #(#field_bindings),* } => { @@ -191,18 +204,20 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVa #output_obj.try_to_js(#js_env) } } - }, + } MyFields::Unnamed(unnamed_fields) => { let variant_output_arr = format_ident!("variant_output_arr"); - let fields_count = unnamed_fields.len(); + let fields_count = unnamed_fields.len(); let field_bindings = (0..fields_count) .into_iter() .map(|field_idx| format_ident!("field_{}", field_idx)) .collect::>(); - let field_conversions = generate_bound_unnamed_field_conversions(&variant_output_arr, - &js_env, - &field_bindings); + let field_conversions = generate_bound_unnamed_field_conversions( + &variant_output_arr, + &js_env, + &field_bindings, + ); quote! { #enum_name::#variant_name( #(#field_bindings),* ) => { @@ -221,7 +236,7 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVa #output_obj.try_to_js(#js_env) } } - }, + } MyFields::Unit => { let variant_name_pascalcase = format!("{}", variant.name).to_pascal_case(); @@ -336,7 +351,7 @@ fn generate_unnamed_field_conversions<'a>( fn generate_bound_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, - field_bindings: &'a [Ident] + field_bindings: &'a [Ident], ) -> Vec { field_bindings .iter() @@ -355,4 +370,4 @@ fn generate_bound_unnamed_field_conversions<'a>( } }) .collect() -} \ No newline at end of file +} From 783057cf3a1ba886bc6cdd8018057aeb260ce9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:43:50 +0200 Subject: [PATCH 07/23] clippy is happier --- Cargo.lock | 2 -- nj-derive/src/ast/types.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 999cdd25..73d95fc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "Inflector" version = "0.11.4" diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index fa1385c5..287671c9 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -6,8 +6,6 @@ use syn::Error; use syn::Result; use syn::spanned::Spanned; use syn::DeriveInput; -use syn::Attribute; -use syn::Expr; use syn::Data; use syn::DataEnum; use syn::DataStruct; From 2cf92545cf228f47ee1b2566c427a72f999cfb26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:47:30 +0200 Subject: [PATCH 08/23] further clippy --- nj-core/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nj-core/src/error.rs b/nj-core/src/error.rs index 585731bd..d4ea3ac9 100644 --- a/nj-core/src/error.rs +++ b/nj-core/src/error.rs @@ -35,7 +35,7 @@ impl NjError { pub fn as_js(&self, js_env: &JsEnv) -> napi_value { match self { NjError::Native(err) => *err, - other => { + _ => { let msg = self.to_string(); js_env.create_error(&msg).expect("error cannot be created") } From 07f14ff41ff16ca78c636951d5a4e6d10bf57fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 11 May 2021 13:37:46 +0200 Subject: [PATCH 09/23] initial modifications --- nj-core/src/convert.rs | 4 +- nj-core/src/error.rs | 11 ++- nj-derive/src/ast/types.rs | 163 ++++++++++++++++++++++++------------- 3 files changed, 119 insertions(+), 59 deletions(-) diff --git a/nj-core/src/convert.rs b/nj-core/src/convert.rs index 25f3b0e5..0fca0413 100644 --- a/nj-core/src/convert.rs +++ b/nj-core/src/convert.rs @@ -62,12 +62,12 @@ impl TryIntoJs for () { impl TryIntoJs for Result where T: TryIntoJs, - E: ToString, + E: TryIntoJs, { fn try_to_js(self, js_env: &JsEnv) -> Result { match self { Ok(val) => val.try_to_js(&js_env), - Err(err) => Err(NjError::Other(err.to_string())), + Err(err) => Err(NjError::Native(err.try_to_js(&js_env)?)), } } } diff --git a/nj-core/src/error.rs b/nj-core/src/error.rs index 780a0b37..585731bd 100644 --- a/nj-core/src/error.rs +++ b/nj-core/src/error.rs @@ -17,6 +17,7 @@ pub enum NjError { NoPlainConstructor, Utf8Error(FromUtf8Error), Utf8ErrorSlice(Utf8Error), + Native(napi_value), Other(String), } @@ -32,8 +33,13 @@ impl IntoJs for NjError { impl NjError { /// convert to napi value pub fn as_js(&self, js_env: &JsEnv) -> napi_value { - let msg = self.to_string(); - js_env.create_error(&msg).expect("error cannot be created") + match self { + NjError::Native(err) => *err, + other => { + let msg = self.to_string(); + js_env.create_error(&msg).expect("error cannot be created") + } + } } } @@ -84,6 +90,7 @@ impl fmt::Display for NjError { expected_count, actual_count ), Self::NoPlainConstructor => write!(f, "Plain constructor not supported yet"), + Self::Native(_val) => write!(f, "Native error payload"), Self::Other(msg) => write!(f, "{}", msg), } } diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 86d4e0fc..078698f0 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -7,6 +7,8 @@ use syn::Result; use syn::spanned::Spanned; use syn::DeriveInput; use syn::Data; +use syn::DataEnum; +use syn::DataStruct; use syn::Fields; use syn::GenericParam; use syn::WhereClause; @@ -109,30 +111,66 @@ impl MyTupleType<'_> { #[derive(Debug)] pub enum MyStruct<'a> { - Named { - name: &'a Ident, - fields: Vec>, - generics: MyGenerics<'a>, - }, - Unnamed { - name: &'a Ident, - fields: Vec>, - generics: MyGenerics<'a>, - }, + fields: MyFields<'a> } #[derive(Debug)] -pub struct MyField<'a> { +pub struct MyNamedField<'a> { pub name: &'a Ident, pub ty: MyFieldType<'a>, } +#[derive(Debug)] +pub struct MyUnnamedField<'a> { + pub ty: MyFieldType<'a> +} + #[derive(Debug)] pub enum MyFieldType<'a> { Path(MyTypePath<'a>), Ref(MyReferenceType<'a>), } +#[derive(Debug)] +pub enum MyFields<'a> { + Named(Vec>), + Unnamed(Vec>) +} + +impl<'a> MyFields<'a> { + pub fn from_ast(input: &'a Fields) -> Result { + match &input { + Fields::Named(named_fields) => { + let fields = named_fields + .named + .iter() + .filter_map(|field| field.ident.as_ref().map(|ident| (ident, &field.ty))) + .map(|(ident, ty)| { + MyFieldType::from(&ty).map(|ty| MyNamedField { name: &ident, ty }) + }) + .collect::>>>()?; + + Ok(MyFields::Named(fields)) + } + Fields::Unnamed(unnamed_fields) => { + let fields = unnamed_fields + .unnamed + .iter() + .map(|field| MyUnnamedField {ty: MyFieldType::from(&field.ty)}) + .collect::>>>()?; + + Ok(MyFields::Unnamed(fields)) + } + Fields::Unit => Err(Error::new( + input.span(), + "Unit structs are not supported for automatic conversion yet. \ + If you would like to see them supported, please reach out.", + )), + } + } +} + + #[derive(Debug)] pub struct MyGenerics<'a> { pub params: Vec, @@ -153,63 +191,78 @@ impl<'a> MyFieldType<'a> { } } -impl<'a> MyStruct<'a> { - pub fn from_ast(input: &'a DeriveInput) -> Result { - let struct_data = match &input.data { - Data::Struct(inner_struct) => Ok(inner_struct), - Data::Enum(_) => Err(Error::new( - input.span(), - "Enums are not supported \ - for automatic conversion to JavaScript representation", - )), - Data::Union(_) => Err(Error::new( - input.span(), - "Unions are not supported \ - for automatic conversion to JavaScript representation", - )), - }?; +#[derive(Debug)] +pub struct MyEnum<'a> { + variants: Vec> +} + +#[derive(Debug)] +pub struct MyVariant<'a> { + attrs: &'a Vec, + name: &'a Ident, + fields: MyFields<'a>, + discriminant: Option<&'a Expr> +} +#[derive(Debug)] +pub struct MyDeriveInput<'a> { + name: &'a Ident, + generics: MyGenerics<'a>, + payload: MyDerivePayload<'a> +} + +#[derive(Debug)] +pub enum MyDerivePayload<'a> { + Struct(MyStruct<'a>), + Enum(MyEnum<'a>) +} + +impl<'a> MyDeriveInput<'a> { + pub fn from_ast(input: &'a DeriveInput) -> Result { + let name = &input.ident; let generic_params = input.generics.params.clone().into_iter().collect(); let generics = MyGenerics { params: generic_params, where_clause: &input.generics.where_clause, }; - match &struct_data.fields { - Fields::Named(named_fields) => { - let fields = named_fields - .named - .iter() - .filter_map(|field| field.ident.as_ref().map(|ident| (ident, &field.ty))) - .map(|(ident, ty)| { - MyFieldType::from(&ty).map(|ty| MyField { name: &ident, ty }) - }) - .collect::>>>()?; - - Ok(MyStruct::Named { - name: &input.ident, - fields, + match &input.data { + Data::Struct(inner_struct) => { + let parsed_struct = MyStruct::from_ast(&inner_struct)?; + Ok(MyDeriveInput { + name, generics, + payload: MyDerivePayload::Struct(parsed_struct) }) - } - Fields::Unnamed(unnamed_fields) => { - let fields = unnamed_fields - .unnamed - .iter() - .map(|field| MyFieldType::from(&field.ty)) - .collect::>>>()?; - - Ok(MyStruct::Unnamed { - name: &input.ident, - fields, + }, + Data::Enum(inner_enum) => { + let parsed_enum = MyEnum::from_ast(&inner_enum)?; + Ok(MyDeriveInput { + name, generics, + payload: MyDerivePayload::Struct(parsed_struct) }) - } - Fields::Unit => Err(Error::new( + }, + Data::Union(_) => Err(Error::new( input.span(), - "Unit structs are not supported for automatic conversion yet. \ - If you would like to see them supported, please reach out.", + "Unions are not supported \ + for automatic conversion to JavaScript representation", )), + }?; + } +} + +impl<'a> MyEnum<'a> { + pub fn from_ast(struct_data: &'a DataEnum) -> Result { + Ok(MyEnum { + variants + }) + } +} + +impl<'a> MyStruct<'a> { + pub fn from_ast(struct_data: &'a DataStruct) -> Result { + match &struct_data.fields { } } } From 3a6fb458cf12c425ecf37977df353d089e7d4e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Wed, 12 May 2021 13:42:33 +0200 Subject: [PATCH 10/23] looks like enum conversion works --- nj-derive/src/ast/types.rs | 69 ++++-- nj-derive/src/generator/derive.rs | 205 +++++++++++++++--- nj-derive/src/lib.rs | 2 +- .../ui-tests/{fail_enum.rs => pass_enum.rs} | 9 +- 4 files changed, 224 insertions(+), 61 deletions(-) rename nj-derive/ui-tests/{fail_enum.rs => pass_enum.rs} (50%) diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 078698f0..4f1a5446 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -6,9 +6,12 @@ use syn::Error; use syn::Result; use syn::spanned::Spanned; use syn::DeriveInput; +use syn::Attribute; +use syn::Expr; use syn::Data; use syn::DataEnum; use syn::DataStruct; +use syn::Variant; use syn::Fields; use syn::GenericParam; use syn::WhereClause; @@ -110,8 +113,8 @@ impl MyTupleType<'_> { } #[derive(Debug)] -pub enum MyStruct<'a> { - fields: MyFields<'a> +pub struct MyStruct<'a> { + pub fields: MyFields<'a> } #[derive(Debug)] @@ -156,14 +159,17 @@ impl<'a> MyFields<'a> { let fields = unnamed_fields .unnamed .iter() - .map(|field| MyUnnamedField {ty: MyFieldType::from(&field.ty)}) - .collect::>>>()?; + .map(|field| MyFieldType::from(&field.ty)) + .collect::>>>()? + .into_iter() + .map(|ty| MyUnnamedField { ty }) + .collect::>>(); Ok(MyFields::Unnamed(fields)) } Fields::Unit => Err(Error::new( input.span(), - "Unit structs are not supported for automatic conversion yet. \ + "Unit structs/enum variants are not supported for automatic conversion yet. \ If you would like to see them supported, please reach out.", )), } @@ -178,7 +184,7 @@ pub struct MyGenerics<'a> { } impl<'a> MyFieldType<'a> { - pub fn from(ty: &'a Type) -> Result { + pub fn from(ty: &'a Type) -> Result { match ty { Type::Path(type_path) => Ok(MyFieldType::Path(MyTypePath::from(type_path)?)), Type::Reference(reference) => Ok(MyFieldType::Ref(MyReferenceType::from(reference)?)), @@ -193,22 +199,13 @@ impl<'a> MyFieldType<'a> { #[derive(Debug)] pub struct MyEnum<'a> { - variants: Vec> + pub variants: Vec> } #[derive(Debug)] pub struct MyVariant<'a> { - attrs: &'a Vec, - name: &'a Ident, - fields: MyFields<'a>, - discriminant: Option<&'a Expr> -} - -#[derive(Debug)] -pub struct MyDeriveInput<'a> { - name: &'a Ident, - generics: MyGenerics<'a>, - payload: MyDerivePayload<'a> + pub name: &'a Ident, + pub fields: MyFields<'a> } #[derive(Debug)] @@ -217,6 +214,13 @@ pub enum MyDerivePayload<'a> { Enum(MyEnum<'a>) } +#[derive(Debug)] +pub struct MyDeriveInput<'a> { + pub name: &'a Ident, + pub generics: MyGenerics<'a>, + pub payload: MyDerivePayload<'a> +} + impl<'a> MyDeriveInput<'a> { pub fn from_ast(input: &'a DeriveInput) -> Result { let name = &input.ident; @@ -240,7 +244,7 @@ impl<'a> MyDeriveInput<'a> { Ok(MyDeriveInput { name, generics, - payload: MyDerivePayload::Struct(parsed_struct) + payload: MyDerivePayload::Enum(parsed_enum) }) }, Data::Union(_) => Err(Error::new( @@ -248,21 +252,40 @@ impl<'a> MyDeriveInput<'a> { "Unions are not supported \ for automatic conversion to JavaScript representation", )), - }?; + } } } impl<'a> MyEnum<'a> { - pub fn from_ast(struct_data: &'a DataEnum) -> Result { + pub fn from_ast(enum_data: &'a DataEnum) -> Result { + let variants = enum_data.variants.iter() + .map(|v| MyVariant::from_ast(v)) + .collect::>>()?; + + Ok(MyEnum { variants }) } } +impl<'a> MyVariant<'a> { + pub fn from_ast(variant_data: &'a Variant) -> Result { + let fields = MyFields::from_ast(&variant_data.fields)?; + + Ok(MyVariant { + name: &variant_data.ident, + fields + }) + } +} + impl<'a> MyStruct<'a> { pub fn from_ast(struct_data: &'a DataStruct) -> Result { - match &struct_data.fields { - } + let fields = MyFields::from_ast(&struct_data.fields)?; + + Ok(MyStruct { + fields + }) } } diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index f7f22899..24144f83 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -12,17 +12,23 @@ use syn::punctuated::Punctuated; use inflector::Inflector; use crate::ast::MyStruct; -use crate::ast::MyField; +use crate::ast::MyEnum; +use crate::ast::MyFields; use crate::ast::MyFieldType; +use crate::ast::MyNamedField; +use crate::ast::MyUnnamedField; use crate::ast::MyGenerics; +use crate::ast::MyDeriveInput; +use crate::ast::MyDerivePayload; +use crate::ast::MyVariant; -pub fn generate_datatype(input_struct: DeriveInput) -> TokenStream { - match MyStruct::from_ast(&input_struct) { +pub fn generate_datatype(input_data: DeriveInput) -> TokenStream { + match MyDeriveInput::from_ast(&input_data) { Err(err) => err.to_compile_error(), - Ok(parsed_struct) => { - let try_into_js = generate_try_into_js(&parsed_struct); + Ok(parsed_data) => { + let try_into_js = generate_try_into_js(&parsed_data); quote! { - #input_struct + #input_data #try_into_js } @@ -30,18 +36,126 @@ pub fn generate_datatype(input_struct: DeriveInput) -> TokenStream { } } -fn generate_try_into_js(parsed_struct: &MyStruct) -> TokenStream { - match parsed_struct { - MyStruct::Named { - name, - fields, - generics, - } => { - let impl_signature = generate_impl_signature(name, generics); - let output_obj = format_ident!("output_obj"); - let js_env = format_ident!("js_env"); - let field_conversions = generate_named_field_conversions(&output_obj, &js_env, fields); +fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { + let impl_signature = generate_impl_signature(&parsed_data.name, &parsed_data.generics); + + match &parsed_data.payload { + MyDerivePayload::Struct(struct_data) => { + generate_struct_try_into_js(&impl_signature, &struct_data) + }, + MyDerivePayload::Enum(enum_data) => { + generate_enum_try_into_js(&parsed_data.name, &impl_signature, &enum_data) + } + } +} + +fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { + let output_obj = format_ident!("output_obj"); + let js_env = format_ident!("js_env"); + + let variant_conversions = enum_data.variants.iter() + .map(|v| generate_variant_conversion(enum_name, &js_env, &output_obj, v)) + .collect::>(); + + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + use node_bindgen::core::{ + TryIntoJs, + val::JsObject + }; + + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + + match self { + #(#variant_conversions),* + }; + + #output_obj.try_to_js(#js_env) + } + } + } +} + +fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &Ident, variant: &MyVariant) -> TokenStream { + let variant_name = variant.name; + let variant_name_camelcase = format!("{}", variant.name).to_camel_case(); + let fields_scope = quote! {}; + + match &variant.fields { + MyFields::Named(named_fields) => { + let variant_output_obj = format_ident!("variant_output_obj"); + let field_bindings = named_fields.iter() + .map(|field| field.name) + .collect::>(); + + let field_conversions = generate_named_field_conversions(&variant_output_obj, + &fields_scope, + &js_env, + &named_fields); + + quote! { + #enum_name::#variant_name { #(#field_bindings),* } => { + let mut #variant_output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + + #(#field_conversions)* + + #output_obj.set_property( + #variant_name_camelcase, + #variant_output_obj.try_to_js(#js_env)? + )?; + } + } + }, + MyFields::Unnamed(unnamed_fields) => { + let variant_output_arr = format_ident!("variant_output_arr"); + let fields_count = unnamed_fields.len(); + let field_bindings = (0..fields_count) + .into_iter() + .map(|field_idx| format_ident!("field_{}", field_idx)) + .collect::>(); + + let field_conversions = generate_bound_unnamed_field_conversions(&variant_output_arr, + &js_env, + &field_bindings); + + quote! { + #enum_name::#variant_name( #(#field_bindings),* ) => { + let #variant_output_arr = #js_env.create_array_with_len(#fields_count)?; + + #(#field_conversions)* + + #output_obj.set_property( + #variant_name_camelcase, + #variant_output_arr.try_to_js(#js_env)? + )?; + } + } + } + } +} + +fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { + let js_env = format_ident!("js_env"); + let fields_scope = quote! { + self. + }; + + + match &struct_data.fields { + MyFields::Named(named_fields) => { + let output_obj = format_ident!("output_obj"); + let field_conversions = + generate_named_field_conversions(&output_obj, + &fields_scope, + &js_env, + &named_fields); quote! { #impl_signature { @@ -63,18 +177,14 @@ fn generate_try_into_js(parsed_struct: &MyStruct) -> TokenStream { } } } - } - MyStruct::Unnamed { - name, - fields, - generics, - } => { - let impl_signature = generate_impl_signature(name, generics); - let fields_count = fields.len(); + }, + MyFields::Unnamed(unnamed_fields) => { + let fields_count = unnamed_fields.len(); let output_arr = format_ident!("output_arr"); - let js_env = format_ident!("js_env"); let field_conversions = - generate_unnamed_field_conversions(&output_arr, &js_env, fields); + generate_unnamed_field_conversions(&output_arr, + &js_env, + &unnamed_fields); quote! { #impl_signature { @@ -86,7 +196,7 @@ fn generate_try_into_js(parsed_struct: &MyStruct) -> TokenStream { TryIntoJs }; - let #output_arr = js_env.create_array_with_len(#fields_count)?; + let #output_arr = #js_env.create_array_with_len(#fields_count)?; #(#field_conversions)* @@ -140,19 +250,20 @@ fn generate_impl_signature<'a>(name: &'a Ident, generics: &'a MyGenerics<'a>) -> fn generate_named_field_conversions<'a>( output_obj: &Ident, + fields_scope: &TokenStream, js_env: &Ident, - fields: &'a [MyField<'a>], + fields: &'a [MyNamedField<'a>], ) -> Vec { fields .iter() - .map(|MyField { name, ty }| { + .map(|MyNamedField { name, ty }| { let field_name = format!("{}", name).to_camel_case(); // References needs to be cloned for try_to_js // to take their ownership. Values can be passed as is let field_access = match ty { - MyFieldType::Path(_) => quote! { self.#name }, - MyFieldType::Ref(_) => quote! {self.#name.clone()}, + MyFieldType::Path(_) => quote! { #fields_scope #name }, + MyFieldType::Ref(_) => quote! { #fields_scope #name.clone() }, }; quote! { @@ -167,12 +278,12 @@ fn generate_named_field_conversions<'a>( fn generate_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, - fields: &'a [MyFieldType<'a>], + fields: &'a [MyUnnamedField<'a>], ) -> Vec { fields .iter() .enumerate() - .map(|(field_idx, ty)| { + .map(|(field_idx, MyUnnamedField { ty })| { let index = Index { index: field_idx as u32, span: output_array.span(), @@ -180,7 +291,7 @@ fn generate_unnamed_field_conversions<'a>( let field_access = match ty { MyFieldType::Path(_) => quote! { self.#index }, - MyFieldType::Ref(_) => quote! {self.#index.clone()}, + MyFieldType::Ref(_) => quote! { self.#index.clone() }, }; quote! { @@ -192,3 +303,27 @@ fn generate_unnamed_field_conversions<'a>( }) .collect() } + +fn generate_bound_unnamed_field_conversions<'a>( + output_array: &Ident, + js_env: &Ident, + field_bindings: &'a [Ident] +) -> Vec { + field_bindings + .iter() + .enumerate() + .map(|(field_idx, field_ident)| { + let index = Index { + index: field_idx as u32, + span: output_array.span(), + }; + + quote! { + #js_env.set_element( + #output_array, + #field_ident.try_to_js(#js_env)?, + #index)?; + } + }) + .collect() +} \ No newline at end of file diff --git a/nj-derive/src/lib.rs b/nj-derive/src/lib.rs index 3864df01..8241a5c0 100644 --- a/nj-derive/src/lib.rs +++ b/nj-derive/src/lib.rs @@ -56,7 +56,7 @@ pub fn node_bindgen(args: TokenStream, item: TokenStream) -> TokenStream { }; // used for debugging, if error occurs println do not work so should uncomment express - // println!("{}", out_express); + println!("{}", out_express); //let out_express = quote::quote! {}; out_express.into() diff --git a/nj-derive/ui-tests/fail_enum.rs b/nj-derive/ui-tests/pass_enum.rs similarity index 50% rename from nj-derive/ui-tests/fail_enum.rs rename to nj-derive/ui-tests/pass_enum.rs index 23ea45a9..bf67edb9 100644 --- a/nj-derive/ui-tests/fail_enum.rs +++ b/nj-derive/ui-tests/pass_enum.rs @@ -2,6 +2,11 @@ use node_bindgen::derive::node_bindgen; #[node_bindgen] enum TestEnum { - Something, - Else + Something(usize), + Else { + val: String + } +} + +fn main() { } \ No newline at end of file From 175262477e54baf71159e0c29ad8782807aeee11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Wed, 12 May 2021 14:03:26 +0200 Subject: [PATCH 11/23] unit variants work --- nj-derive/src/ast/types.rs | 9 +++---- nj-derive/src/generator/derive.rs | 42 ++++++++++++++++++++++++------- nj-derive/ui-tests/pass_enum.rs | 3 ++- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 4f1a5446..ae8f77b3 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -137,7 +137,8 @@ pub enum MyFieldType<'a> { #[derive(Debug)] pub enum MyFields<'a> { Named(Vec>), - Unnamed(Vec>) + Unnamed(Vec>), + Unit } impl<'a> MyFields<'a> { @@ -167,11 +168,7 @@ impl<'a> MyFields<'a> { Ok(MyFields::Unnamed(fields)) } - Fields::Unit => Err(Error::new( - input.span(), - "Unit structs/enum variants are not supported for automatic conversion yet. \ - If you would like to see them supported, please reach out.", - )), + Fields::Unit => Ok(MyFields::Unit) } } } diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index 24144f83..b2701f3f 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -51,11 +51,10 @@ fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { } fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { - let output_obj = format_ident!("output_obj"); let js_env = format_ident!("js_env"); let variant_conversions = enum_data.variants.iter() - .map(|v| generate_variant_conversion(enum_name, &js_env, &output_obj, v)) + .map(|v| generate_variant_conversion(enum_name, &js_env, v)) .collect::>(); quote! { @@ -69,23 +68,19 @@ fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, en val::JsObject }; - let mut #output_obj = JsObject::new(#js_env.clone(), - #js_env.create_object()?); - match self { #(#variant_conversions),* - }; - - #output_obj.try_to_js(#js_env) + } } } } } -fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &Ident, variant: &MyVariant) -> TokenStream { +fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVariant) -> TokenStream { let variant_name = variant.name; let variant_name_camelcase = format!("{}", variant.name).to_camel_case(); let fields_scope = quote! {}; + let output_obj = format_ident!("output_obj"); match &variant.fields { MyFields::Named(named_fields) => { @@ -101,6 +96,9 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I quote! { #enum_name::#variant_name { #(#field_bindings),* } => { + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + let mut #variant_output_obj = JsObject::new(#js_env.clone(), #js_env.create_object()?); @@ -110,6 +108,8 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I #variant_name_camelcase, #variant_output_obj.try_to_js(#js_env)? )?; + + #output_obj.try_to_js(#js_env) } } }, @@ -127,6 +127,9 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I quote! { #enum_name::#variant_name( #(#field_bindings),* ) => { + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + let #variant_output_arr = #js_env.create_array_with_len(#fields_count)?; #(#field_conversions)* @@ -135,6 +138,15 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, output_obj: &I #variant_name_camelcase, #variant_output_arr.try_to_js(#js_env)? )?; + + #output_obj.try_to_js(#js_env) + } + } + }, + MyFields::Unit => { + quote! { + #enum_name::#variant_name => { + #js_env.create_string_utf8(#variant_name_camelcase) } } } @@ -205,6 +217,18 @@ fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStr } } } + MyFields::Unit => { + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + #js_env.get_null() + } + } + } + } } } diff --git a/nj-derive/ui-tests/pass_enum.rs b/nj-derive/ui-tests/pass_enum.rs index bf67edb9..9c412027 100644 --- a/nj-derive/ui-tests/pass_enum.rs +++ b/nj-derive/ui-tests/pass_enum.rs @@ -5,7 +5,8 @@ enum TestEnum { Something(usize), Else { val: String - } + }, + UnitVariant } fn main() { From 9ec97f3e3f75fb9dbf65be6cc8a286cc870f9624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:28:13 +0200 Subject: [PATCH 12/23] feature complete --- CHANGELOG.md | 6 + Cargo.lock | 6 +- Cargo.toml | 2 +- README.md | 49 +++++++- examples/Cargo.lock | 186 +++++++++++++++++++++++++++++- examples/json/src/lib.rs | 26 +++++ examples/json/test.js | 20 +++- nj-core/Cargo.toml | 2 +- nj-derive/Cargo.toml | 2 +- nj-derive/src/ast/types.rs | 139 +++++++++++----------- nj-derive/src/generator/derive.rs | 165 +++++++++++++------------- nj-derive/src/lib.rs | 4 +- nj-derive/ui-tests/pass_enum.rs | 6 + 13 files changed, 445 insertions(+), 168 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd944574..6d319299 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ ## Unreleased ### Improvements +## [4.5.0] - TBD +### Improvements +- Added support for automatic conversion of enums into the JS representation by decorating their definition with `#[node_bindgen]` +- Defined a `NjError::Native` Error payload, which allows errors to return structured data to JS +- `Result` converts the error value to JS using `TryIntoJs` for structured error payloads + ## [4.4.0] - TBD ### Improvements - Added support for automatic conversion of structs into the JS representation by decorating their definition with `#[node_bindgen]` diff --git a/Cargo.lock b/Cargo.lock index e1dcf425..999cdd25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -676,7 +676,7 @@ dependencies = [ [[package]] name = "nj-core" -version = "4.4.0" +version = "4.5.0" dependencies = [ "async-trait", "ctor", @@ -692,7 +692,7 @@ dependencies = [ [[package]] name = "nj-derive" -version = "3.3.0" +version = "3.4.0" dependencies = [ "Inflector", "fluvio-future", @@ -709,7 +709,7 @@ version = "3.0.0" [[package]] name = "node-bindgen" -version = "4.4.0" +version = "4.5.0" dependencies = [ "nj-build", "nj-core", diff --git a/Cargo.toml b/Cargo.toml index 4b2849f8..eab3376f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-bindgen" -version = "4.4.0" +version = "4.5.0" authors = ["Fluvio Contributors "] edition = "2018" description = "easy way to write nodejs module using rust" diff --git a/README.md b/README.md index 5b1f5440..fa7e1db3 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ fn my_json() -> MyJson { ```js let addon = require('./dist'); -assert.deepEqual(addon.my_json(), { +assert.deepStrictEqual(addon.my_json(), { someName: "John", aNumber: 1337 }); @@ -281,6 +281,53 @@ Note that the fields must implement Any references must also implement `Clone`. Field names will be converted to camelCase. +## Enums + +Enums will also have their JS representation autogenerated with the help of `node_bindgen`: + +```rust +#[node_bindgen] +enum ErrorType { + WithMessage(String, usize), + WithFields { + val: usize + }, + UnitErrorType +} + +#[node_bindgen] +fn with_message() -> ErrorType { + ErrorType::WithMessage("test".to_owned(), 321) +} + +#[node_bindgen] +fn with_fields() -> ErrorType { + ErrorType::WithFields { + val: 123 + } +} + +#[node_bindgen] +fn with_unit() -> ErrorType { + ErrorType::UnitErrorType +} +``` + +```js +assert.deepStrictEqual(addon.withMessage(), { + withMessage: ["test", 321n] +}); +assert.deepStrictEqual(addon.withFields(), { + withFields: { + val: 123n + } +}); +assert.deepStrictEqual(addon.withUnit(), "UnitErrorType") +``` + +Unnamed variants will be converted to lists, named to objects and unit variants to strings equal to their name in PascalCase. +Generics and references are supported, with the same caveats as for structs. + ## JavaScript class JavaScript class is supported. diff --git a/examples/Cargo.lock b/examples/Cargo.lock index ce99b117..86c019a5 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -109,6 +109,23 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-process" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f38756dd9ac84671c428afbf7c9f7495feff9ec5b0710f17100098e5b354ac" +dependencies = [ + "async-io", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "libc", + "once_cell", + "signal-hook", + "winapi", +] + [[package]] name = "async-std" version = "1.9.0" @@ -119,6 +136,7 @@ dependencies = [ "async-global-executor", "async-io", "async-lock", + "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -296,9 +314,9 @@ dependencies = [ [[package]] name = "fluvio-future" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b5b2317b98bf0fa3653cdadaca2acb5d0cfbb4712f4396545db39c01e4eed9" +checksum = "61587e440c936984e7dab40903de1c9adc39ab13e8446b52c50852da5cd6fbcb" dependencies = [ "async-io", "async-std", @@ -308,6 +326,7 @@ dependencies = [ "thiserror", "tracing", "tracing-subscriber", + "wasm-timer", ] [[package]] @@ -325,6 +344,21 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "futures" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.13" @@ -332,6 +366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -340,6 +375,17 @@ version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" +[[package]] +name = "futures-executor" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.13" @@ -361,6 +407,50 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-macro" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" + +[[package]] +name = "futures-task" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" + +[[package]] +name = "futures-util" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + [[package]] name = "getrandom" version = "0.2.2" @@ -482,6 +572,15 @@ version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -545,7 +644,7 @@ dependencies = [ [[package]] name = "nj-core" -version = "4.3.0" +version = "4.5.0" dependencies = [ "async-trait", "ctor", @@ -561,7 +660,7 @@ dependencies = [ [[package]] name = "nj-derive" -version = "3.2.0" +version = "3.4.0" dependencies = [ "Inflector", "proc-macro2", @@ -695,7 +794,7 @@ version = "3.0.0" [[package]] name = "node-bindgen" -version = "4.3.0" +version = "4.5.0" dependencies = [ "nj-build", "nj-core", @@ -788,6 +887,31 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "pin-project" version = "1.0.5" @@ -845,6 +969,18 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + [[package]] name = "proc-macro2" version = "1.0.24" @@ -964,6 +1100,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "security-framework" version = "2.1.2" @@ -1027,6 +1169,25 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signal-hook" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.2" @@ -1306,6 +1467,21 @@ version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.48" diff --git a/examples/json/src/lib.rs b/examples/json/src/lib.rs index 4850df59..c447b349 100644 --- a/examples/json/src/lib.rs +++ b/examples/json/src/lib.rs @@ -20,6 +20,15 @@ struct Outer { #[node_bindgen] struct Inner(String); +#[node_bindgen] +enum ErrorType { + WithMessage(String, usize), + WithFields { + val: usize + }, + UnitErrorType +} + struct CustomJson { val: f64 } @@ -56,4 +65,21 @@ fn multilevel_json() -> Outer { Outer { val: Inner("hello".to_owned()) } +} + +#[node_bindgen] +fn with_message() -> ErrorType { + ErrorType::WithMessage("test".to_owned(), 321) +} + +#[node_bindgen] +fn with_fields() -> ErrorType { + ErrorType::WithFields { + val: 123 + } +} + +#[node_bindgen] +fn with_unit() -> ErrorType { + ErrorType::UnitErrorType } \ No newline at end of file diff --git a/examples/json/test.js b/examples/json/test.js index d9e3bc68..bcad0599 100644 --- a/examples/json/test.js +++ b/examples/json/test.js @@ -2,13 +2,25 @@ const assert = require('assert'); let addon = require('./dist'); -assert.deepEqual(addon.customJson(), { +assert.deepStrictEqual(addon.customJson(), { customFieldName: 10 }, "verify custom json"); -assert.deepEqual(addon.standardJson(), { +assert.deepStrictEqual(addon.standardJson(), { someName: "John", aNumber: 1337 }, "verify standard json"); -assert.deepEqual(addon.multilevelJson(), { +assert.deepStrictEqual(addon.multilevelJson(), { val: ["hello"] -}, "verify multilevel json"); \ No newline at end of file +}, "verify multilevel json"); + +assert.deepStrictEqual(addon.withMessage(), { + withMessage: ["test", 321n] +}, "simple unnamed enum variant"); +assert.deepStrictEqual(addon.withFields(), { + withFields: { + val: 123n + } +}, "named enum variant"); +assert.deepStrictEqual(addon.withUnit(), + "UnitErrorType", + "unit enum variant") \ No newline at end of file diff --git a/nj-core/Cargo.toml b/nj-core/Cargo.toml index 7e6a68b4..fb819a86 100644 --- a/nj-core/Cargo.toml +++ b/nj-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nj-core" -version = "4.4.0" +version = "4.5.0" authors = ["fluvio.io"] edition = "2018" description = "high level wrapper for Node N-API" diff --git a/nj-derive/Cargo.toml b/nj-derive/Cargo.toml index e6439355..b4f7a333 100644 --- a/nj-derive/Cargo.toml +++ b/nj-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nj-derive" -version = "3.3.0" +version = "3.4.0" authors = ["fluvio.io"] edition = "2018" description = "procedure macro for node-bindgen" diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index ae8f77b3..898eab06 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -113,8 +113,58 @@ impl MyTupleType<'_> { } #[derive(Debug)] -pub struct MyStruct<'a> { - pub fields: MyFields<'a> +pub struct MyDeriveInput<'a> { + pub name: &'a Ident, + pub generics: MyGenerics<'a>, + pub payload: MyDerivePayload<'a> +} + +#[derive(Debug)] +pub enum MyDerivePayload<'a> { + Struct(MyStruct<'a>), + Enum(MyEnum<'a>) +} + +impl<'a> MyDeriveInput<'a> { + pub fn from_ast(input: &'a DeriveInput) -> Result { + let name = &input.ident; + let generic_params = input.generics.params.clone().into_iter().collect(); + let generics = MyGenerics { + params: generic_params, + where_clause: &input.generics.where_clause, + }; + + match &input.data { + Data::Struct(inner_struct) => { + let parsed_struct = MyStruct::from_ast(&inner_struct)?; + Ok(MyDeriveInput { + name, + generics, + payload: MyDerivePayload::Struct(parsed_struct) + }) + }, + Data::Enum(inner_enum) => { + let parsed_enum = MyEnum::from_ast(&inner_enum)?; + Ok(MyDeriveInput { + name, + generics, + payload: MyDerivePayload::Enum(parsed_enum) + }) + }, + Data::Union(_) => Err(Error::new( + input.span(), + "Unions are not supported \ + for automatic conversion to JavaScript representation", + )), + } + } +} + +#[derive(Debug)] +pub enum MyFields<'a> { + Named(Vec>), + Unnamed(Vec>), + Unit } #[derive(Debug)] @@ -134,13 +184,6 @@ pub enum MyFieldType<'a> { Ref(MyReferenceType<'a>), } -#[derive(Debug)] -pub enum MyFields<'a> { - Named(Vec>), - Unnamed(Vec>), - Unit -} - impl<'a> MyFields<'a> { pub fn from_ast(input: &'a Fields) -> Result { match &input { @@ -173,13 +216,6 @@ impl<'a> MyFields<'a> { } } - -#[derive(Debug)] -pub struct MyGenerics<'a> { - pub params: Vec, - pub where_clause: &'a Option, -} - impl<'a> MyFieldType<'a> { pub fn from(ty: &'a Type) -> Result { match ty { @@ -199,60 +235,6 @@ pub struct MyEnum<'a> { pub variants: Vec> } -#[derive(Debug)] -pub struct MyVariant<'a> { - pub name: &'a Ident, - pub fields: MyFields<'a> -} - -#[derive(Debug)] -pub enum MyDerivePayload<'a> { - Struct(MyStruct<'a>), - Enum(MyEnum<'a>) -} - -#[derive(Debug)] -pub struct MyDeriveInput<'a> { - pub name: &'a Ident, - pub generics: MyGenerics<'a>, - pub payload: MyDerivePayload<'a> -} - -impl<'a> MyDeriveInput<'a> { - pub fn from_ast(input: &'a DeriveInput) -> Result { - let name = &input.ident; - let generic_params = input.generics.params.clone().into_iter().collect(); - let generics = MyGenerics { - params: generic_params, - where_clause: &input.generics.where_clause, - }; - - match &input.data { - Data::Struct(inner_struct) => { - let parsed_struct = MyStruct::from_ast(&inner_struct)?; - Ok(MyDeriveInput { - name, - generics, - payload: MyDerivePayload::Struct(parsed_struct) - }) - }, - Data::Enum(inner_enum) => { - let parsed_enum = MyEnum::from_ast(&inner_enum)?; - Ok(MyDeriveInput { - name, - generics, - payload: MyDerivePayload::Enum(parsed_enum) - }) - }, - Data::Union(_) => Err(Error::new( - input.span(), - "Unions are not supported \ - for automatic conversion to JavaScript representation", - )), - } - } -} - impl<'a> MyEnum<'a> { pub fn from_ast(enum_data: &'a DataEnum) -> Result { let variants = enum_data.variants.iter() @@ -266,6 +248,12 @@ impl<'a> MyEnum<'a> { } } +#[derive(Debug)] +pub struct MyVariant<'a> { + pub name: &'a Ident, + pub fields: MyFields<'a> +} + impl<'a> MyVariant<'a> { pub fn from_ast(variant_data: &'a Variant) -> Result { let fields = MyFields::from_ast(&variant_data.fields)?; @@ -277,6 +265,11 @@ impl<'a> MyVariant<'a> { } } +#[derive(Debug)] +pub struct MyStruct<'a> { + pub fields: MyFields<'a> +} + impl<'a> MyStruct<'a> { pub fn from_ast(struct_data: &'a DataStruct) -> Result { let fields = MyFields::from_ast(&struct_data.fields)?; @@ -286,3 +279,9 @@ impl<'a> MyStruct<'a> { }) } } + +#[derive(Debug)] +pub struct MyGenerics<'a> { + pub params: Vec, + pub where_clause: &'a Option, +} diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index b2701f3f..16cac79c 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -50,6 +50,85 @@ fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { } } +fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { + let js_env = format_ident!("js_env"); + let fields_scope = quote! { + self. + }; + + + match &struct_data.fields { + MyFields::Named(named_fields) => { + let output_obj = format_ident!("output_obj"); + let field_conversions = + generate_named_field_conversions(&output_obj, + &fields_scope, + &js_env, + &named_fields); + + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + use node_bindgen::core::{ + TryIntoJs, + val::JsObject + }; + + let mut #output_obj = JsObject::new(#js_env.clone(), + #js_env.create_object()?); + + #(#field_conversions)* + + #output_obj.try_to_js(#js_env) + } + } + } + }, + MyFields::Unnamed(unnamed_fields) => { + let fields_count = unnamed_fields.len(); + let output_arr = format_ident!("output_arr"); + let field_conversions = + generate_unnamed_field_conversions(&output_arr, + &js_env, + &unnamed_fields); + + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + use node_bindgen::core::{ + TryIntoJs + }; + + let #output_arr = #js_env.create_array_with_len(#fields_count)?; + + #(#field_conversions)* + + Ok(#output_arr) + } + } + } + } + MyFields::Unit => { + quote! { + #impl_signature { + fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> + Result + { + #js_env.get_null() + } + } + } + } + } +} + fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { let js_env = format_ident!("js_env"); @@ -144,88 +223,11 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVa } }, MyFields::Unit => { - quote! { - #enum_name::#variant_name => { - #js_env.create_string_utf8(#variant_name_camelcase) - } - } - } - } -} - -fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { - let js_env = format_ident!("js_env"); - let fields_scope = quote! { - self. - }; - - - match &struct_data.fields { - MyFields::Named(named_fields) => { - let output_obj = format_ident!("output_obj"); - let field_conversions = - generate_named_field_conversions(&output_obj, - &fields_scope, - &js_env, - &named_fields); + let variant_name_pascalcase = format!("{}", variant.name).to_pascal_case(); quote! { - #impl_signature { - fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> - Result - { - use node_bindgen::core::{ - TryIntoJs, - val::JsObject - }; - - let mut #output_obj = JsObject::new(#js_env.clone(), - #js_env.create_object()?); - - #(#field_conversions)* - - #output_obj.try_to_js(#js_env) - } - } - } - }, - MyFields::Unnamed(unnamed_fields) => { - let fields_count = unnamed_fields.len(); - let output_arr = format_ident!("output_arr"); - let field_conversions = - generate_unnamed_field_conversions(&output_arr, - &js_env, - &unnamed_fields); - - quote! { - #impl_signature { - fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> - Result - { - use node_bindgen::core::{ - TryIntoJs - }; - - let #output_arr = #js_env.create_array_with_len(#fields_count)?; - - #(#field_conversions)* - - Ok(#output_arr) - } - } - } - } - MyFields::Unit => { - quote! { - #impl_signature { - fn try_to_js(self, #js_env: &node_bindgen::core::val::JsEnv) -> - Result - { - #js_env.get_null() - } + #enum_name::#variant_name => { + #js_env.create_string_utf8(#variant_name_pascalcase) } } } @@ -272,6 +274,7 @@ fn generate_impl_signature<'a>(name: &'a Ident, generics: &'a MyGenerics<'a>) -> } } +// Named fields, already bound to their field names fn generate_named_field_conversions<'a>( output_obj: &Ident, fields_scope: &TokenStream, @@ -299,6 +302,7 @@ fn generate_named_field_conversions<'a>( .collect() } +// Unnamed fields, stored in a tuple and accessed by index fn generate_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, @@ -328,6 +332,7 @@ fn generate_unnamed_field_conversions<'a>( .collect() } +// Unnamed fields, bound ahead of time to named variables fn generate_bound_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, diff --git a/nj-derive/src/lib.rs b/nj-derive/src/lib.rs index 8241a5c0..85a39c8a 100644 --- a/nj-derive/src/lib.rs +++ b/nj-derive/src/lib.rs @@ -56,8 +56,8 @@ pub fn node_bindgen(args: TokenStream, item: TokenStream) -> TokenStream { }; // used for debugging, if error occurs println do not work so should uncomment express - println!("{}", out_express); - //let out_express = quote::quote! {}; + // println!("{}", out_express); + // let out_express = quote::quote! {}; out_express.into() } diff --git a/nj-derive/ui-tests/pass_enum.rs b/nj-derive/ui-tests/pass_enum.rs index 9c412027..cd49b219 100644 --- a/nj-derive/ui-tests/pass_enum.rs +++ b/nj-derive/ui-tests/pass_enum.rs @@ -1,4 +1,5 @@ use node_bindgen::derive::node_bindgen; +use node_bindgen::core::TryIntoJs; #[node_bindgen] enum TestEnum { @@ -9,5 +10,10 @@ enum TestEnum { UnitVariant } +#[node_bindgen] +enum Generic { + Container(T) +} + fn main() { } \ No newline at end of file From 12dbff1ff8246fef9116e37b76292cc86acbb149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:32:05 +0200 Subject: [PATCH 13/23] added the unit struct to the examples --- examples/json/src/lib.rs | 8 ++++++++ examples/json/test.js | 2 ++ 2 files changed, 10 insertions(+) diff --git a/examples/json/src/lib.rs b/examples/json/src/lib.rs index c447b349..d32fbcc5 100644 --- a/examples/json/src/lib.rs +++ b/examples/json/src/lib.rs @@ -20,6 +20,9 @@ struct Outer { #[node_bindgen] struct Inner(String); +#[node_bindgen] +struct UnitStruct; + #[node_bindgen] enum ErrorType { WithMessage(String, usize), @@ -67,6 +70,11 @@ fn multilevel_json() -> Outer { } } +#[node_bindgen] +fn unit_struct() -> UnitStruct { + UnitStruct +} + #[node_bindgen] fn with_message() -> ErrorType { ErrorType::WithMessage("test".to_owned(), 321) diff --git a/examples/json/test.js b/examples/json/test.js index bcad0599..09c99834 100644 --- a/examples/json/test.js +++ b/examples/json/test.js @@ -13,6 +13,8 @@ assert.deepStrictEqual(addon.multilevelJson(), { val: ["hello"] }, "verify multilevel json"); +assert.strictEqual(addon.unitStruct(), null); + assert.deepStrictEqual(addon.withMessage(), { withMessage: ["test", 321n] }, "simple unnamed enum variant"); From 9c0976235bb353db5000943bc2ee30a312364f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:38:56 +0200 Subject: [PATCH 14/23] formatter ran --- nj-derive/src/ast/types.rs | 39 ++++++++-------- nj-derive/src/generator/derive.rs | 77 ++++++++++++++++++------------- 2 files changed, 64 insertions(+), 52 deletions(-) diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index 898eab06..fa1385c5 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -116,13 +116,13 @@ impl MyTupleType<'_> { pub struct MyDeriveInput<'a> { pub name: &'a Ident, pub generics: MyGenerics<'a>, - pub payload: MyDerivePayload<'a> + pub payload: MyDerivePayload<'a>, } #[derive(Debug)] pub enum MyDerivePayload<'a> { Struct(MyStruct<'a>), - Enum(MyEnum<'a>) + Enum(MyEnum<'a>), } impl<'a> MyDeriveInput<'a> { @@ -140,17 +140,17 @@ impl<'a> MyDeriveInput<'a> { Ok(MyDeriveInput { name, generics, - payload: MyDerivePayload::Struct(parsed_struct) + payload: MyDerivePayload::Struct(parsed_struct), }) - }, + } Data::Enum(inner_enum) => { let parsed_enum = MyEnum::from_ast(&inner_enum)?; Ok(MyDeriveInput { name, generics, - payload: MyDerivePayload::Enum(parsed_enum) + payload: MyDerivePayload::Enum(parsed_enum), }) - }, + } Data::Union(_) => Err(Error::new( input.span(), "Unions are not supported \ @@ -164,7 +164,7 @@ impl<'a> MyDeriveInput<'a> { pub enum MyFields<'a> { Named(Vec>), Unnamed(Vec>), - Unit + Unit, } #[derive(Debug)] @@ -175,7 +175,7 @@ pub struct MyNamedField<'a> { #[derive(Debug)] pub struct MyUnnamedField<'a> { - pub ty: MyFieldType<'a> + pub ty: MyFieldType<'a>, } #[derive(Debug)] @@ -211,7 +211,7 @@ impl<'a> MyFields<'a> { Ok(MyFields::Unnamed(fields)) } - Fields::Unit => Ok(MyFields::Unit) + Fields::Unit => Ok(MyFields::Unit), } } } @@ -232,26 +232,25 @@ impl<'a> MyFieldType<'a> { #[derive(Debug)] pub struct MyEnum<'a> { - pub variants: Vec> + pub variants: Vec>, } impl<'a> MyEnum<'a> { pub fn from_ast(enum_data: &'a DataEnum) -> Result { - let variants = enum_data.variants.iter() + let variants = enum_data + .variants + .iter() .map(|v| MyVariant::from_ast(v)) .collect::>>()?; - - Ok(MyEnum { - variants - }) + Ok(MyEnum { variants }) } } #[derive(Debug)] pub struct MyVariant<'a> { pub name: &'a Ident, - pub fields: MyFields<'a> + pub fields: MyFields<'a>, } impl<'a> MyVariant<'a> { @@ -260,23 +259,21 @@ impl<'a> MyVariant<'a> { Ok(MyVariant { name: &variant_data.ident, - fields + fields, }) } } #[derive(Debug)] pub struct MyStruct<'a> { - pub fields: MyFields<'a> + pub fields: MyFields<'a>, } impl<'a> MyStruct<'a> { pub fn from_ast(struct_data: &'a DataStruct) -> Result { let fields = MyFields::from_ast(&struct_data.fields)?; - Ok(MyStruct { - fields - }) + Ok(MyStruct { fields }) } } diff --git a/nj-derive/src/generator/derive.rs b/nj-derive/src/generator/derive.rs index 16cac79c..1805e8de 100644 --- a/nj-derive/src/generator/derive.rs +++ b/nj-derive/src/generator/derive.rs @@ -36,35 +36,37 @@ pub fn generate_datatype(input_data: DeriveInput) -> TokenStream { } } - fn generate_try_into_js(parsed_data: &MyDeriveInput) -> TokenStream { let impl_signature = generate_impl_signature(&parsed_data.name, &parsed_data.generics); match &parsed_data.payload { MyDerivePayload::Struct(struct_data) => { generate_struct_try_into_js(&impl_signature, &struct_data) - }, + } MyDerivePayload::Enum(enum_data) => { generate_enum_try_into_js(&parsed_data.name, &impl_signature, &enum_data) } } } -fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStruct) -> TokenStream { +fn generate_struct_try_into_js( + impl_signature: &TokenStream, + struct_data: &MyStruct, +) -> TokenStream { let js_env = format_ident!("js_env"); let fields_scope = quote! { self. }; - match &struct_data.fields { MyFields::Named(named_fields) => { let output_obj = format_ident!("output_obj"); - let field_conversions = - generate_named_field_conversions(&output_obj, - &fields_scope, - &js_env, - &named_fields); + let field_conversions = generate_named_field_conversions( + &output_obj, + &fields_scope, + &js_env, + &named_fields, + ); quote! { #impl_signature { @@ -86,14 +88,12 @@ fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStr } } } - }, + } MyFields::Unnamed(unnamed_fields) => { let fields_count = unnamed_fields.len(); let output_arr = format_ident!("output_arr"); let field_conversions = - generate_unnamed_field_conversions(&output_arr, - &js_env, - &unnamed_fields); + generate_unnamed_field_conversions(&output_arr, &js_env, &unnamed_fields); quote! { #impl_signature { @@ -129,10 +129,16 @@ fn generate_struct_try_into_js(impl_signature: &TokenStream, struct_data: &MyStr } } -fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, enum_data: &MyEnum) -> TokenStream { +fn generate_enum_try_into_js( + enum_name: &Ident, + impl_signature: &TokenStream, + enum_data: &MyEnum, +) -> TokenStream { let js_env = format_ident!("js_env"); - let variant_conversions = enum_data.variants.iter() + let variant_conversions = enum_data + .variants + .iter() .map(|v| generate_variant_conversion(enum_name, &js_env, v)) .collect::>(); @@ -155,23 +161,30 @@ fn generate_enum_try_into_js(enum_name: &Ident, impl_signature: &TokenStream, en } } -fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVariant) -> TokenStream { - let variant_name = variant.name; +fn generate_variant_conversion( + enum_name: &Ident, + js_env: &Ident, + variant: &MyVariant, +) -> TokenStream { + let variant_name = variant.name; let variant_name_camelcase = format!("{}", variant.name).to_camel_case(); - let fields_scope = quote! {}; + let fields_scope = quote! {}; let output_obj = format_ident!("output_obj"); match &variant.fields { MyFields::Named(named_fields) => { let variant_output_obj = format_ident!("variant_output_obj"); - let field_bindings = named_fields.iter() + let field_bindings = named_fields + .iter() .map(|field| field.name) .collect::>(); - let field_conversions = generate_named_field_conversions(&variant_output_obj, - &fields_scope, - &js_env, - &named_fields); + let field_conversions = generate_named_field_conversions( + &variant_output_obj, + &fields_scope, + &js_env, + &named_fields, + ); quote! { #enum_name::#variant_name { #(#field_bindings),* } => { @@ -191,18 +204,20 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVa #output_obj.try_to_js(#js_env) } } - }, + } MyFields::Unnamed(unnamed_fields) => { let variant_output_arr = format_ident!("variant_output_arr"); - let fields_count = unnamed_fields.len(); + let fields_count = unnamed_fields.len(); let field_bindings = (0..fields_count) .into_iter() .map(|field_idx| format_ident!("field_{}", field_idx)) .collect::>(); - let field_conversions = generate_bound_unnamed_field_conversions(&variant_output_arr, - &js_env, - &field_bindings); + let field_conversions = generate_bound_unnamed_field_conversions( + &variant_output_arr, + &js_env, + &field_bindings, + ); quote! { #enum_name::#variant_name( #(#field_bindings),* ) => { @@ -221,7 +236,7 @@ fn generate_variant_conversion(enum_name: &Ident, js_env: &Ident, variant: &MyVa #output_obj.try_to_js(#js_env) } } - }, + } MyFields::Unit => { let variant_name_pascalcase = format!("{}", variant.name).to_pascal_case(); @@ -336,7 +351,7 @@ fn generate_unnamed_field_conversions<'a>( fn generate_bound_unnamed_field_conversions<'a>( output_array: &Ident, js_env: &Ident, - field_bindings: &'a [Ident] + field_bindings: &'a [Ident], ) -> Vec { field_bindings .iter() @@ -355,4 +370,4 @@ fn generate_bound_unnamed_field_conversions<'a>( } }) .collect() -} \ No newline at end of file +} From eef26270c7045e7b69feda889b588dac3c147d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:43:50 +0200 Subject: [PATCH 15/23] clippy is happier --- Cargo.lock | 2 -- nj-derive/src/ast/types.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 999cdd25..73d95fc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "Inflector" version = "0.11.4" diff --git a/nj-derive/src/ast/types.rs b/nj-derive/src/ast/types.rs index fa1385c5..287671c9 100644 --- a/nj-derive/src/ast/types.rs +++ b/nj-derive/src/ast/types.rs @@ -6,8 +6,6 @@ use syn::Error; use syn::Result; use syn::spanned::Spanned; use syn::DeriveInput; -use syn::Attribute; -use syn::Expr; use syn::Data; use syn::DataEnum; use syn::DataStruct; From 7801fe5bd97f978da65f09d4b1848864e9697fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Thu, 13 May 2021 14:47:30 +0200 Subject: [PATCH 16/23] further clippy --- nj-core/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nj-core/src/error.rs b/nj-core/src/error.rs index 585731bd..d4ea3ac9 100644 --- a/nj-core/src/error.rs +++ b/nj-core/src/error.rs @@ -35,7 +35,7 @@ impl NjError { pub fn as_js(&self, js_env: &JsEnv) -> napi_value { match self { NjError::Native(err) => *err, - other => { + _ => { let msg = self.to_string(); js_env.create_error(&msg).expect("error cannot be created") } From 0e4625261958b1f38164ac492a24854fc75290ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 18 May 2021 08:10:21 +0200 Subject: [PATCH 17/23] updated the changelog, readme --- CHANGELOG.md | 6 +----- README.md | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d319299..c156121b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,9 @@ ## [4.5.0] - TBD ### Improvements -- Added support for automatic conversion of enums into the JS representation by decorating their definition with `#[node_bindgen]` +- Added support for automatic conversion of structs and enums into the JS representation by decorating their definition with `#[node_bindgen]` ([#148](https://github.com/infinyon/node-bindgen/pull/148) and [#155](https://github.com/infinyon/node-bindgen/pull/155)) - Defined a `NjError::Native` Error payload, which allows errors to return structured data to JS - `Result` converts the error value to JS using `TryIntoJs` for structured error payloads - -## [4.4.0] - TBD -### Improvements -- Added support for automatic conversion of structs into the JS representation by decorating their definition with `#[node_bindgen]` - Add support for passing tuples between Node and Rust ([#142](https://github.com/infinyon/node-bindgen/pull/142)) - Bump electron from 9.3.1 to 9.4.0 in /examples/electron ([#135](https://github.com/infinyon/node-bindgen/pull/135)) - Update JSArrayBuffer to be usable in `env.convert_to_rust` ([#136](https://github.com/infinyon/node-bindgen/pull/136)) diff --git a/README.md b/README.md index fa7e1db3..87f59028 100644 --- a/README.md +++ b/README.md @@ -325,7 +325,7 @@ assert.deepStrictEqual(addon.withFields(), { assert.deepStrictEqual(addon.withUnit(), "UnitErrorType") ``` -Unnamed variants will be converted to lists, named to objects and unit variants to strings equal to their name in PascalCase. +Tuple variants will be converted into lists, struct variants converted to objects, and unit variants converted into strings matching the variant's name in PascalCase. Generics and references are supported, with the same caveats as for structs. ## JavaScript class From ced2028c89b7ac47d509e05fc48e85366f61ed96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 18 May 2021 08:29:41 +0200 Subject: [PATCH 18/23] tryintojs is implemented for std::io::Error --- nj-core/src/convert.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/nj-core/src/convert.rs b/nj-core/src/convert.rs index 0fca0413..2e9a1421 100644 --- a/nj-core/src/convert.rs +++ b/nj-core/src/convert.rs @@ -59,6 +59,20 @@ impl TryIntoJs for () { } } +impl TryIntoJs for NjError { + fn try_to_js(self, js_env: &JsEnv) -> Result { + // Re-throw the error into JS + Err(self) + } +} + +impl TryIntoJs for std::io::Error { + fn try_to_js(self, js_env: &JsEnv) -> Result { + let message = self.to_string(); + Err(NjError::Other(message)) + } +} + impl TryIntoJs for Result where T: TryIntoJs, From 9ba7389c65b3372aa4c73e65ea91b82db431645c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 18 May 2021 08:31:14 +0200 Subject: [PATCH 19/23] fmt is a happy fmt --- nj-core/src/convert.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nj-core/src/convert.rs b/nj-core/src/convert.rs index 2e9a1421..6554b381 100644 --- a/nj-core/src/convert.rs +++ b/nj-core/src/convert.rs @@ -60,14 +60,14 @@ impl TryIntoJs for () { } impl TryIntoJs for NjError { - fn try_to_js(self, js_env: &JsEnv) -> Result { + fn try_to_js(self, _js_env: &JsEnv) -> Result { // Re-throw the error into JS Err(self) } } impl TryIntoJs for std::io::Error { - fn try_to_js(self, js_env: &JsEnv) -> Result { + fn try_to_js(self, _js_env: &JsEnv) -> Result { let message = self.to_string(); Err(NjError::Other(message)) } From 15c408269c5bd281335107f98058a8062f40bc14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 18 May 2021 10:07:07 +0200 Subject: [PATCH 20/23] fixed a comment typo --- nj-core/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nj-core/src/error.rs b/nj-core/src/error.rs index d4ea3ac9..7da62307 100644 --- a/nj-core/src/error.rs +++ b/nj-core/src/error.rs @@ -21,7 +21,7 @@ pub enum NjError { Other(String), } -// error are throw +// errors are thrown impl IntoJs for NjError { fn into_js(self, js_env: &JsEnv) -> napi_value { let msg = self.to_string(); From f1c918455de2ac408e1644f8866ed0408d8d4e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 18 May 2021 18:41:35 +0200 Subject: [PATCH 21/23] bumped the version to v5 --- CHANGELOG.md | 2 +- Cargo.lock | 97 +++++++------- Cargo.toml | 4 +- examples/Cargo.lock | 258 +++++++++++++++++-------------------- examples/tuples/Cargo.toml | 4 +- nj-core/Cargo.toml | 2 +- 6 files changed, 176 insertions(+), 191 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c156121b..978eb0c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Unreleased ### Improvements -## [4.5.0] - TBD +## [5.0.0] - TBD ### Improvements - Added support for automatic conversion of structs and enums into the JS representation by decorating their definition with `#[node_bindgen]` ([#148](https://github.com/infinyon/node-bindgen/pull/148) and [#155](https://github.com/infinyon/node-bindgen/pull/155)) - Defined a `NjError::Native` Error payload, which allows errors to return structured data to JS diff --git a/Cargo.lock b/Cargo.lock index 73d95fc6..b790d73e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Inflector" version = "0.11.4" @@ -328,9 +330,9 @@ dependencies = [ [[package]] name = "fluvio-future" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd29a0773ef0ab97eb91e621093b4b64218456941e33fd63d9647fbe57a439cf" +checksum = "61587e440c936984e7dab40903de1c9adc39ab13e8446b52c50852da5cd6fbcb" dependencies = [ "async-io", "async-std", @@ -360,9 +362,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "futures" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" +checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" dependencies = [ "futures-channel", "futures-core", @@ -375,9 +377,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" +checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" dependencies = [ "futures-core", "futures-sink", @@ -385,15 +387,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" +checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" [[package]] name = "futures-executor" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" +checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" dependencies = [ "futures-core", "futures-task", @@ -402,9 +404,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" +checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" [[package]] name = "futures-lite" @@ -423,10 +425,11 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" +checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ + "autocfg", "proc-macro-hack", "proc-macro2", "quote", @@ -435,22 +438,23 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" [[package]] name = "futures-task" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" [[package]] name = "futures-util" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" +checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ + "autocfg", "futures-channel", "futures-core", "futures-io", @@ -573,9 +577,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" +checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" dependencies = [ "wasm-bindgen", ] @@ -674,7 +678,7 @@ dependencies = [ [[package]] name = "nj-core" -version = "4.5.0" +version = "5.0.0" dependencies = [ "async-trait", "ctor", @@ -707,7 +711,7 @@ version = "3.0.0" [[package]] name = "node-bindgen" -version = "4.5.0" +version = "5.0.0" dependencies = [ "nj-build", "nj-core", @@ -777,9 +781,9 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-sys" @@ -1084,18 +1088,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2", "quote", @@ -1385,11 +1389,12 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "value-bag" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" +checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" dependencies = [ "ctor", + "version_check", ] [[package]] @@ -1418,9 +1423,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1428,9 +1433,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" dependencies = [ "bumpalo", "lazy_static", @@ -1443,9 +1448,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" +checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" dependencies = [ "cfg-if", "js-sys", @@ -1455,9 +1460,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1465,9 +1470,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" dependencies = [ "proc-macro2", "quote", @@ -1478,9 +1483,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" [[package]] name = "wasm-timer" @@ -1499,9 +1504,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" +checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index eab3376f..63e54407 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-bindgen" -version = "4.5.0" +version = "5.0.0" authors = ["Fluvio Contributors "] edition = "2018" description = "easy way to write nodejs module using rust" @@ -15,7 +15,7 @@ build = ["nj-build"] [dependencies] nj-sys = { path = "nj-sys", version = "3.0.0", optional = true } -nj-core = { path = "nj-core", version = "4.3.0", optional = true } +nj-core = { path = "nj-core", version = "5.0.0", optional = true } nj-build = { path = "nj-build", version = "0.2.3", optional = true } nj-derive = { path = "nj-derive", version = "3.2.0", optional = true } diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 86c019a5..37da8b24 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -43,16 +43,16 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", "once_cell", - "vec-arena", + "slab", ] [[package]] @@ -73,29 +73,29 @@ dependencies = [ [[package]] name = "async-io" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" +checksum = "4bbfd5cf2794b1e908ea8457e6c45f8f8f1f6ec5f74617bf4662623f47503c3b" dependencies = [ "concurrent-queue", "fastrand", "futures-lite", "libc", "log", - "nb-connect", "once_cell", "parking", "polling", - "vec-arena", + "slab", + "socket2", "waker-fn", "winapi", ] [[package]] name = "async-lock" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" +checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" dependencies = [ "event-listener", ] @@ -117,7 +117,7 @@ checksum = "a8f38756dd9ac84671c428afbf7c9f7495feff9ec5b0710f17100098e5b354ac" dependencies = [ "async-io", "blocking", - "cfg-if 1.0.0", + "cfg-if", "event-listener", "futures-lite", "libc", @@ -162,9 +162,9 @@ checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" -version = "0.1.48" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea56748e10732c49404c153638a15ec3d6211ec5ff35d9bb20e13b93576adf" +checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722" dependencies = [ "proc-macro2", "quote", @@ -227,12 +227,6 @@ version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -278,20 +272,20 @@ checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" [[package]] name = "crossbeam-utils" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] [[package]] name = "ctor" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" +checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" dependencies = [ "quote", "syn", @@ -305,9 +299,9 @@ checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "fastrand" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +checksum = "77b705829d1e87f762c2df6da140b26af5839e1033aa84aa5f56bb688e4e1bdb" dependencies = [ "instant", ] @@ -346,9 +340,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "futures" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" dependencies = [ "futures-channel", "futures-core", @@ -361,9 +355,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" +checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" dependencies = [ "futures-core", "futures-sink", @@ -371,15 +365,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" +checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" [[package]] name = "futures-executor" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" +checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" dependencies = [ "futures-core", "futures-task", @@ -388,9 +382,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" +checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" [[package]] name = "futures-lite" @@ -409,10 +403,11 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" +checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ + "autocfg", "proc-macro-hack", "proc-macro2", "quote", @@ -433,10 +428,11 @@ checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" [[package]] name = "futures-util" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ + "autocfg", "futures-channel", "futures-core", "futures-io", @@ -457,7 +453,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] @@ -511,7 +507,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -544,9 +540,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.48" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" +checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" dependencies = [ "wasm-bindgen", ] @@ -568,9 +564,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.88" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" +checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" [[package]] name = "lock_api" @@ -587,7 +583,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "value-bag", ] @@ -602,9 +598,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" [[package]] name = "native-tls" @@ -624,16 +620,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nb-connect" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f" -dependencies = [ - "libc", - "socket2", -] - [[package]] name = "nj-build" version = "0.2.3" @@ -644,7 +630,7 @@ dependencies = [ [[package]] name = "nj-core" -version = "4.5.0" +version = "5.0.0" dependencies = [ "async-trait", "ctor", @@ -794,7 +780,7 @@ version = "3.0.0" [[package]] name = "node-bindgen" -version = "4.5.0" +version = "5.0.0" dependencies = [ "nj-build", "nj-core", @@ -850,29 +836,29 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "openssl" -version = "0.10.32" +version = "0.10.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", - "lazy_static", "libc", + "once_cell", "openssl-sys", ] [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-sys" -version = "0.9.60" +version = "0.9.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98" dependencies = [ "autocfg", "cc", @@ -904,7 +890,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -914,18 +900,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" +checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" +checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" dependencies = [ "proc-macro2", "quote", @@ -952,11 +938,11 @@ checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "polling" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" +checksum = "4fc12d774e799ee9ebae13f4076ca003b40d18a11ac0f3641e6f899618580b7b" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "log", "wepoll-sys", @@ -983,9 +969,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -1041,18 +1027,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.4.4" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54fd1046a3107eb58f42de31d656fee6853e5d276c455fd943742dce89fc3dd3" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -1071,9 +1057,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -1108,9 +1094,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d493c5f39e02dfb062cd8f33301f90f9b13b650e8c1b1d0fd75c19dd64bff69d" +checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84" dependencies = [ "bitflags", "core-foundation", @@ -1121,9 +1107,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee48cdde5ed250b0d3252818f646e174ab414036edb884dde62d80a3ac6082d" +checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339" dependencies = [ "core-foundation-sys", "libc", @@ -1131,18 +1117,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.124" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.124" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2", "quote", @@ -1190,9 +1176,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" [[package]] name = "smallvec" @@ -1202,20 +1188,19 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "socket2" -version = "0.3.19" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" dependencies = [ - "cfg-if 1.0.0", "libc", "winapi", ] [[package]] name = "syn" -version = "1.0.63" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ "proc-macro2", "quote", @@ -1228,7 +1213,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "rand", "redox_syscall", @@ -1274,11 +1259,11 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1286,9 +1271,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41768be5b9f3489491825f56f01f25290aa1d3e7cc97e182d4d34360493ba6fa" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" dependencies = [ "proc-macro2", "quote", @@ -1297,9 +1282,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" dependencies = [ "lazy_static", ] @@ -1327,9 +1312,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ab8966ac3ca27126141f7999361cc97dd6fb4b71da04c02044fa9045d98bb96" +checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5" dependencies = [ "ansi_term", "chrono", @@ -1358,30 +1343,25 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "value-bag" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" +checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" dependencies = [ "ctor", + "version_check", ] [[package]] name = "vcpkg" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" - -[[package]] -name = "vec-arena" -version = "1.0.0" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" +checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d" [[package]] name = "version_check" @@ -1403,19 +1383,19 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.71" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" +checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.71" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" +checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" dependencies = [ "bumpalo", "lazy_static", @@ -1428,11 +1408,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.21" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e67a5806118af01f0d9045915676b22aaebecf4178ae7021bc171dab0b897ab" +checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -1440,9 +1420,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.71" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" +checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1450,9 +1430,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.71" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" +checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" dependencies = [ "proc-macro2", "quote", @@ -1463,9 +1443,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.71" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" +checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" [[package]] name = "wasm-timer" @@ -1484,9 +1464,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.48" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" +checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/examples/tuples/Cargo.toml b/examples/tuples/Cargo.toml index d4437f3d..5dfdcdfd 100644 --- a/examples/tuples/Cargo.toml +++ b/examples/tuples/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -node-bindgen = { version = "4.3.0", path = "../.." } +node-bindgen = { path = "../.."} [build-dependencies] -node-bindgen = { version = "4.3.0", path = "../../", features = ["build"] } +node-bindgen = { path = "../../", features = ["build"] } diff --git a/nj-core/Cargo.toml b/nj-core/Cargo.toml index fb819a86..d2b9e689 100644 --- a/nj-core/Cargo.toml +++ b/nj-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nj-core" -version = "4.5.0" +version = "5.0.0" authors = ["fluvio.io"] edition = "2018" description = "high level wrapper for Node N-API" From cf0b1bba3f5af47d3c364e84760e7cd8df257596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 18 May 2021 21:17:03 +0200 Subject: [PATCH 22/23] sync and async exceptions behave the same, added tests/examples --- examples/json/src/lib.rs | 12 ++++++++++++ examples/json/test.js | 15 ++++++++++++++- nj-core/src/basic.rs | 17 +++++++++++++++++ nj-core/src/error.rs | 14 +++++++++++--- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/examples/json/src/lib.rs b/examples/json/src/lib.rs index d32fbcc5..0a98eaa6 100644 --- a/examples/json/src/lib.rs +++ b/examples/json/src/lib.rs @@ -90,4 +90,16 @@ fn with_fields() -> ErrorType { #[node_bindgen] fn with_unit() -> ErrorType { ErrorType::UnitErrorType +} + +#[node_bindgen] +fn failed_result_with_fields() -> Result<(), ErrorType> { + Err(ErrorType::WithFields { + val: 987 + }) +} + +#[node_bindgen] +async fn async_result_failed_unit() -> Result<(), ErrorType> { + Err(ErrorType::UnitErrorType) } \ No newline at end of file diff --git a/examples/json/test.js b/examples/json/test.js index 09c99834..80355ba9 100644 --- a/examples/json/test.js +++ b/examples/json/test.js @@ -25,4 +25,17 @@ assert.deepStrictEqual(addon.withFields(), { }, "named enum variant"); assert.deepStrictEqual(addon.withUnit(), "UnitErrorType", - "unit enum variant") \ No newline at end of file + "unit enum variant") + +assert.throws(() => addon.failedResultWithFields(), { + "withFields": { + val: 987n + } +}, "sync exception"); + +assert.rejects(() => addon.asyncResultFailedUnit(), + (err) => { + assert.strictEqual(err, "UnitErrorType"); + return true; + }, + "async exception"); \ No newline at end of file diff --git a/nj-core/src/basic.rs b/nj-core/src/basic.rs index 5c8ae885..2fedc2a5 100644 --- a/nj-core/src/basic.rs +++ b/nj-core/src/basic.rs @@ -476,6 +476,23 @@ impl JsEnv { pending } + pub fn throw(&self, value: napi_value) { + debug!("throwing a native value"); + + // check if there is exception pending, if so log and not do anything + if self.is_exception_pending() { + error!( + "there is exception pending when trying to throw \ + a native value, ignoring for now", + ); + return; + } + + unsafe { + crate::sys::napi_throw(self.inner(), value) + }; + } + pub fn throw_type_error(&self, message: &str) { debug!("throwing type error: {}", message); // check if there is exception pending, if so log and not do anything diff --git a/nj-core/src/error.rs b/nj-core/src/error.rs index 7da62307..a8095293 100644 --- a/nj-core/src/error.rs +++ b/nj-core/src/error.rs @@ -24,9 +24,17 @@ pub enum NjError { // errors are thrown impl IntoJs for NjError { fn into_js(self, js_env: &JsEnv) -> napi_value { - let msg = self.to_string(); - js_env.throw_type_error(&msg); - ptr::null_mut() + match self { + NjError::Native(err) => { + js_env.throw(err); + ptr::null_mut() + }, + _ => { + let msg = self.to_string(); + js_env.throw_type_error(&msg); + ptr::null_mut() + } + } } } From f7cb0a577453881aeef6b097326e5f127ee36821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kawalec?= Date: Tue, 18 May 2021 21:19:32 +0200 Subject: [PATCH 23/23] and the formatter is happy as well --- nj-core/src/basic.rs | 4 +--- nj-core/src/error.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/nj-core/src/basic.rs b/nj-core/src/basic.rs index 2fedc2a5..670da7da 100644 --- a/nj-core/src/basic.rs +++ b/nj-core/src/basic.rs @@ -488,9 +488,7 @@ impl JsEnv { return; } - unsafe { - crate::sys::napi_throw(self.inner(), value) - }; + unsafe { crate::sys::napi_throw(self.inner(), value) }; } pub fn throw_type_error(&self, message: &str) { diff --git a/nj-core/src/error.rs b/nj-core/src/error.rs index a8095293..42ab75dc 100644 --- a/nj-core/src/error.rs +++ b/nj-core/src/error.rs @@ -28,7 +28,7 @@ impl IntoJs for NjError { NjError::Native(err) => { js_env.throw(err); ptr::null_mut() - }, + } _ => { let msg = self.to_string(); js_env.throw_type_error(&msg);