candid_derive/
lib.rs

1use proc_macro::TokenStream;
2use syn::{parse_macro_input, Result};
3
4mod derive;
5mod func;
6
7#[proc_macro_derive(CandidType, attributes(candid_path))]
8pub fn derive_idl_type(input: TokenStream) -> TokenStream {
9    let input = parse_macro_input!(input as syn::DeriveInput);
10    let custom_candid_path_result = get_custom_candid_path(&input);
11
12    match custom_candid_path_result {
13        Ok(custom_candid_path) => derive::derive_idl_type(input, &custom_candid_path).into(),
14        Err(e) => e.to_compile_error().into(),
15    }
16}
17
18#[proc_macro_attribute]
19pub fn candid_method(attr: TokenStream, item: TokenStream) -> TokenStream {
20    use syn::{parse::Parser, punctuated::Punctuated, Meta, Token};
21    let attrs = match Punctuated::<Meta, Token![,]>::parse_terminated.parse(attr) {
22        Ok(attrs) => attrs.into_iter().collect(),
23        Err(e) => return e.to_compile_error().into(),
24    };
25    let fun = parse_macro_input!(item as syn::ItemFn);
26    func::candid_method(attrs, fun).map_or_else(|e| e.to_compile_error().into(), Into::into)
27}
28
29#[proc_macro]
30pub fn export_service(input: TokenStream) -> TokenStream {
31    if input.is_empty() {
32        func::export_service(None).into()
33    } else {
34        func::export_service(Some(input.into())).into()
35    }
36}
37
38#[inline]
39pub(crate) fn idl_hash(id: &str) -> u32 {
40    let mut s: u32 = 0;
41    for c in id.as_bytes() {
42        s = s.wrapping_mul(223).wrapping_add(*c as u32);
43    }
44    s
45}
46
47pub(crate) fn candid_path(
48    custom_candid_path: &Option<proc_macro2::TokenStream>,
49) -> proc_macro2::TokenStream {
50    match custom_candid_path {
51        Some(custom_candid_path_value) => custom_candid_path_value.clone(),
52        None => quote::quote! { ::candid },
53    }
54}
55pub(crate) fn get_lit_str(expr: &syn::Expr) -> std::result::Result<syn::LitStr, ()> {
56    if let syn::Expr::Lit(expr) = expr {
57        if let syn::Lit::Str(lit) = &expr.lit {
58            return Ok(lit.clone());
59        }
60    }
61    Err(())
62}
63
64fn get_custom_candid_path(input: &syn::DeriveInput) -> Result<Option<proc_macro2::TokenStream>> {
65    let candid_path_helper_attribute_option = input
66        .attrs
67        .iter()
68        .find(|attr| attr.path().is_ident("candid_path"));
69
70    match candid_path_helper_attribute_option {
71        Some(candid_path_helper_attribute) => {
72            let custom_candid_path_lit: syn::LitStr = candid_path_helper_attribute.parse_args()?;
73            let custom_candid_token_stream: proc_macro2::TokenStream =
74                custom_candid_path_lit.value().parse()?;
75
76            Ok(Some(custom_candid_token_stream))
77        }
78        None => Ok(None),
79    }
80}