candid icon indicating copy to clipboard operation
candid copied to clipboard

Add a proc-macro for a string principal constant

Open ranile opened this issue 4 weeks ago • 0 comments

Is your feature request related to a problem? Please describe. Principal::from_text is not const but there's many circumstances in which a principal constant is wanted in code. Principal::from_slice is const but it is much harder to inspect and verify as it just takes a byte slice

Describe the solution you'd like

principal!("...")

Describe alternatives you've considered

Principal::from_slice(&[...]), but as mentioned above, that is less than ideal.

Potential implementation

use candid::Principal;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, LitStr, parse::Parse, parse::ParseStream};

struct CandidPrincipal(Principal);

impl Parse for CandidPrincipal {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let text = input.parse::<LitStr>()?.value();
        Principal::from_text(&text)
            .map(Self)
            .map_err(|e| syn::Error::new(input.span(), e.to_string()))
    }
}

impl ToTokens for CandidPrincipal {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        let bytes = self.0.as_slice();
        tokens.extend(quote! {
            ::candid::Principal::from_slice(&[#(#bytes),*])
        })
    }
}

#[proc_macro]
pub fn principal(tokens: TokenStream) -> TokenStream {
    parse_macro_input!(tokens as CandidPrincipal)
        .into_token_stream()
        .into()
}

syn and quote are dependencies of ic-cdk anyway so this will not have any negative effects on compilation performance

ranile avatar Dec 01 '25 07:12 ranile