leo_bindings_macro/
lib.rs

1use leo_bindings_core::SimplifiedBindings;
2use leo_bindings_core::generator::generate_program_module;
3use proc_macro::TokenStream;
4
5fn read_json_string_from_path_string(path: String) -> String {
6    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
7    let manifest_path = std::path::Path::new(&manifest_dir);
8    let path = manifest_path.join(path);
9    std::fs::read_to_string(&path)
10        .unwrap_or_else(|e| panic!("Failed to read JSON at {}: {}.", path.display(), e))
11}
12
13fn simplified_from_json_string(json: String) -> SimplifiedBindings {
14    serde_json::from_str(&json).expect("Failed to parse signatures from json")
15}
16
17/// Generates Rust bindings for a Leo program.
18///
19/// The input is the path of a "signatures.json" file with types from the Leo program.
20#[proc_macro]
21pub fn generate_bindings(input: TokenStream) -> TokenStream {
22    let input_str = input.to_string();
23    let path = input_str.trim().trim_matches('"').to_string();
24    let json = read_json_string_from_path_string(path);
25    let simplified = simplified_from_json_string(json);
26
27    let crate_name = std::env::var("CARGO_CRATE_NAME").unwrap();
28    let expected_crate_name = format!("{}_bindings", simplified.program_name);
29
30    if crate_name != expected_crate_name {
31        let error_msg = format!(
32            "Naming convention violation: library '{}' should be named '{}' for program '{}.aleo'. \
33            Update your Cargo.toml [lib] name to follow the convention: {{program}}_bindings",
34            crate_name, expected_crate_name, simplified.program_name
35        );
36        return quote::quote! {
37            compile_error!(#error_msg);
38        }
39        .into();
40    }
41
42    let exports: Vec<proc_macro2::TokenStream> = simplified
43        .imports
44        .iter()
45        .map(|import| {
46            let import_crate = proc_macro2::Ident::new(
47                &format!("{}_bindings", import),
48                proc_macro2::Span::call_site(),
49            );
50            let import_module = proc_macro2::Ident::new(import, proc_macro2::Span::call_site());
51            quote::quote! {
52                pub use ::#import_crate::#import_module;
53            }
54        })
55        .collect();
56
57    let program_module = generate_program_module(&simplified);
58
59    quote::quote! {
60        #(#exports)*
61
62        #program_module
63    }
64    .into()
65}