sewup_derive/
lib.rs

1#![feature(box_into_inner)]
2extern crate proc_macro;
3
4#[cfg(test)]
5mod function_tests;
6
7use convert_case::{Case::Camel, Casing};
8use fancy_regex::Regex;
9use proc_macro::TokenStream;
10use proc_macro2::{Ident, Span};
11use proc_macro_error::{abort, abort_call_site, proc_macro_error};
12use quote::quote;
13use serde_derive::Deserialize;
14use tiny_keccak::{Hasher, Keccak};
15
16type MayString = Option<String>;
17
18#[derive(Deserialize)]
19#[serde(rename_all = "camelCase")]
20#[allow(dead_code)]
21struct AbiIO {
22    #[serde(skip_serializing_if = "Option::is_none")]
23    internal_type: Option<String>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    name: MayString,
26    r#type: String,
27}
28
29/// Different Contract mode will treat input and output in different
30#[derive(Debug, PartialEq)]
31enum ContractMode {
32    /// Default mode, only return the error message, if any
33    /// This is for a scenario that you just want to modify the data on
34    /// chain only
35    DefaultMode,
36    /// Rusty mode, return serialized binary of `Result<T,E>`, this is good for rust client
37    /// This is for a scenario that you are using a rust client to operation the contract
38    RustyMode,
39    /// Auto mode, return serialize binary for `T` if the Result is Ok, else return the serialize
40    /// binary of E
41    /// This is for a scenario that you take care the result but not using Rust client
42    AutoMode,
43}
44
45/// Options can set in ewasm_main function
46#[allow(dead_code)]
47#[derive(Debug, PartialEq)]
48enum ContractOption {
49    /// The default message that can be used in Default mode and Auto mode
50    DefaultMessage(String),
51}
52
53fn parse_contract_mode_and_options(
54    attr: String,
55) -> Result<(ContractMode, Vec<ContractOption>), &'static str> {
56    let (arg_str, option_str) = match attr.split_once(',') {
57        Some((head, tail)) => (head, tail),
58        None => {
59            if attr.starts_with("default") {
60                ("", attr.as_str())
61            } else {
62                (attr.as_str(), "")
63            }
64        }
65    };
66    let options = if let Ok(Some(cap)) =
67        unsafe { Regex::new(r#"default.*=.*"(?<default>[^"]*)""#).unwrap_unchecked() }
68            .captures(option_str)
69    {
70        let default = unsafe { cap.name("default").unwrap_unchecked() }.as_str();
71        vec![ContractOption::DefaultMessage(default.into())]
72    } else {
73        vec![]
74    };
75    let output = match arg_str {
76        "auto" => (ContractMode::AutoMode, options),
77        "rusty" => {
78            if options.len() != 0 {
79                return Err("can not set default message for rusty mode");
80            }
81            (ContractMode::RustyMode, options)
82        }
83        _ => (ContractMode::DefaultMode, options),
84    };
85    Ok(output)
86}
87
88fn get_function_signature(function_prototype: &str) -> [u8; 4] {
89    let mut sig = [0; 4];
90    let mut hasher = Keccak::v256();
91    hasher.update(function_prototype.as_bytes());
92    hasher.finalize(&mut sig);
93    sig
94}
95
96fn write_function_signature(sig_str: &str) -> String {
97    let re = unsafe { Regex::new(r"^(?P<name>[^(]+?)\((?P<params>[^)]*?)\)").unwrap_unchecked() };
98    if let Ok(Some(cap)) = re.captures(sig_str) {
99        let fn_name = unsafe { cap.name("name").unwrap_unchecked() }.as_str();
100        let params = unsafe { cap.name("params").unwrap_unchecked() }
101            .as_str()
102            .replace(" ", "");
103        let canonical_fn = format!(
104            "{}({})",
105            fn_name,
106            params
107                .split(',')
108                .map(|p| {
109                    let p_split = p.split(':').collect::<Vec<_>>();
110                    if p_split.len() == 2 {
111                        p_split[1]
112                    } else {
113                        p_split[0]
114                    }
115                    .trim()
116                })
117                .collect::<Vec<_>>()
118                .join(",")
119        );
120        format!(r"{:?}", get_function_signature(&canonical_fn))
121    } else {
122        format!(
123            "{}_SIG",
124            sig_str.to_string().replace(" ", "").to_ascii_uppercase()
125        )
126    }
127}
128
129/// helps you setup the main function of a contract
130///
131/// There are three different kind contract output, and the return `Result` can based on
132/// `anyhow::Result` or `std::result::Result`.  If you want to use `std::result::Result`, you need
133/// to set up `default` option with default message in default mode and auto mode, such that there
134/// will be a return message in bytes let you know some error happen.
135///
136/// `#[ewasm_main]`
137/// The default contract output, the Anyhow error will be return as a string message
138/// This is for a scenario that you just want to modify the data on
139/// chain only, and the error will to string than return.
140///
141/// `#[ewasm_main(default="message")]`
142/// The default contract output, if any error happened the default message will be returned
143///
144/// `#[ewasm_main(rusty)]`
145/// The rust style output, the result object from ewasm_main function will be
146/// returned, this is for a scenario that you are using a rust client to catch
147/// and want to catch the result from the contract.
148///
149/// `#[ewasm_main(auto)]`
150/// Auto unwrap the OK output of the Anyhow::Result object from ewasm_main function.
151/// This is for a scenario that you are using a rust non-rust client,
152/// and you are only care the happy case of executing the contract.
153///
154/// `#[ewasm_main(auto, default="message")]`
155/// Auto unwrap the OK output of the result object (it can be `Anyhow::Result`
156/// or `std::result::Result`) from ewasm_main function, if any error happened the default message
157/// will be returned.  This is for a scenario that you are using a rust non-rust client,
158/// and you are only care the happy case of executing the contract.
159///
160/// ```compile_fail
161/// #[ewasm_main]
162/// fn main() -> anyhow::Result<()> {
163///     let contract = Contract::new()?;
164///     match contract.get_function_selector()? {
165///         ewasm_fn_sig!(check_input_object) => ewasm_input_from!(contract move check_input_object)?,
166///         _ => return Err(Error::UnknownHandle.into()),
167///     };
168///     Ok(())
169/// }
170/// ```
171/// ```compile_fail
172/// #[ewasm_main(auto, default = "Some error happen")]
173/// fn main() -> Result<String, ()> {
174///     let contract = sewup::primitives::Contract::new().expect("contract should work");
175///     match contract
176///         .get_function_selector()
177///         .expect("function selector should work")
178///     {
179///         sewup_derive::ewasm_fn_sig!(hello) => hello(),
180///         _ => Err(()),
181///     }
182/// }
183///
184/// ```
185#[proc_macro_error]
186#[proc_macro_attribute]
187pub fn ewasm_main(attr: TokenStream, item: TokenStream) -> TokenStream {
188    let input = syn::parse_macro_input!(item as syn::ItemFn);
189    let name = &input.sig.ident;
190    if !input.sig.inputs.is_empty() {
191        abort!(
192            input.sig.inputs,
193            "ewasm_main only wrap the function without inputs"
194        )
195    }
196
197    let output_type = match input.sig.clone().output {
198        syn::ReturnType::Type(_, boxed) => match Box::into_inner(boxed) {
199            syn::Type::Path(syn::TypePath { path: p, .. }) => {
200                let mut ok_type: Option<String> = None;
201                let mut segments = p.segments;
202                while let Some(pair) = segments.pop() {
203                    ok_type = match pair.into_value() {
204                        syn::PathSegment {
205                            arguments:
206                                syn::PathArguments::AngleBracketed(
207                                    syn::AngleBracketedGenericArguments { args: a, .. },
208                                ),
209                            ..
210                        } => match a.first() {
211                            Some(syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
212                                path: p,
213                                ..
214                            }))) => {
215                                if let Some(syn::PathSegment { ident: i, .. }) = p.segments.last() {
216                                    Some(i.to_string())
217                                } else {
218                                    None
219                                }
220                            }
221                            _ => None,
222                        },
223                        _ => None,
224                    };
225                    if ok_type.is_some() {
226                        break;
227                    }
228                }
229                ok_type
230            }
231            _ => None,
232        },
233        _ => None,
234    };
235
236    let (contract_mode, options) = match parse_contract_mode_and_options(attr.to_string()) {
237        Ok(o) => o,
238        Err(e) => abort_call_site!(e),
239    };
240
241    let mut default_message = None;
242    for option in options.into_iter() {
243        let ContractOption::DefaultMessage(s) = option;
244        default_message = Some(s);
245    }
246
247    match contract_mode {
248        ContractMode::AutoMode if Some("EwasmAny".to_string()) == output_type && default_message.is_some() => quote! {
249            #[cfg(target_arch = "wasm32")]
250            use sewup::bincode;
251            #[cfg(target_arch = "wasm32")]
252            use sewup::ewasm_api::finish_data;
253            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
254            pub fn main() {}
255            #[cfg(target_arch = "wasm32")]
256            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
257            #[no_mangle]
258            pub fn main() {
259                #input
260                match #name() {
261                    Ok(r) =>  {
262                        finish_data(&r.bin);
263                    },
264                    Err(e) => {
265                        finish_data(&#default_message.as_bytes());
266                    }
267                }
268            }
269        },
270        ContractMode::AutoMode if Some("EwasmAny".to_string()) == output_type  => quote! {
271            #[cfg(target_arch = "wasm32")]
272            use sewup::bincode;
273            #[cfg(target_arch = "wasm32")]
274            use sewup::ewasm_api::finish_data;
275            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
276            pub fn main() {}
277            #[cfg(target_arch = "wasm32")]
278            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
279            #[no_mangle]
280            pub fn main() {
281                #input
282                match #name() {
283                    Ok(r) =>  {
284                        finish_data(&r.bin);
285                    },
286                    Err(e) => {
287                        let error_msg = e.to_string();
288                        finish_data(&error_msg.as_bytes());
289                    }
290                }
291            }
292        },
293        ContractMode::AutoMode if default_message.is_some() => quote! {
294            #[cfg(target_arch = "wasm32")]
295            use sewup::bincode;
296            #[cfg(target_arch = "wasm32")]
297            use sewup::ewasm_api::finish_data;
298            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
299            pub fn main() {}
300            #[cfg(target_arch = "wasm32")]
301            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
302            #[no_mangle]
303            pub fn main() {
304                #input
305                match #name() {
306                    Ok(r) =>  {
307                        let bin = bincode::serialize(&r).expect("The resuslt of `ewasm_main` should be serializable");
308                        finish_data(&bin);
309                    },
310                    Err(_) => {
311                        finish_data(&#default_message.as_bytes());
312                    }
313                }
314            }
315        },
316        ContractMode::AutoMode => quote! {
317            #[cfg(target_arch = "wasm32")]
318            use sewup::bincode;
319            #[cfg(target_arch = "wasm32")]
320            use sewup::ewasm_api::finish_data;
321            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
322            pub fn main() {}
323            #[cfg(target_arch = "wasm32")]
324            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
325            #[no_mangle]
326            pub fn main() {
327                #input
328                match #name() {
329                    Ok(r) =>  {
330                        let bin = bincode::serialize(&r).expect("The resuslt of `ewasm_main` should be serializable");
331                        finish_data(&bin);
332                    },
333                    Err(e) => {
334                        let error_msg = e.to_string();
335                        finish_data(&error_msg.as_bytes());
336                    }
337                }
338            }
339        },
340        ContractMode::RustyMode if Some("EwasmAny".to_string()) == output_type  => quote! {
341            #[cfg(target_arch = "wasm32")]
342            use sewup::bincode;
343            #[cfg(target_arch = "wasm32")]
344            use sewup::ewasm_api::finish_data;
345            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
346            pub fn main() {}
347            #[cfg(target_arch = "wasm32")]
348            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
349            #[no_mangle]
350            pub fn main() {
351                #input
352                let r = #name().map(|any| any.bin);
353                let bin = bincode::serialize(&r).expect("The resuslt of `ewasm_main` should be serializable");
354                finish_data(&bin);
355            }
356        },
357        ContractMode::RustyMode => quote! {
358            #[cfg(target_arch = "wasm32")]
359            use sewup::bincode;
360            #[cfg(target_arch = "wasm32")]
361            use sewup::ewasm_api::finish_data;
362            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
363            pub fn main() {}
364            #[cfg(target_arch = "wasm32")]
365            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
366            #[no_mangle]
367            pub fn main() {
368                #input
369                let r = #name();
370                let bin = bincode::serialize(&r).expect("The resuslt of `ewasm_main` should be serializable");
371                finish_data(&bin);
372            }
373        },
374        ContractMode::DefaultMode if default_message.is_some() => quote! {
375            #[cfg(target_arch = "wasm32")]
376            use sewup::bincode;
377            #[cfg(target_arch = "wasm32")]
378            use sewup::ewasm_api::finish_data;
379            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
380            pub fn main() {}
381            #[cfg(target_arch = "wasm32")]
382            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
383            #[no_mangle]
384            pub fn main() {
385                #input
386                if let Err(e) = #name() {
387                    finish_data(#default_message.as_bytes());
388                }
389            }
390        },
391        ContractMode::DefaultMode => quote! {
392            #[cfg(target_arch = "wasm32")]
393            use sewup::bincode;
394            #[cfg(target_arch = "wasm32")]
395            use sewup::ewasm_api::finish_data;
396            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
397            pub fn main() {}
398            #[cfg(target_arch = "wasm32")]
399            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
400            #[no_mangle]
401            pub fn main() {
402                #input
403                if let Err(e) = #name() {
404                    let error_msg = e.to_string();
405                    finish_data(&error_msg.as_bytes());
406                }
407            }
408        }
409    }.into()
410}
411
412fn parse_fn_attr(
413    fn_name: String,
414    attr: String,
415) -> Result<(Option<String>, String, Option<String>), &'static str> {
416    let attr_str = attr.replace(" ", "").replace("\n", "");
417    return if attr_str.is_empty() {
418        Ok((None, "{}".into(), None))
419    } else if let Some((head, tail)) = attr_str.split_once(',') {
420        if tail.is_empty() {
421            Ok((Some(head.replace("\"", "")), "{}".into(), None))
422        } else {
423            let root_str = if let Ok(Some(cap)) =
424                unsafe { Regex::new(r"only_by=(?P<account>[^,]*)").unwrap_unchecked() }
425                    .captures(&attr_str)
426            {
427                Some(
428                    unsafe { cap.name("account").unwrap_unchecked() }
429                        .as_str()
430                        .into(),
431                )
432            } else {
433                None
434            };
435
436            let mut json = "{".to_string();
437            if let Ok(Some(cap)) =
438                unsafe { Regex::new(r"constant=(?P<constant>[^,]*)").unwrap_unchecked() }
439                    .captures(&attr_str)
440            {
441                match unsafe { cap.name("constant").unwrap_unchecked() }.as_str() {
442                    "true" => json.push_str(r#""constant":true,"#),
443                    "false" => json.push_str(r#""constant":false,"#),
444                    _ => return Err("constacnt should be true or false"),
445                }
446            } else {
447                json.push_str(r#""constant":false,"#)
448            }
449
450            if let Ok(Some(cap)) =
451                unsafe { Regex::new(r#"inputs=(?<inputs>\[.*?\])(?!")"#).unwrap_unchecked() }
452                    .captures(&attr_str)
453            {
454                json.push_str(r#""inputs":"#);
455                let inputs_str = unsafe { cap.name("inputs").unwrap_unchecked() }.as_str();
456                for cap in Regex::new(r"\{[^\{\}]*\}").unwrap().find_iter(inputs_str) {
457                    if let Ok(input_cap) = cap {
458                        if serde_json::from_str::<AbiIO>(input_cap.as_str()).is_err() {
459                            return Err("inputs are not valid format");
460                        }
461                    }
462                }
463                json.push_str(inputs_str);
464                json.push(',');
465            } else {
466                json.push_str(r#""inputs":[],"#);
467            }
468
469            if let Ok(Some(cap)) = unsafe { Regex::new(r"name=(?P<name>[^,]*)").unwrap_unchecked() }
470                .captures(&attr_str)
471            {
472                json.push_str(r#""name":""#);
473                json.push_str(unsafe { cap.name("name").unwrap_unchecked() }.as_str());
474                json.push_str(r#"","#);
475            } else {
476                json.push_str(&format!(r#""name":"{}","#, fn_name.to_case(Camel)));
477            }
478
479            if let Ok(Some(cap)) =
480                unsafe { Regex::new(r#"outputs=(?<outputs>\[.*?\])(?!")"#).unwrap_unchecked() }
481                    .captures(&attr_str)
482            {
483                json.push_str(r#""outputs":"#);
484                let outputs_str = unsafe { cap.name("outputs").unwrap_unchecked() }.as_str();
485                for cap in Regex::new(r"\{[^\{\}]*\}").unwrap().find_iter(outputs_str) {
486                    if let Ok(output_cap) = cap {
487                        if serde_json::from_str::<AbiIO>(output_cap.as_str()).is_err() {
488                            return Err("outputs are not valid format");
489                        }
490                    }
491                }
492                json.push_str(outputs_str);
493                json.push(',');
494            } else {
495                json.push_str(r#""outputs":[],"#);
496            }
497
498            if let Ok(Some(cap)) =
499                unsafe { Regex::new(r"payable=(?P<payable>[^,]*)").unwrap_unchecked() }
500                    .captures(&attr_str)
501            {
502                match unsafe { cap.name("payable").unwrap_unchecked() }.as_str() {
503                    "true" => json.push_str(r#""payable":true,"#),
504                    "false" => json.push_str(r#""payable":false,"#),
505                    _ => return Err("payable should be true or false"),
506                }
507            } else {
508                json.push_str(r#""payable":false,"#);
509            }
510
511            if let Ok(Some(cap)) = unsafe {
512                Regex::new(r"stateMutability=(?P<stateMutability>[^,]*)").unwrap_unchecked()
513            }
514            .captures(&attr_str)
515            {
516                match unsafe { cap.name("stateMutability").unwrap_unchecked() }.as_str() {
517                    "nonpayable" => json.push_str(r#""stateMutability":"nonpayable","#),
518                    "view" => json.push_str(r#""stateMutability":"view","#),
519                    _ => return Err("stateMutability should be nonpayable or view"),
520                }
521            } else {
522                json.push_str(r#""stateMutability":"view","#);
523            }
524
525            json.push_str(r#""type":"function"}"#);
526            if head.starts_with("only_by") {
527                Ok((None, json, root_str))
528            } else {
529                Ok((Some(head.replace("\"", "")), json, root_str))
530            }
531        }
532    } else if let Ok(Some(cap)) =
533        unsafe { Regex::new(r"only_by=(?P<account>[^,]*)").unwrap_unchecked() }.captures(&attr_str)
534    {
535        Ok((
536            None,
537            "{}".into(),
538            Some(
539                unsafe { cap.name("account").unwrap_unchecked() }
540                    .as_str()
541                    .into(),
542            ),
543        ))
544    } else {
545        Ok((Some(attr_str.replace("\"", "")), "{}".into(), None))
546    };
547}
548
549/// helps you to build your handlers in the contract
550///
551/// This macro also generate the function signature, you can use
552/// `ewasm_fn_sig!` macro to get your function signature;
553///
554/// ```compile_fail
555/// #[ewasm_fn]
556/// fn check_input_object(s: SimpleStruct) -> anyhow::Result<()> {
557///     Ok(())
558/// }
559///
560/// #[ewasm_main]
561/// fn main() -> Result<()> {
562///     let contract = Contract::new()?;
563///     match contract.get_function_selector()? {
564///         ewasm_fn_sig!(check_input_object) => ewasm_input_from!(contract move check_input_object)?,
565///         _ => return Err(Error::UnknownHandle.into()),
566///     };
567///     Ok(())
568/// }
569/// ```
570///
571/// There are two kind of inputs for `ewasm_fn` macro, first is functional signature, second and
572/// more are the fields of abijson.
573/// The functional signature can be specific as following ways.
574/// `#[ewasm_fn(00fdd58e)]` or #[ewasm_fn("00fdd58e")]
575///
576/// ```compile_fail
577/// #[ewasm_fn(00fdd58e,
578/// constant=true,
579/// inputs=[
580///     { "internalType": "address", "name": "account", "type": "address" },
581///     { "internalType": "uint256", "name": "token_id", "type": "uint256" }
582/// ],
583/// name=balanceOf,
584/// outputs=[
585///     { "internalType": "uint256", "name": "", "type": "uint256" }
586/// ],
587/// payable=false,
588/// stateMutability=view
589/// )]
590/// ```
591/// The fields are not required, it can use default value if not provided.
592/// The default values of `constant`, `payable` are `false`; the default values of `inputs` and
593/// `outputs` are `[]`; the default value of `stateMutability` is `view`; the default name is the
594/// camel case style of the function name.
595///
596/// The handler also can be restricted by called special account with `only_by` attribute,
597/// following are examples:
598/// ```compile_fail
599/// #[ewasm_fn(only_by=8663DBF0cC68AaF37fC8BA262F2df4c666a41993)]
600/// #[ewasm_fn(only_by="0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993")]
601/// #[ewasm_fn(only_by=0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993)]
602/// #[ewasm_fn(only_by="8663DBF0cC68AaF37fC8BA262F2df4c666a41993")]
603/// ```
604#[proc_macro_error]
605#[proc_macro_attribute]
606pub fn ewasm_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
607    let syn::ItemFn {
608        attrs,
609        vis,
610        sig,
611        block,
612    } = syn::parse_macro_input!(item as syn::ItemFn);
613    let syn::Block { stmts, .. } = *block;
614
615    let name = &sig.ident;
616
617    let (hex_str, abi_str, root_str) = match parse_fn_attr(name.to_string(), attr.to_string()) {
618        Ok(o) => o,
619        Err(e) => abort_call_site!(e),
620    };
621
622    let args = &sig
623        .inputs
624        .iter()
625        .map(|fn_arg| match fn_arg {
626            syn::FnArg::Receiver(r) => {
627                abort!(r, "please use ewasm_fn for function not method")
628            }
629            syn::FnArg::Typed(p) => Box::into_inner(p.ty.clone()),
630        })
631        .map(|ty| match ty {
632            syn::Type::Path(tp) => (
633                tp.path
634                    .segments
635                    .first()
636                    .expect("at least one segment")
637                    .ident
638                    .clone(),
639                false,
640            ),
641            syn::Type::Reference(tr) => match Box::into_inner(tr.elem) {
642                syn::Type::Path(tp) => (
643                    tp.path
644                        .segments
645                        .first()
646                        .expect("at least one segment")
647                        .ident
648                        .clone(),
649                    true,
650                ),
651                _ => abort_call_site!("please pass Path type or Reference type to ewasm_fn_sig"),
652            },
653            _ => abort_call_site!("please pass Path type or Reference type to ewasm_fn_sig"),
654        })
655        .map(|(ident, is_ref)| {
656            if is_ref {
657                format!("&{}", ident).to_ascii_lowercase()
658            } else {
659                format!("{}", ident).to_ascii_lowercase()
660            }
661        })
662        .collect::<Vec<_>>()
663        .join(",");
664    let canonical_fn = format!("{}({})", name, args);
665    let (sig_0, sig_1, sig_2, sig_3) = if let Some(hex_str) = hex_str {
666        let fn_sig = hex::decode(hex_str).expect("function signature is not correct");
667        (fn_sig[0], fn_sig[1], fn_sig[2], fn_sig[3])
668    } else {
669        let fn_sig = get_function_signature(&canonical_fn);
670        (fn_sig[0], fn_sig[1], fn_sig[2], fn_sig[3])
671    };
672    let abi_info = Ident::new(
673        &format!("{}_ABI", name.to_string().to_ascii_uppercase()),
674        Span::call_site(),
675    );
676    let sig_name = Ident::new(
677        &format!("{}_SIG", name.to_string().to_ascii_uppercase()),
678        Span::call_site(),
679    );
680    let result = if let Some(root_str) = root_str {
681        let addr = root_str.replace("\"", "");
682        quote! {
683            pub const #sig_name : [u8; 4] = [#sig_0, #sig_1, #sig_2, #sig_3];
684            pub(crate) const #abi_info: &'static str = #abi_str;
685
686            #[cfg(target_arch = "wasm32")]
687            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
688            #(#attrs)*
689            #vis #sig {
690                if sewup::utils::caller() != sewup::types::Address::from_str(#addr)? {
691                    return Err(sewup::errors::HandlerError::Unauthorized.into())
692                }
693                #(#stmts)*
694            }
695        }
696    } else {
697        quote! {
698            pub const #sig_name : [u8; 4] = [#sig_0, #sig_1, #sig_2, #sig_3];
699            pub(crate) const #abi_info: &'static str = #abi_str;
700
701            #[cfg(target_arch = "wasm32")]
702            #[cfg(not(any(feature = "constructor", feature = "constructor-test")))]
703            #(#attrs)*
704            #vis #sig {
705                #(#stmts)*
706            }
707        }
708    };
709    result.into()
710}
711
712/// helps you to build your constructor for the contract
713#[proc_macro_error]
714#[proc_macro_attribute]
715pub fn ewasm_constructor(_attr: TokenStream, item: TokenStream) -> TokenStream {
716    let mut input = syn::parse_macro_input!(item as syn::ItemFn);
717    let default_name = Ident::new("__constructor", Span::call_site());
718    if input.sig.ident != "__constructor" {
719        input.sig.ident = default_name;
720    }
721    let result = quote! {
722        #[cfg(target_arch = "wasm32")]
723        #[cfg(any(feature = "constructor", feature = "constructor-test"))]
724        #[no_mangle]
725        #input
726
727        #[cfg(target_arch = "wasm32")]
728        #[cfg(feature = "constructor-test")]
729        #[no_mangle]
730        pub fn main() {
731            __constructor();
732        }
733    };
734    result.into()
735}
736
737/// helps you to build your handler in other module
738///
739/// This macro will automatically generated as `{FUNCTION_NAME}_SIG`
740///
741/// ```compile_fail
742/// // module.rs
743///
744/// use sewup::ewasm_api;
745///
746/// #[ewasm_lib_fn]
747/// pub fn symbol(s: &str) {
748///     let symbol = s.to_string().into_bytes();
749///     ewasm_api::finish_data(&symbol);
750/// }
751/// ```
752///
753/// ```compile_fail
754/// // lib.rs
755///
756/// use module::{symbol, SYMBOL_SIG};
757///
758/// #[ewasm_main]
759/// fn main() -> Result<()> {
760///     let contract = Contract::new()?;
761///     match contract.get_function_selector()? {
762///         SYMBOL_SIG => symbol("ETD"),
763///         _ => return Err(Error::UnknownHandle.into()),
764///     };
765///     Ok(())
766/// }
767/// ```
768///
769/// There are two kind of inputs for `ewasm_fn` macro, first is functional signature, second and
770/// more are the fields of abijson.
771/// The functional signature can be specific as following ways.
772/// `#[ewasm_lib_fn(00fdd58e)]` or #[ewasm_lib_fn("00fdd58e")]
773///
774/// ``` #[ewasm_lib_fn(00fdd58e,
775/// constant=true,
776/// inputs=[
777///     { "internalType": "address", "name": "account", "type": "address" },
778///     { "internalType": "uint256", "name": "token_id", "type": "uint256" }
779/// ],
780/// name=balanceOf,
781/// outputs=[
782///     { "internalType": "uint256", "name": "", "type": "uint256" }
783/// ],
784/// payable=false,
785/// stateMutability=view
786/// )]
787/// ```
788/// The fields are not required, it can use default value if not provided.
789/// The default values of `constant`, `payable` are `false`; the default values of `inputs` and
790/// `outputs` are `[]`; the default value of `stateMutability` is `view`; the default name is the
791/// camel case style of the function name.
792///
793#[proc_macro_error]
794#[proc_macro_attribute]
795pub fn ewasm_lib_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
796    let input = syn::parse_macro_input!(item as syn::ItemFn);
797    let name = &input.sig.ident;
798
799    let (hex_str, abi_str, _root_str) = match parse_fn_attr(name.to_string(), attr.to_string()) {
800        Ok(o) => o,
801        Err(e) => abort_call_site!(e),
802    };
803
804    let inputs = &input.sig.inputs;
805
806    let (sig_0, sig_1, sig_2, sig_3) = if let Some(hex_str) = hex_str {
807        let fn_sig = hex::decode(hex_str).expect("function signature is not correct");
808        (fn_sig[0], fn_sig[1], fn_sig[2], fn_sig[3])
809    } else {
810        let args = &inputs
811            .iter()
812            .map(|fn_arg| match fn_arg {
813                syn::FnArg::Receiver(r) => {
814                    abort!(r, "please use ewasm_fn for function not method")
815                }
816                syn::FnArg::Typed(p) => Box::into_inner(p.ty.clone()),
817            })
818            .map(|ty| match ty {
819                syn::Type::Path(tp) => (
820                    tp.path
821                        .segments
822                        .first()
823                        .expect("at least one segment")
824                        .ident
825                        .clone(),
826                    false,
827                ),
828                syn::Type::Reference(tr) => match Box::into_inner(tr.elem) {
829                    syn::Type::Path(tp) => (
830                        tp.path
831                            .segments
832                            .first()
833                            .expect("at least one segment")
834                            .ident
835                            .clone(),
836                        true,
837                    ),
838                    _ => {
839                        abort_call_site!("please pass Path type or Reference type to ewasm_fn_sig")
840                    }
841                },
842                _ => abort_call_site!("please pass Path type or Reference type to ewasm_fn_sig"),
843            })
844            .map(|(ident, is_ref)| {
845                if is_ref {
846                    format!("&{}", ident).to_ascii_lowercase()
847                } else {
848                    format!("{}", ident).to_ascii_lowercase()
849                }
850            })
851            .collect::<Vec<_>>()
852            .join(",");
853        let canonical_fn = format!("{}({})", name, args);
854        let fn_sig = get_function_signature(&canonical_fn);
855        (fn_sig[0], fn_sig[1], fn_sig[2], fn_sig[3])
856    };
857    let sig_name = Ident::new(
858        &format!("{}_SIG", name.to_string().to_ascii_uppercase()),
859        Span::call_site(),
860    );
861    let abi_info = Ident::new(
862        &format!("{}_ABI", name.to_string().to_ascii_uppercase()),
863        Span::call_site(),
864    );
865    let result = quote! {
866        pub const #sig_name: [u8; 4] = [#sig_0, #sig_1, #sig_2, #sig_3];
867        pub const #abi_info: &'static str = #abi_str;
868
869        #[cfg(not(target_arch = "wasm32"))]
870        #[allow(unused)]
871        pub fn #name(#inputs) {}
872
873        #[cfg(target_arch = "wasm32")]
874        #input
875    };
876    result.into()
877}
878
879/// helps you get you function signature
880///
881/// 1. provide function name to get function signature from the same namespace,
882/// which function should be decorated with `#[ewasm_fn]`, for example,
883/// `ewasm_fn_sig!(contract_handler)`
884///
885/// ```compile_fail
886/// #[ewasm_fn]
887/// fn decorated_handler(a: i32, b: String) -> Result<()> {
888///     Ok(())
889/// }
890///
891/// #[ewasm_main]
892/// fn main() -> Result<()> {
893///     let contract = Contract::new()?;
894///     match contract.get_function_selector()? {
895///         ewasm_fn_sig!(decorated_handler) => ewasm_input_from!(contract move decorated_handler)?,
896///         _ => return Err(Error::UnknownHandle.into()),
897///     };
898///     Ok(())
899/// }
900/// ```
901///
902/// 2. provide a function name with input parameters then the macro will
903/// calculate the correct functional signature for you.
904/// ex: `ewasm_fn_sig!(undecorated_handler( a: i32, b: String ))`
905///
906/// ```compile_fail
907/// // some_crate.rs
908/// pub fn decorated_handler(a: i32, b: String) -> Result<()> {
909///     Ok(())
910/// }
911/// ```
912///
913/// ```compile_fail
914/// use some_crate::decorated_handler;
915///
916/// #[ewasm_main]
917/// fn main() -> Result<()> {
918///     let contract = Contract::new()?;
919///     match contract.get_function_selector()? {
920///         ewasm_fn_sig!(undecorated_handler(a: i32, b: String))
921///             => ewasm_input_from!(contract move undecorated_handler)?,
922///         _ => return Err(Error::UnknownHandle.into()),
923///     };
924///     Ok(())
925/// }
926/// ```
927///
928#[proc_macro_error]
929#[proc_macro]
930pub fn ewasm_fn_sig(item: TokenStream) -> TokenStream {
931    write_function_signature(&item.to_string())
932        .parse()
933        .expect("can not generate function signature")
934}
935
936/// helps you generate the input raw data for specific contract handler
937/// ```compile_fail
938/// let create_input = person::protocol(person.clone());
939/// let mut input = ewasm_input!(create_input for person::create);
940/// ```
941#[proc_macro]
942pub fn ewasm_input(item: TokenStream) -> TokenStream {
943    let re = unsafe { Regex::new(r"(?P<instance>.*)\s+for\s+(?P<sig>.*)").unwrap_unchecked() };
944    if let Ok(Some(cap)) = re.captures(&item.to_string()) {
945        let sig = unsafe { cap.name("sig").unwrap_unchecked() }.as_str();
946        let instance = unsafe { cap.name("instance").unwrap_unchecked() }.as_str();
947        let output = if instance == "None" {
948            format!("{}.to_vec()", write_function_signature(sig),)
949        } else {
950            format!(
951                "{{
952                let mut input = {}.to_vec();
953                input.append(&mut bincode::serialize(&{}).unwrap());
954                input
955            }}",
956                write_function_signature(sig),
957                instance
958            )
959        };
960        output.parse().expect("ewasm input transform unexpected")
961    } else {
962        panic!("ewasm_input input incorrect")
963    }
964}
965
966/// helps you to get the input data from contract caller
967///
968/// This macro automatically deserialize input into handler
969/// `ewasm_input_from!(contract, the_name_of_the_handler)`
970/// ```compile_fail
971/// #[ewasm_main]
972/// fn main() -> Result<()> {
973///     let contract = Contract::new()?;
974///     match contract.get_function_selector()? {
975///         ewasm_fn_sig!(check_input_object) => ewasm_input_from!(contract move check_input_object)?,
976///         _ => return Err(Error::UnknownHandle.into()),
977///     };
978///  Ok(())
979///  }
980/// ```
981///
982/// Besides, you can map the error to your customized error when something wrong happened in
983/// `ewasm_input_from!`, for example:
984/// `ewasm_input_from!(contract move check_input_object, |_| Err("DeserdeError"))`
985/// ```compile_fail
986/// #[ewasm_main(rusty)]
987/// fn main() -> Result<(), &'static str> {
988///     let contract = Contract::new().map_err(|_| "NewContractError")?;
989///     match contract.get_function_selector().map_err(|_| "FailGetFnSelector")? {
990///         ewasm_fn_sig!(check_input_object) =>  ewasm_input_from!(contract move check_input_object, |_| "DeserdeError")?
991///         _ => return Err("UnknownHandle"),
992///     };
993///     Ok(())
994/// }
995/// ```
996#[proc_macro_error]
997#[proc_macro]
998pub fn ewasm_input_from(item: TokenStream) -> TokenStream {
999    let re = unsafe {
1000        Regex::new(r"^(?P<contract>\w+)\s+move\s+(?P<name>[^,]+),?(?P<error_handler>.*)")
1001            .unwrap_unchecked()
1002    };
1003    if let Ok(Some(cap)) = re.captures(&item.to_string()) {
1004        let contract = Ident::new(
1005            unsafe { cap.name("contract").unwrap_unchecked() }.as_str(),
1006            Span::call_site(),
1007        );
1008        let name_result: syn::Result<syn::ExprPath> =
1009            syn::parse_str(unsafe { cap.name("name").unwrap_unchecked() }.as_str());
1010        let name = if let Ok(name) = name_result {
1011            name
1012        } else {
1013            abort_call_site!(
1014                "`{}` is not an ExprPath",
1015                unsafe { cap.name("name").unwrap_unchecked() }.as_str()
1016            );
1017        };
1018        let error_handler = unsafe { cap.name("error_handler").unwrap_unchecked() }.as_str();
1019        return if error_handler.is_empty() {
1020            quote! {
1021                #name(sewup::bincode::deserialize(&#contract.input_data[4..])
1022                      .map_err(|e| anyhow::anyhow!("contract input deserialize error: {}", e))?
1023                )
1024            }
1025        } else {
1026            let closure: syn::Result<syn::ExprClosure> = syn::parse_str(error_handler);
1027            if let Ok(closure) = closure {
1028                quote! {
1029                    #name(sewup::bincode::deserialize(&#contract.input_data[4..]).map_err(#closure)?)
1030                }
1031            } else {
1032                abort_call_site!("`{}` is not an closure input for map_err", error_handler);
1033            }
1034        }
1035        .into();
1036    } else {
1037        abort_call_site!(
1038            r#"fail to parsing ewasm_input_from,
1039            please use
1040                `ewasm_input_from( contract move handler )
1041            or
1042                `ewasm_input_from( contract move handler, closure_for_map_err)`
1043            "#
1044        );
1045    }
1046}
1047
1048/// help you generate the exactly contract output form rust instance
1049#[proc_macro]
1050pub fn ewasm_output_from(item: TokenStream) -> TokenStream {
1051    format!(
1052        r#"sewup::bincode::serialize(&{}).expect("fail to serialize in `ewasm_output_from`")"#,
1053        item,
1054    )
1055    .parse()
1056    .expect("ewasm output format unexpected")
1057}
1058
1059/// `Key` derive help you implement Key trait for the kv feature
1060///
1061/// ```
1062/// use sewup_derive::Key;
1063/// #[derive(Key)]
1064/// struct SimpleStruct {
1065///     trust: bool,
1066///     description: String,
1067/// }
1068/// ```
1069#[cfg(feature = "kv")]
1070#[proc_macro_derive(Key)]
1071pub fn derive_key(item: TokenStream) -> TokenStream {
1072    let input = syn::parse_macro_input!(item as syn::DeriveInput);
1073    let sturct_name = &input.ident;
1074    return quote! {
1075        #[cfg(target_arch = "wasm32")]
1076        impl sewup::kv::traits::Key for #sturct_name {}
1077    }
1078    .into();
1079}
1080
1081/// `Value` derive help you implement Value trait for kv feature
1082///
1083/// ```
1084/// use sewup_derive::Value;
1085/// #[derive(Value)]
1086/// struct SimpleStruct {
1087///     trust: bool,
1088///     description: String,
1089/// }
1090/// ```
1091#[cfg(feature = "kv")]
1092#[proc_macro_derive(Value)]
1093pub fn derive_value(item: TokenStream) -> TokenStream {
1094    let input = syn::parse_macro_input!(item as syn::DeriveInput);
1095    let sturct_name = &input.ident;
1096    return quote! {
1097        #[cfg(target_arch = "wasm32")]
1098        impl sewup::kv::traits::Value for #sturct_name {}
1099    }
1100    .into();
1101}
1102
1103/// provides the handers for CRUD and the Protocol struct to communicate with these handlers.
1104///
1105/// ```compile_fail
1106/// use sewup_derive::Table;
1107/// #[derive(Table)]
1108/// struct Person {
1109///     trusted: bool,
1110///     age: u8,
1111/// }
1112/// ```
1113///
1114/// The crud handlers are generated as `{struct_name}::get`, `{struct_name}::create`,
1115/// `{struct_name}::update`, `{struct_name}::delete`, you can easily used these handlers as
1116/// following example.
1117///
1118/// ```compile_fail
1119/// #[ewasm_main]
1120/// fn main() -> Result<()> {
1121///     let mut contract = Contract::new()?;
1122///
1123///     match contract.get_function_selector()? {
1124///         ewasm_fn_sig!(person::get) => ewasm_input_from!(contract move person::get)?,
1125///         ewasm_fn_sig!(person::create) => ewasm_input_from!(contract move person::create)?,
1126///         ewasm_fn_sig!(person::update) => ewasm_input_from!(contract move person::update)?,
1127///         ewasm_fn_sig!(person::delete) => ewasm_input_from!(contract move person::delete)?,
1128///         _ => return Err(RDBError::UnknownHandle.into()),
1129///     }
1130///
1131///     Ok(())
1132/// }
1133/// ```
1134///
1135/// The protocol is the input and also the output format of these handlers, besides these handlers
1136/// are easy to build by the `{struct_name}::protocol`, `{struct_name}::Protocol`, and use `set_id`
1137/// for specify the record you want to modify.
1138/// for examples.
1139///
1140/// ```compile_fail
1141/// let handler_input = person::protocol(person);
1142/// let mut default_person_input: person::Protocol = Person::default().into();
1143/// default_input.set_id(2);
1144/// ```
1145///
1146/// you can use `ewasm_output_from!` to get the exactly input/output binary of the protol, for
1147/// example:
1148/// ```compile_fail
1149/// let handler_input = person::protocol(person);
1150/// ewasm_output_from!(handler_input)
1151/// ```
1152///
1153/// Please note that the protocol default and the protocol for default instance may be different.
1154/// This base on the implementation of the default trait of the structure.
1155///
1156/// ```compile_fail
1157/// let default_input = person::Protocol::default();
1158/// let default_person_input: person::Protocol = Person::default().into();
1159/// assert!(default_input != default_person_input)
1160/// ```
1161///
1162/// The relation can be set with `#[belongs_to(Person)]` or `#[belongs_none_or(Person)]`
1163/// ```compile_fail
1164/// #[derive(Table, Default, Clone, PartialEq, Serialize, Deserialize)]
1165/// #[belongs_none_or(Location)]
1166/// pub struct Person {
1167///     pub trusted: bool,
1168///     pub age: u8,
1169///     pub location_id: Option<usize>,
1170/// }
1171///
1172/// #[derive(Table, Default, Clone, PartialEq, Serialize, Deserialize)]
1173/// #[belongs_to(Person)]
1174/// pub struct Post {
1175///     pub content: SizedString!(50),
1176///
1177///     // Currently, this field need to set up manually, this will be enhance later
1178///     pub person_id: usize,
1179/// }
1180///
1181/// #[derive(Table, Default, Clone, PartialEq, Serialize, Deserialize)]
1182/// pub struct Location {
1183///     pub address: Raw,
1184/// }
1185/// ```
1186/// After the directive setup, you can use `table_name.another_table_name` to get the related
1187/// instance, for example
1188/// ```compile_fail
1189/// let person: Person = post.person()?;
1190/// let home: Option<Location> = person.location()?;
1191/// ```
1192#[cfg(feature = "rdb")]
1193#[proc_macro_derive(Table, attributes(belongs_to, belongs_none_or))]
1194pub fn derive_table(item: TokenStream) -> TokenStream {
1195    let input = syn::parse_macro_input!(item as syn::DeriveInput);
1196    let attrs = &input.attrs;
1197    let mut belongs_to: Option<String> = None;
1198    let mut belongs_none_or: Option<String> = None;
1199    for a in attrs.iter() {
1200        let syn::Attribute { path, tokens, .. } = a;
1201        let attr_name = path.segments.first().map(|s| s.ident.to_string());
1202        if Some("belongs_to".to_string()) == attr_name {
1203            belongs_to = Some(
1204                tokens
1205                    .to_string()
1206                    .strip_prefix('(')
1207                    .expect("#[belongs_to(table_name)] is not correct")
1208                    .strip_suffix(')')
1209                    .expect("#[belongs_to(table_name)] is not correct")
1210                    .to_string(),
1211            );
1212        }
1213        if Some("belongs_none_or".to_string()) == attr_name {
1214            belongs_none_or = Some(
1215                tokens
1216                    .to_string()
1217                    .strip_prefix('(')
1218                    .expect("#[belongs_none_or(table_name)] is not correct")
1219                    .strip_suffix(')')
1220                    .expect("#[belongs_none_or(table_name)] is not correct")
1221                    .to_string(),
1222            );
1223        }
1224    }
1225    let struct_name = &input.ident;
1226    let fields_with_type = match &input.data {
1227        syn::Data::Struct(syn::DataStruct {
1228            fields: syn::Fields::Named(f),
1229            ..
1230        }) => f
1231            .clone()
1232            .named
1233            .into_pairs()
1234            .map(|p| p.into_value())
1235            .map(|f| (f.ident.unwrap(), f.ty))
1236            .collect::<Vec<_>>(),
1237        _ => abort!(&input.ident, "Table derive only use for struct"),
1238    };
1239
1240    let mut wrapper_fields = vec![(
1241        Ident::new("id", Span::call_site()),
1242        syn::Type::Path(syn::TypePath {
1243            qself: None,
1244            path: syn::parse("Option<usize>".parse().unwrap()).unwrap(),
1245        }),
1246    )];
1247    wrapper_fields.append(
1248        &mut fields_with_type
1249            .iter()
1250            .map(|(f, t)| {
1251                (
1252                    f.clone(),
1253                    syn::parse(quote!(Option<#t>).to_string().parse().unwrap()).unwrap(),
1254                )
1255            })
1256            .collect::<Vec<_>>(),
1257    );
1258    let wrapper_field_names = wrapper_fields.iter().map(|(f, _)| f);
1259    let wrapper_field_types = wrapper_fields.iter().map(|(_, t)| t);
1260    let field_names = fields_with_type.iter().map(|(f, _)| f);
1261    let clone_field_names = field_names.clone();
1262    let clone_field_names2 = field_names.clone();
1263    let clone_field_names3 = field_names.clone();
1264    let clone_field_names4 = field_names.clone();
1265    let clone_field_names5 = field_names.clone();
1266    let field_types = fields_with_type.iter().map(|(_, t)| t);
1267
1268    let protocol_name = Ident::new(&format!("{}Protocol", struct_name), Span::call_site());
1269    let wrapper_name = Ident::new(&format!("{}Wrapper", struct_name), Span::call_site());
1270    let captal_name = Ident::new(
1271        &format!("{}", struct_name).to_ascii_uppercase(),
1272        Span::call_site(),
1273    );
1274    let lower_name = Ident::new(
1275        &format!("{}", struct_name).to_ascii_lowercase(),
1276        Span::call_site(),
1277    );
1278    let mut output = quote!(
1279        impl sewup::rdb::traits::Record for #struct_name {}
1280
1281        #[cfg_attr(any(feature = "debug", test), derive(Debug))]
1282        #[derive(Clone, sewup::Serialize, sewup::Deserialize)]
1283        pub struct #protocol_name {
1284            pub select_fields: Option<std::collections::HashSet::<String>>,
1285            pub filter: bool,
1286            pub records: Vec<#wrapper_name>
1287        }
1288
1289        impl #protocol_name {
1290            pub fn set_select_fields(&mut self, fields: Vec<String>) {
1291                if fields.is_empty() {
1292                    self.select_fields = None;
1293                } else {
1294                    let mut select_fields = std::collections::HashSet::<String>::new();
1295                    for field in fields.iter() {
1296                        select_fields.insert(field.into());
1297                    }
1298                    self.select_fields = Some(select_fields);
1299                }
1300            }
1301        }
1302
1303        impl Default for #protocol_name {
1304            fn default() -> Self {
1305                Self {
1306                    select_fields: None,
1307                    filter: false,
1308                    records: vec![Default::default()]
1309                }
1310            }
1311        }
1312
1313        impl From<#struct_name> for #protocol_name {
1314            fn from(instance: #struct_name) -> Self {
1315                Self {
1316                    select_fields: None,
1317                    filter: false,
1318                    records: vec![instance.into()]
1319                }
1320            }
1321        }
1322
1323        impl From<(usize, #struct_name)> for #protocol_name {
1324            fn from(instance: (usize, #struct_name)) -> Self {
1325                Self {
1326                    select_fields: None,
1327                    filter: false,
1328                    records: vec![instance.into()]
1329                }
1330            }
1331        }
1332
1333        impl From<Vec<#struct_name>> for #protocol_name {
1334            fn from(instances: Vec<#struct_name>) -> Self {
1335                Self {
1336                    select_fields: None,
1337                    filter: false,
1338                    records: instances.into_iter().map(|i| i.into()).collect::<Vec<_>>()
1339                }
1340            }
1341        }
1342
1343        impl From<Vec<(usize, #struct_name)>> for #protocol_name {
1344            fn from(instances: Vec<(usize, #struct_name)>) -> Self {
1345                Self {
1346                    select_fields: None,
1347                    filter: false,
1348                    records: instances.into_iter().map(|i| i.into()).collect::<Vec<_>>()
1349                }
1350            }
1351        }
1352
1353        impl From<Vec<#wrapper_name>> for #protocol_name {
1354            fn from(records: Vec<#wrapper_name>) -> Self {
1355                Self {
1356                    select_fields: None,
1357                    filter: false,
1358                    records,
1359                }
1360            }
1361        }
1362
1363        pub mod #captal_name {
1364            use sewup_derive::ewasm_fn_sig;
1365            pub const GET_SIG: [u8; 4] = ewasm_fn_sig!(#struct_name::get());
1366            pub const CREATE_SIG: [u8; 4] = ewasm_fn_sig!(#struct_name::create());
1367            pub const UPDATE_SIG: [u8; 4] = ewasm_fn_sig!(#struct_name::update());
1368            pub const DELETE_SIG: [u8; 4] = ewasm_fn_sig!(#struct_name::delete());
1369        }
1370
1371        #[cfg_attr(any(feature = "debug", test), derive(Debug))]
1372        #[derive(Default, Clone, sewup::Serialize, sewup::Deserialize)]
1373        pub struct #wrapper_name {
1374            #(pub #wrapper_field_names: #wrapper_field_types,)*
1375        }
1376
1377        impl From<#struct_name> for #wrapper_name {
1378            fn from(instance: #struct_name) -> Self {
1379                Self {
1380                    id: None,
1381                    #(#field_names: Some(instance.#field_names),)*
1382                }
1383            }
1384        }
1385
1386        impl From<(usize, #struct_name)> for #wrapper_name {
1387            fn from(t: (usize, #struct_name)) -> Self {
1388                Self {
1389                    id: Some(t.0),
1390                    #(#clone_field_names5: Some(t.1.#clone_field_names5),)*
1391                }
1392            }
1393        }
1394
1395        impl From<#wrapper_name> for #struct_name {
1396            fn from(wrapper: #wrapper_name) -> Self {
1397                Self {
1398                    #(#clone_field_names: wrapper.#clone_field_names.expect("#clone_field_names field missing"),)*
1399                }
1400            }
1401        }
1402        #[cfg(target_arch = "wasm32")]
1403        pub mod #lower_name {
1404            use super::*;
1405            pub type Protocol = #protocol_name;
1406            pub type Wrapper = #wrapper_name;
1407            pub type _InstanceType = #struct_name;
1408            pub fn get(proc: Protocol) -> sewup::Result<sewup::primitives::EwasmAny> {
1409                let table = sewup::rdb::Db::load(None)?.table::<_InstanceType>()?;
1410                if proc.filter {
1411                    let mut raw_output: Vec<Wrapper> = Vec::new();
1412                    for (idx, r) in table.all_records()?.drain(..).enumerate(){
1413                        let mut all_field_match = true;
1414                        #(
1415                            paste::paste! {
1416                                let [<#clone_field_names2 _filed_filter>] : Option<#field_types> =
1417                                    sewup::utils::get_field_by_name(proc.records[0].clone(), stringify!(#clone_field_names2));
1418
1419                                let  [<#clone_field_names2 _field>] : #field_types =
1420                                    sewup::utils::get_field_by_name(&r, stringify!(#clone_field_names2));
1421
1422                                if [<#clone_field_names2 _filed_filter>].is_some() {
1423                                    all_field_match &=
1424                                        [<#clone_field_names2 _filed_filter>].unwrap()
1425                                            == [<#clone_field_names2 _field>];
1426                                }
1427                            }
1428                         )*
1429
1430                        if all_field_match {
1431                            raw_output.push((idx + 1, r).into());
1432                        }
1433                    }
1434                    if let Some(select_fields) = proc.select_fields {
1435                        for w in raw_output.iter_mut() {
1436                            #(
1437                                if (! select_fields.contains(stringify!(#clone_field_names3)))
1438                                    && stringify!(#clone_field_names3) != "id" {
1439                                    w.#clone_field_names3 = None;
1440                                }
1441                            )*
1442                        }
1443                    }
1444                    let p: #protocol_name = raw_output.into();
1445                    Ok(p.into())
1446                } else {
1447                    let raw_output = table.get_record(proc.records[0].id.unwrap_or_default())?;
1448                    let mut output_proc: Protocol = raw_output.into();
1449                    output_proc.records[0].id = proc.records[0].id;
1450                    Ok(output_proc.into())
1451                }
1452            }
1453            pub fn create(proc: Protocol) -> sewup::Result<sewup::primitives::EwasmAny> {
1454                let mut table = sewup::rdb::Db::load(None)?.table::<_InstanceType>()?;
1455                let mut output_proc = proc.clone();
1456                output_proc.records[0].id = Some(table.add_record(proc.records[0].clone().into())?);
1457                table.commit()?;
1458                Ok(output_proc.into())
1459            }
1460            pub fn update(proc: Protocol) -> sewup::Result<sewup::primitives::EwasmAny> {
1461                let mut table = sewup::rdb::Db::load(None)?.table::<_InstanceType>()?;
1462                let id = proc.records[0].id.unwrap_or_default();
1463                table.update_record(id, Some(proc.records[0].clone().into()))?;
1464                table.commit()?;
1465                Ok(proc.into())
1466            }
1467            pub fn delete(proc: Protocol) -> sewup::Result<sewup::primitives::EwasmAny> {
1468                let mut table = sewup::rdb::Db::load(None)?.table::<_InstanceType>()?;
1469                let id = proc.records[0].id.unwrap_or_default();
1470                table.update_record(id, None)?;
1471                table.commit()?;
1472                Ok(proc.into())
1473            }
1474        }
1475        #[cfg(not(target_arch = "wasm32"))]
1476        pub mod #lower_name {
1477            use super::*;
1478            pub type Protocol = #protocol_name;
1479            pub type Wrapper = #wrapper_name;
1480            pub type _InstanceType = #struct_name;
1481            pub type Query = Wrapper;
1482
1483            #[inline]
1484            pub fn protocol(instance: _InstanceType) -> Protocol {
1485                instance.into()
1486            }
1487            impl Protocol {
1488                pub fn set_id(&mut self, id: usize) {
1489                    self.records[0].id = Some(id);
1490                }
1491                pub fn is_empty(&self) -> bool {
1492                    #(self.records[0].#clone_field_names4.is_none() && )*
1493                    true
1494                }
1495            }
1496            pub fn query(instance: _InstanceType) -> Wrapper {
1497                instance.into()
1498            }
1499
1500            impl From<Query> for Protocol {
1501                fn from(instance: Query) -> Self {
1502                    Self {
1503                        select_fields: None,
1504                        filter: true,
1505                        records: vec![instance.into()]
1506                    }
1507                }
1508            }
1509        }
1510    ).to_string();
1511
1512    if let Some(parent_table) = belongs_to {
1513        let lower_parent_table = &format!("{}", &parent_table).to_ascii_lowercase();
1514        let parent_table = Ident::new(&parent_table, Span::call_site());
1515        let lower_parent_table_ident = Ident::new(&lower_parent_table, Span::call_site());
1516        let field_name = &format!("{}_id", lower_parent_table);
1517
1518        output += &quote! {
1519            impl #struct_name {
1520                pub fn #lower_parent_table_ident (&self) -> sewup::Result<#parent_table> {
1521                    let id: usize = sewup::utils::get_field_by_name(self, #field_name);
1522                    let parent_table = sewup::rdb::Db::load(None)?.table::<#parent_table>()?;
1523                    parent_table.get_record(id)
1524                }
1525            }
1526        }
1527        .to_string();
1528    }
1529
1530    if let Some(parent_table) = belongs_none_or {
1531        let lower_parent_table = &format!("{}", &parent_table).to_ascii_lowercase();
1532        let parent_table = Ident::new(&parent_table, Span::call_site());
1533        let lower_parent_table_ident = Ident::new(&lower_parent_table, Span::call_site());
1534        let field_name = &format!("{}_id", lower_parent_table);
1535
1536        output += &quote! {
1537            impl #struct_name {
1538                pub fn #lower_parent_table_ident (&self) -> sewup::Result<Option<#parent_table>> {
1539                    let id: Option<usize> = sewup::utils::get_field_by_name(self, #field_name);
1540                    let parent_table = sewup::rdb::Db::load(None)?.table::<#parent_table>()?;
1541                    if let Some(id) = id {
1542                        match parent_table.get_record(id) {
1543                            Ok(r) => Ok(Some(r)),
1544                            Err(e) => Err(e)
1545                        }
1546                    } else {
1547                        Ok(None)
1548                    }
1549                }
1550            }
1551        }
1552        .to_string();
1553    }
1554
1555    output.parse().unwrap()
1556}
1557
1558/// helps you setup the test mododule, and test cases in contract.
1559/// ```compile_fail
1560/// #[ewasm_test]
1561/// mod tests {
1562///     use super::*;
1563///
1564///     #[ewasm_test]
1565///     fn test_execute_basic_operations() {
1566///         ewasm_assert_ok!(contract_fn());
1567///     }
1568/// }
1569/// ```
1570/// The test runtime will be create in the module, and all the test case will use the same test
1571/// runtime, if you can create more runtimes for testing by setup more test modules.
1572/// You can setup a log file when running the test as following, then use `sewup::ewasm_dbg!` to debug the
1573/// ewasm contract in the executing in the runtime.
1574/// ```compile_fail
1575/// #[ewasm_test(log=/path/to/logfile)]
1576/// mod tests {
1577///     use super::*;
1578///
1579///     #[ewasm_test]
1580///     fn test_execute_basic_operations() {
1581///         ewasm_assert_ok!(contract_fn());
1582///     }
1583/// }
1584/// ```
1585#[proc_macro_error]
1586#[proc_macro_attribute]
1587pub fn ewasm_test(attr: TokenStream, item: TokenStream) -> TokenStream {
1588    let mod_re = unsafe {
1589        Regex::new(r"^mod (?P<mod_name>[^\{\s]*)(?P<to_first_bracket>[^\{]*\{)").unwrap_unchecked()
1590    };
1591    let fn_re = unsafe {
1592        Regex::new(r"^fn (?P<fn_name>[^\(\s]*)(?P<to_first_bracket>[^\{]*\{)").unwrap_unchecked()
1593    };
1594    let context = item.to_string();
1595    let mod_captures = mod_re.captures(&context).unwrap();
1596    let fn_captures = fn_re.captures(&context).unwrap();
1597    if mod_captures.is_some() {
1598        let attr_str = attr.to_string().replace(" ", "");
1599        let runtime_log_option = if attr_str.is_empty() {
1600            "".to_string()
1601        } else {
1602            let options = attr_str.split('=').collect::<Vec<_>>();
1603            match options[0].to_lowercase().as_str() {
1604                "log" => format!(".set_log_file({:?}.into())", options[1]),
1605                _ => abort_call_site!("no support option"),
1606            }
1607        };
1608        let template = r#"
1609            #[cfg(test)]
1610            mod $mod_name {
1611                use sewup::bincode;
1612                use sewup::runtimes::{handler::ContractHandler, test::TestRuntime};
1613                use std::cell::RefCell;
1614                use std::path::Path;
1615                use std::path::PathBuf;
1616                use std::process::Command;
1617                use std::sync::Arc;
1618                use sewup::runtimes::traits::RT;
1619
1620                fn _build_wasm(opt: Option<String>) -> String {
1621                    let cargo_cmd = format!("cargo build --release --target=wasm32-unknown-unknown {}", opt.unwrap_or_default());
1622                    let output = Command::new("sh")
1623                        .arg("-c")
1624                        .arg(&cargo_cmd)
1625                        .output()
1626                        .expect("failed to build wasm binary");
1627                    if !output.status.success() {
1628                        panic!("return code not success: fail to build wasm binary")
1629                    }
1630                    let pkg_name = env!("CARGO_PKG_NAME");
1631                    let base_dir = env!("CARGO_MANIFEST_DIR");
1632                    let wasm_binary = format!(
1633                        "{}/target/wasm32-unknown-unknown/release/{}.wasm",
1634                        base_dir,
1635                        pkg_name.replace("-", "_")
1636                    );
1637
1638                    if !Path::new(&wasm_binary).exists() {
1639                        panic!("wasm binary missing")
1640                    }
1641                    wasm_binary
1642                }
1643
1644                fn _build_runtime_and_runner() -> (
1645                    Arc<RefCell<TestRuntime>>,
1646                    impl Fn(Arc<RefCell<TestRuntime>>, Option<&str>, &str, [u8; 4], Option<&[u8]>, Vec<u8>) -> (),
1647                ) {
1648                    let rt = Arc::new(RefCell::new(TestRuntime::default()"#.to_string()
1649                            + &runtime_log_option
1650                            + r#"));
1651                    let mut h = ContractHandler {
1652                        call_data: None,
1653                        rt: Some(rt.clone())
1654                    };
1655
1656                    match h.run_fn(_build_wasm(Some("--features=constructor-test".to_string())), None, 1_000_000_000_000) {
1657                        Ok(_) => (),
1658                        Err(e) => {
1659                            panic!("vm run constructor error: {:?}", e);
1660                        }
1661                    };
1662
1663                    (rt,
1664                        |runtime: Arc<RefCell<TestRuntime>>,
1665                        caller: Option<&str>,
1666                        fn_name: &str,
1667                        sig: [u8; 4],
1668                        input_data: Option<&[u8]>,
1669                        expect_output: Vec<u8>| {
1670                            let mut h = ContractHandler {
1671                                call_data: Some(_build_wasm(None)),
1672                                rt: Some(runtime.clone())
1673                            };
1674
1675                            match h.execute(caller.clone(), sig, input_data, 1_000_000_000_000) {
1676                                Ok(r) => {
1677                                    if !(*r.output_data == *expect_output) {
1678                                        if let Some(caller) = caller {
1679                                            eprintln!("vm caller : {}", caller);
1680                                        }
1681
1682                                        if let Ok(output_msg) = std::str::from_utf8(&r.output_data) {
1683                                            eprintln!("vm msg    : \"{}\"", output_msg);
1684                                        }
1685                                        eprintln!("vm output : {:?}", r.output_data);
1686
1687                                        if let Ok(expect_msg) = std::str::from_utf8(&expect_output) {
1688                                            eprintln!("expected  : \"{}\"", expect_msg);
1689                                        }
1690                                        eprintln!("expected  : {:?}", expect_output);
1691                                        panic!("function `{}` output is unexpected", fn_name);
1692                                    }
1693                                },
1694                                Err(e) => {
1695                                    panic!("vm error: {:?}", e);
1696                                }
1697                            }
1698                        },
1699                    )
1700                }
1701
1702                #[test]
1703                fn _compile_runtime_test() {
1704                    _build_wasm(None);
1705                }
1706
1707                #[test]
1708                fn _compile_constructor_test() {
1709                    _build_wasm(Some("--features=constructor-test".to_string()));
1710                }"#;
1711        return mod_re
1712            .replace(&context, &template)
1713            .to_string()
1714            .parse()
1715            .unwrap();
1716    } else if fn_captures.is_some() {
1717        let attr_str = attr.to_string().replace(" ", "");
1718        if !attr_str.is_empty() {
1719            abort_call_site!("no support option when wrapping on function")
1720        };
1721        return fn_re
1722            .replace(
1723                &context,
1724                r#"
1725            #[test]
1726            fn $fn_name () {
1727                let (_runtime, _run_wasm_fn) = _build_runtime_and_runner();
1728                let mut _bin: Vec<u8> = Vec::new();"#,
1729            )
1730            .to_string()
1731            .parse()
1732            .unwrap();
1733    } else {
1734        abort_call_site!("parse mod or function for testing error")
1735    }
1736}
1737/// helps you assert output from the handle of a contract with `Vec<u8>`.
1738///
1739/// ```compile_fail
1740/// #[ewasm_test]
1741/// mod tests {
1742///     use super::*;
1743///
1744///     #[ewasm_test]
1745///     fn test_execute_basic_operations() {
1746///         ewasm_assert_eq!(handler_fn(), vec![74, 111, 118, 121]);
1747///     }
1748/// }
1749/// ```
1750///
1751/// Besides, you can run the handler as a block chan user with `by` syntax
1752/// ```compile_fail
1753/// ewasm_assert_eq!(handler_fn() by "eD5897cCEa7aee785D31cdcA87Cf59D1D041aAFC", vec![74, 111, 118, 121]);
1754/// ```
1755#[proc_macro_error]
1756#[proc_macro]
1757pub fn ewasm_assert_eq(item: TokenStream) -> TokenStream {
1758    let re = unsafe {
1759        Regex::new(r#"^(?P<fn_name>[^(]+?)\((?P<params>[^)]*?)\)\s*(by)?\s*(?P<caller>"[^"]*")?\s*,(?P<equivalence>.*)"#).unwrap_unchecked()
1760    };
1761    if let Ok(Some(cap)) = re.captures(&item.to_string().replace("\n", "")) {
1762        let fn_name = unsafe { cap.name("fn_name").unwrap_unchecked() }
1763            .as_str()
1764            .replace(" ", "");
1765        let params = unsafe { cap.name("params").unwrap_unchecked() }
1766            .as_str()
1767            .replace(" ", "");
1768        let equivalence = unsafe { cap.name("equivalence").unwrap_unchecked() }.as_str();
1769        let caller = cap
1770            .name("caller")
1771            .map(|c| format!("Some({})", c.as_str()))
1772            .unwrap_or_else(|| "None".to_string());
1773        if params.is_empty() {
1774            format!(
1775                r#"_run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), None, {});"#,
1776                caller, fn_name, fn_name, equivalence
1777            )
1778            .parse()
1779            .unwrap()
1780        } else {
1781            format!(
1782                r#"_bin = bincode::serialize(&{}).unwrap();
1783                   _run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), Some(&_bin), {});"#,
1784                params, caller, fn_name, fn_name, equivalence
1785            )
1786            .parse()
1787            .unwrap()
1788        }
1789    } else {
1790        abort_call_site!("fail to parsing function in ewasm_assert_eq");
1791    }
1792}
1793
1794/// helps you assert return instance from your handler with auto unwrap ewasm_main, namely `#[ewasm_main(auto)]`
1795///
1796/// This usage of the macro likes `ewasm_assert_eq`, but the contract main function should be
1797/// decorated with `#[ewasm_main(auto)]`, and the equivalence arm will be serialized into `Vec<u8>`
1798/// Besides, you can run the handler as a block chan user with `by` syntax as the same usage of `ewasm_assert_eq`.
1799#[proc_macro_error]
1800#[proc_macro]
1801pub fn ewasm_auto_assert_eq(item: TokenStream) -> TokenStream {
1802    let re = unsafe {
1803        Regex::new(r#"^(?P<fn_name>[^(]+?)\((?P<params>[^)]*?)\)\s*(by)?\s*(?P<caller>"[^"]*")?\s*,(?P<equivalence>.*)"#).unwrap_unchecked()
1804    };
1805    if let Ok(Some(cap)) = re.captures(&item.to_string().replace("\n", "")) {
1806        let fn_name = unsafe { cap.name("fn_name").unwrap_unchecked() }.as_str();
1807        let params = unsafe { cap.name("params").unwrap_unchecked() }
1808            .as_str()
1809            .replace(" ", "");
1810        let equivalence = unsafe { cap.name("equivalence").unwrap_unchecked() }.as_str();
1811        let caller = cap
1812            .name("caller")
1813            .map(|c| format!("Some({})", c.as_str()))
1814            .unwrap_or_else(|| "None".to_string());
1815        if params.is_empty() {
1816            format!(
1817                r#"_run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), None, sewup_derive::ewasm_output_from!({}));"#,
1818                caller, fn_name, fn_name, equivalence
1819            )
1820            .parse()
1821            .unwrap()
1822        } else {
1823            format!(
1824                r#"_bin = bincode::serialize(&{}).unwrap();
1825                   _run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), Some(&_bin), sewup_derive::ewasm_output_from!({}));"#,
1826                params, caller, fn_name, fn_name, equivalence
1827            )
1828            .parse()
1829            .unwrap()
1830        }
1831    } else {
1832        abort_call_site!("fail to parsing function in fn_select");
1833    }
1834}
1835
1836/// helps you assert your handler without error and returns
1837///
1838/// ```compile_fail
1839/// #[ewasm_test]
1840/// mod tests {
1841///     use super::*;
1842///
1843///     #[ewasm_test]
1844///     fn test_execute_basic_operations() {
1845///         ewasm_assert_ok!(contract_fn());
1846///     }
1847/// }
1848/// ```
1849///
1850/// Besides, you can run the handler as a block chan user with `by` syntax.
1851/// ```compile_fail
1852/// ewasm_assert_ok!(contract_fn() by "eD5897cCEa7aee785D31cdcA87Cf59D1D041aAFC");
1853/// ```
1854#[proc_macro_error]
1855#[proc_macro]
1856pub fn ewasm_assert_ok(item: TokenStream) -> TokenStream {
1857    let re = unsafe {
1858        Regex::new(
1859            r#"^(?P<fn_name>[^(]+?)\((?P<params>[^)]*?)\)\s*(by)?\s*(?P<caller>"[^"]*")?\s*"#,
1860        )
1861        .unwrap_unchecked()
1862    };
1863    if let Ok(Some(cap)) = re.captures(&item.to_string().replace("\n", "")) {
1864        let fn_name = unsafe { cap.name("fn_name").unwrap_unchecked() }.as_str();
1865        let params = unsafe { cap.name("params").unwrap_unchecked() }
1866            .as_str()
1867            .replace(" ", "");
1868        let caller = cap
1869            .name("caller")
1870            .map(|c| format!("Some({})", c.as_str()))
1871            .unwrap_or_else(|| "None".to_string());
1872        if params.is_empty() {
1873            format!(
1874                r#"_run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), None, Vec::with_capacity(0));"#,
1875                caller, fn_name, fn_name
1876            )
1877            .parse()
1878            .unwrap()
1879        } else {
1880            format!(
1881                r#"_bin = bincode::serialize(&{}).unwrap();
1882                   _run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), Some(&_bin), Vec::with_capacity(0));"#,
1883                params, caller, fn_name, fn_name
1884            )
1885            .parse()
1886            .unwrap()
1887        }
1888    } else {
1889        abort_call_site!("fail to parsing function in fn_select");
1890    }
1891}
1892
1893/// helps you assert return Ok(()) your handler with rusty ewasm_main, namely `#[ewasm_main(rusty)]`
1894///
1895/// This usage of the macro likes `ewasm_assert_ok`, this only difference is that the contract main
1896/// function should be decorated with `#[ewasm_main(rusty)]`.
1897/// Besides, you can run the handler as a block chan user with `by` syntax as the same usage of `ewasm_assert_ok`.
1898#[proc_macro_error]
1899#[proc_macro]
1900pub fn ewasm_rusty_assert_ok(item: TokenStream) -> TokenStream {
1901    let re = unsafe {
1902        Regex::new(
1903            r#"^(?P<fn_name>[^(]+?)\((?P<params>[^)]*?)\)\s*(by)?\s*(?P<caller>"[^"]*")?\s*"#,
1904        )
1905        .unwrap_unchecked()
1906    };
1907    if let Ok(Some(cap)) = re.captures(&item.to_string().replace("\n", "")) {
1908        let fn_name = unsafe { cap.name("fn_name").unwrap_unchecked() }.as_str();
1909        let params = unsafe { cap.name("params").unwrap_unchecked() }
1910            .as_str()
1911            .replace(" ", "");
1912        let caller = cap
1913            .name("caller")
1914            .map(|c| format!("Some({})", c.as_str()))
1915            .unwrap_or_else(|| "None".to_string());
1916        if params.is_empty() {
1917            format!(
1918                r#"_run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), None, vec![0, 0, 0, 0]);"#,
1919                caller, fn_name, fn_name
1920            )
1921            .parse()
1922            .unwrap()
1923        } else {
1924            format!(
1925                r#"_bin = bincode::serialize(&{}).unwrap();
1926                   _run_wasm_fn( _runtime.clone(), {}, "{}", ewasm_fn_sig!({}), Some(&_bin), vec![0, 0, 0, 0]);"#,
1927                params, caller, fn_name, fn_name
1928            )
1929            .parse()
1930            .unwrap()
1931        }
1932    } else {
1933        abort_call_site!("fail to parsing function in fn_select");
1934    }
1935}
1936
1937/// helps you assert return Err your handler with rusty ewasm_main, namely `#[ewasm_main(rusty)]`
1938///
1939/// This usage of the macro likes `ewasm_err_output`, the contract main function should be
1940/// decorated with `#[ewasm_main(rusty)]`.
1941///
1942/// You should pass the complete Result type, as the following example
1943/// `ewasm_rusty_err_output!(Err("NotTrustedInput") as Result<(), &'static str>)`
1944/// such that you can easy to use any kind of rust error as you like.
1945#[proc_macro_error]
1946#[proc_macro]
1947pub fn ewasm_rusty_err_output(item: TokenStream) -> TokenStream {
1948    format!(
1949        r#"bincode::serialize(&({})).expect("can not serialize the output expected from ewasm").to_vec()"#,
1950        &item.to_string()
1951    )
1952    .parse()
1953    .unwrap()
1954}
1955
1956/// helps you to get the binary result of the thiserror,
1957///
1958/// such that you can assert your handler with error.
1959/// for example:
1960/// ```compile_fail
1961/// #[ewasm_test]
1962/// mod tests {
1963///    use super::*;
1964///
1965///    #[ewasm_test]
1966///    fn test_execute_basic_operations() {
1967///        let mut simple_struct = SimpleStruct::default();
1968///
1969///        ewasm_assert_eq!(
1970///            check_input_object(simple_struct),
1971///            ewasm_err_output!(Error::NotTrustedInput)
1972///        );
1973///    }
1974///}
1975/// ```
1976#[proc_macro_error]
1977#[proc_macro]
1978pub fn ewasm_err_output(item: TokenStream) -> TokenStream {
1979    format!("{}.to_string().as_bytes().to_vec()", &item.to_string())
1980        .parse()
1981        .unwrap()
1982}
1983
1984/// help you write the field which storage string no longer than the specific size
1985///```compile_fail
1986///#[derive(Table)]
1987///pub struct Blog {
1988///     pub content: SizedString!(50),
1989///}
1990///```
1991#[allow(non_snake_case)]
1992#[proc_macro_error]
1993#[proc_macro]
1994pub fn SizedString(item: TokenStream) -> TokenStream {
1995    let num = item.to_string();
1996
1997    if let Ok(num) = num.trim().parse::<usize>() {
1998        if num > 0 {
1999            let raw_size = num / 32usize + 1;
2000            return format!("[sewup::types::Raw; {}]", raw_size)
2001                .parse()
2002                .unwrap();
2003        }
2004    }
2005    panic!("The input of SizedString! should be a greator than zero integer")
2006}
2007
2008/// helps you return handler when caller is not in access control list
2009/// ```compile_fail
2010/// ewasm_call_only_by!("8663..1993")
2011/// ```
2012#[proc_macro]
2013pub fn ewasm_call_only_by(item: TokenStream) -> TokenStream {
2014    let input = item.to_string().replace(" ", "");
2015    let output = if input.starts_with('"') {
2016        let addr = input.replace("\"", "");
2017        quote! {
2018            if sewup::utils::caller() != sewup::types::Address::from_str(#addr)? {
2019                return Err(sewup::errors::HandlerError::Unauthorized.into())
2020            }
2021        }
2022    } else {
2023        let addr = Ident::new(&input, Span::call_site());
2024        quote! {
2025            if sewup::utils::caller() != sewup::types::Address::from_str(#addr)? {
2026                return Err(sewup::errors::HandlerError::Unauthorized.into())
2027            }
2028        }
2029    };
2030
2031    output.into()
2032}
2033
2034/// helps you inspect the storage in test
2035/// this will print out the detail of storage, you can add description on the storage debug or
2036/// leave  it empty
2037/// ```compile_fail
2038/// ewasm_storage_debug!();
2039/// ewasm_storage_debug!(description);
2040/// ```
2041#[proc_macro]
2042pub fn ewasm_storage_debug(item: TokenStream) -> TokenStream {
2043    let desc = item.to_string();
2044    quote!({
2045        let __cloned = _runtime.clone();
2046        let __borrowed = __cloned.borrow();
2047        let __storage = __borrowed.get_storage(&[0; 20]);
2048        eprintln!("{}", sewup::utils::pretty_print_storage(#desc, __storage));
2049    })
2050    .into()
2051}