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 { v.raw() },
81 Ok(None) => ptr::null_mut(),
82 }
83 }
84 FunctionKind::JsFunction => {
85 quote! {
86 Ok(v) => unsafe { v.raw() },
87 }
88 }
89 };
90 quote! {
91 match panic::catch_unwind(AssertUnwindSafe(move || #new_fn_name(ctx))).map_err(|e| {
92 let message = {
93 if let Some(string) = e.downcast_ref::<String>() {
94 string.clone()
95 } else if let Some(string) = e.downcast_ref::<&str>() {
96 string.to_string()
97 } else {
98 format!("panic from Rust code: {:?}", e)
99 }
100 };
101 Error::from_reason(message)
102 }).and_then(|v| v) {
103 #return_token_stream
104 Err(e) => {
105 unsafe { napi::JsError::from(e).throw_into(raw_env) };
106 ptr::null_mut()
107 }
108 }
109 }
110}
111