Skip to main content

anchor_syn/codegen/program/
common.rs

1use {crate::IxArg, heck::ToUpperCamelCase, quote::quote, syn::Result};
2
3// Namespace for calculating instruction sighash signatures for any instruction
4// not affecting program state.
5pub const SIGHASH_GLOBAL_NAMESPACE: &str = "global";
6
7// We don't technically use sighash, because the input arguments aren't given.
8// Rust doesn't have method overloading so no need to use the arguments.
9// However, we do namespace methods in the preeimage so that we can use
10// different traits with the same method name.
11pub fn sighash(namespace: &str, name: &str) -> [u8; 8] {
12    let preimage = format!("{namespace}:{name}");
13
14    let mut sighash = [0u8; 8];
15    sighash.copy_from_slice(&crate::hash::hash(preimage.as_bytes()).to_bytes()[..8]);
16    sighash
17}
18
19pub fn gen_discriminator(namespace: &str, name: impl ToString) -> proc_macro2::TokenStream {
20    let discriminator = sighash(namespace, name.to_string().as_str());
21    #[allow(
22        clippy::unwrap_used,
23        reason = "debug-formatted array literal is always valid Rust token syntax"
24    )]
25    let ts = format!("&{discriminator:?}").parse().unwrap();
26    ts
27}
28
29pub fn generate_ix_variant(name: &str, args: &[IxArg]) -> Result<proc_macro2::TokenStream> {
30    let ix_arg_names: Vec<&syn::Ident> = args.iter().map(|arg| &arg.name).collect();
31    let ix_name_camel = generate_ix_variant_name(name)?;
32
33    let variant = if args.is_empty() {
34        quote! {
35            #ix_name_camel
36        }
37    } else {
38        quote! {
39            #ix_name_camel {
40                #(#ix_arg_names),*
41            }
42        }
43    };
44    Ok(variant)
45}
46
47pub fn generate_ix_variant_name(name: &str) -> Result<syn::Ident> {
48    syn::parse_str(&name.to_upper_camel_case())
49}