1mod gen;
2mod idl;
3
4use proc_macro::TokenStream;
5
6#[proc_macro]
7pub fn shank_parse(input: TokenStream) -> TokenStream {
8 match shank_parse_inner(input.into()) {
9 Ok(tokens) => tokens.into(),
10 Err(err) => err.to_compile_error().into(),
11 }
12}
13
14fn shank_parse_inner(input: proc_macro2::TokenStream) -> syn::Result<proc_macro2::TokenStream> {
15 let lit: syn::LitStr = syn::parse2(input)?;
16 let path_str = lit.value();
17
18 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(|e| {
19 syn::Error::new(lit.span(), format!("CARGO_MANIFEST_DIR not set: {e}"))
20 })?;
21
22 let full_path = std::path::Path::new(&manifest_dir).join(&path_str);
23
24 let content = std::fs::read_to_string(&full_path).map_err(|e| {
25 syn::Error::new(
26 lit.span(),
27 format!("failed to read IDL file '{}': {e}", full_path.display()),
28 )
29 })?;
30
31 let idl: idl::Idl = serde_json::from_str(&content).map_err(|e| {
32 syn::Error::new(lit.span(), format!("failed to parse IDL JSON: {e}"))
33 })?;
34
35 let program_id_bytes = idl
36 .metadata
37 .as_ref()
38 .and_then(|m| m.address.as_ref())
39 .and_then(|addr| {
40 let decoded = bs58::decode(addr).into_vec().ok()?;
41 if decoded.len() == 32 {
42 let mut arr = [0u8; 32];
43 arr.copy_from_slice(&decoded);
44 Some(arr)
45 } else {
46 None
47 }
48 });
49
50 Ok(gen::generate(&idl, program_id_bytes))
51}