1use proc_macro2::{Ident, Literal, TokenStream};
2use quote::{format_ident, quote};
3use syn::fold::{fold_fn_arg, fold_signature, Fold};
4use syn::parse::{Parse, ParseStream, Result};
5use syn::punctuated::Punctuated;
6use syn::{Block, FnArg, Signature, Token, Visibility};
7
8pub struct ArgLength {
9 pub length: Literal,
10}
11
12impl Parse for ArgLength {
13 fn parse(input: ParseStream) -> Result<Self> {
14 let vars: Punctuated = Punctuated::<Literal, Token![,]>::parse_terminated(input)?;
15 Ok(ArgLength {
16 length: varsOption
17 .first()
18 .cloned()
19 .unwrap_or_else(|| Literal::usize_unsuffixed(0)),
20 })
21 }
22}
23
24pub struct JsFunction {
25 pub args: Vec<FnArg>,
26 pub name: Option<Ident>,
27 pub signature: Option<Signature>,
28 pub signature_raw: Option<Signature>,
29 pub block: Vec<Block>,
30 pub visibility: Visibility,
31}
32
33impl JsFunction {
34 pub fn new() -> Self {
35 JsFunction {
36 args: vec![],
37 name: None,
38 signature: None,
39 signature_raw: None,
40 visibility: Visibility::Inherited,
41 block: vec![],
42 }
43 }
44}
45
46impl Fold for JsFunction {
47 fn fold_fn_arg(&mut self, arg: FnArg) -> FnArg {
48 self.args.push(arg.clone());
49 fold_fn_arg(self, arg)
50 }
51
52 fn fold_signature(&mut self, signature: Signature) -> Signature {
53 self.name = Some(format_ident!("{}", signature.ident));
54 let mut new_signature = signature.clone();
55 new_signature.ident = format_ident!("_generated_{}_generated_", signature.ident);
56 self.signature = Some(new_signature);
57 self.signature_raw = Some(signature.clone());
58 fold_signature(self, signature)
59 }
60
61 fn fold_visibility(&mut self, v: Visibility) -> Visibility {
62 self.visibility = v.clone();
63 v
64 }
65
66 fn fold_block(&mut self, node: Block) -> Block {
67 self.block.push(node.clone());
68 node
69 }
70}
71pub enum FunctionKind {
72 Contextless,
73 JsFunction,
74}
75
76pub fn get_execute_js_code(new_fn_name: Ident, function_kind: FunctionKind) -> TokenStream {
77 let return_token_stream = match function_kind {
78 FunctionKind::Contextless => {
79 quote! {
80 Ok(Some(v)) => unsafe {
81 napi::bindgen_prelude::ToNapiValue::to_napi_value(raw_env, v).unwrap_or_else(|e| {
82 napi::JsError::from(e).throw_into(raw_env);
83 ptr::null_mut()
84 })
85 },
86 Ok(None) => ptr::null_mut(),
87 }
88 }
89 FunctionKind::JsFunction => {
90 quote! {
91 Ok(v) => unsafe {
92 napi::bindgen_prelude::ToNapiValue::to_napi_value(raw_env, v).unwrap_or_else(|e| {
93 napi::JsError::from(e).throw_into(raw_env);
94 ptr::null_mut()
95 })
96 },
97 }
98 }
99 };
100 quote! {
101 match panic::catch_unwind(AssertUnwindSafe(move || #new_fn_name(ctx))).map_err(|e| {
102 let message = {
103 if let Some(string) = e.downcast_ref::<String>() {
104 string.clone()
105 } else if let Some(string) = e.downcast_ref::<&str>() {
106 string.to_string()
107 } else {
108 format!("panic from Rust code: {:?}", e)
109 }
110 };
111 Error::from_reason(message)
112 }).and_then(|v| v) {
113 #return_token_stream
114 Err(e) => {
115 unsafe { napi::JsError::from(e).throw_into(raw_env) };
116 ptr::null_mut()
117 }
118 }
119 }
120}
121