Skip to main content

ic_platform_macros/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use proc_macro::TokenStream;
4use syn::Error;
5
6mod export;
7
8fn handle_debug_and_errors<F>(
9    cb: F,
10    name: &str,
11    attr: TokenStream,
12    item: TokenStream,
13) -> TokenStream
14where
15    F: FnOnce(
16        proc_macro2::TokenStream,
17        proc_macro2::TokenStream,
18    ) -> Result<proc_macro2::TokenStream, Error>,
19{
20    if std::env::var_os("IC_CDK_DEBUG").is_some() {
21        eprintln!("--- IC_CDK_MACROS DEBUG ---");
22        eprintln!("{name}\n    attr: {attr}\n    item: {item}");
23    }
24
25    let result = cb(attr.into(), item.into());
26
27    if std::env::var_os("IC_CDK_DEBUG").is_some() {
28        eprintln!("--------- RESULT  ---------");
29        if let Ok(ref stream) = result {
30            eprintln!("{stream}");
31        }
32        eprintln!("---------------------------");
33    }
34
35    result.map_or_else(|e| e.to_compile_error().into(), Into::into)
36}
37
38/// Export the service using the Platform Candid contract or an explicit path.
39#[proc_macro]
40pub fn export_candid(input: TokenStream) -> TokenStream {
41    let candid: syn::Path = if input.is_empty() {
42        syn::parse_quote!(::ic_platform::candid::contract)
43    } else {
44        syn::parse_macro_input!(input as syn::Path)
45    };
46    quote::quote! {
47        #candid::export_service!(#candid);
48
49        /// Return the owned service C string for the Candid extractor.
50        #[unsafe(no_mangle)]
51        pub fn get_candid_pointer() -> *mut std::os::raw::c_char {
52            let c_string = std::ffi::CString::new(__export_service()).unwrap();
53            c_string.into_raw()
54        }
55    }
56    .into()
57}
58
59/// Generate an upstream-compatible query or composite-query entrypoint.
60#[proc_macro_attribute]
61pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream {
62    handle_debug_and_errors(export::ic_query, "ic_query", attr, item)
63}
64
65/// Generate an upstream-compatible update entrypoint.
66#[proc_macro_attribute]
67pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream {
68    handle_debug_and_errors(export::ic_update, "ic_update", attr, item)
69}
70
71/// Generate an upstream-compatible initialization entrypoint.
72#[proc_macro_attribute]
73pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream {
74    handle_debug_and_errors(export::ic_init, "ic_init", attr, item)
75}
76
77/// Generate an upstream-compatible pre-upgrade entrypoint.
78#[proc_macro_attribute]
79pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream {
80    handle_debug_and_errors(export::ic_pre_upgrade, "ic_pre_upgrade", attr, item)
81}
82
83/// Generate an upstream-compatible post-upgrade entrypoint.
84#[proc_macro_attribute]
85pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream {
86    handle_debug_and_errors(export::ic_post_upgrade, "ic_post_upgrade", attr, item)
87}
88
89/// Generate an upstream-compatible heartbeat entrypoint.
90#[proc_macro_attribute]
91pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream {
92    handle_debug_and_errors(export::ic_heartbeat, "ic_heartbeat", attr, item)
93}
94
95/// Generate an upstream-compatible message inspection entrypoint.
96#[proc_macro_attribute]
97pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream {
98    handle_debug_and_errors(export::ic_inspect_message, "ic_inspect_message", attr, item)
99}
100
101/// Generate an upstream-compatible low-Wasm-memory entrypoint.
102#[proc_macro_attribute]
103pub fn on_low_wasm_memory(attr: TokenStream, item: TokenStream) -> TokenStream {
104    handle_debug_and_errors(
105        export::ic_on_low_wasm_memory,
106        "ic_on_low_wasm_memory",
107        attr,
108        item,
109    )
110}