shank-parse-macro 2.0.0

Internal proc-macro implementation for shank-parse — generates Rust client code from Shank/Anchor IDL JSON files.
Documentation
mod gen;
mod idl;

use proc_macro::TokenStream;

#[proc_macro]
pub fn shank_parse(input: TokenStream) -> TokenStream {
    match shank_parse_inner(input.into()) {
        Ok(tokens) => tokens.into(),
        Err(err) => err.to_compile_error().into(),
    }
}

fn shank_parse_inner(input: proc_macro2::TokenStream) -> syn::Result<proc_macro2::TokenStream> {
    let lit: syn::LitStr = syn::parse2(input)?;
    let path_str = lit.value();

    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(|e| {
        syn::Error::new(lit.span(), format!("CARGO_MANIFEST_DIR not set: {e}"))
    })?;

    let full_path = std::path::Path::new(&manifest_dir).join(&path_str);

    let content = std::fs::read_to_string(&full_path).map_err(|e| {
        syn::Error::new(
            lit.span(),
            format!("failed to read IDL file '{}': {e}", full_path.display()),
        )
    })?;

    let idl: idl::Idl = serde_json::from_str(&content).map_err(|e| {
        syn::Error::new(lit.span(), format!("failed to parse IDL JSON: {e}"))
    })?;

    let program_id_bytes = idl
        .metadata
        .as_ref()
        .and_then(|m| m.address.as_ref())
        .and_then(|addr| {
            let decoded = bs58::decode(addr).into_vec().ok()?;
            if decoded.len() == 32 {
                let mut arr = [0u8; 32];
                arr.copy_from_slice(&decoded);
                Some(arr)
            } else {
                None
            }
        });

    Ok(gen::generate(&idl, program_id_bytes))
}