tx3_bindgen/
rust.rs

1use convert_case::Casing;
2use proc_macro2::Ident;
3use quote::{format_ident, quote};
4
5use crate::Job;
6
7fn to_syn_type(ty: &tx3_lang::ir::Type) -> syn::Type {
8    match ty {
9        tx3_lang::ir::Type::Int => syn::parse_str("i64").unwrap(),
10        tx3_lang::ir::Type::Bool => syn::parse_str("bool").unwrap(),
11        tx3_lang::ir::Type::Bytes => syn::parse_str("Vec<u8>").unwrap(),
12        tx3_lang::ir::Type::Unit => syn::parse_str("()").unwrap(),
13        tx3_lang::ir::Type::Address => syn::parse_str("tx3_lang::ArgValue").unwrap(),
14        tx3_lang::ir::Type::UtxoRef => syn::parse_str("tx3_lang::ArgValue").unwrap(),
15        tx3_lang::ir::Type::Custom(name) => syn::parse_str(name).unwrap(),
16        tx3_lang::ir::Type::AnyAsset => syn::parse_str("tx3_lang::ArgValue").unwrap(),
17        tx3_lang::ir::Type::List => syn::parse_str("Vec<tx3_lang::ArgValue>").unwrap(),
18        tx3_lang::ir::Type::Undefined => unreachable!(),
19    }
20}
21
22pub fn generate(job: &Job) {
23    let mut output = String::new();
24
25    for tx_def in job.protocol.txs() {
26        let proto_tx = job.protocol.new_tx(&tx_def.name).unwrap();
27        let proto_bytes: Vec<u8> = proto_tx.ir_bytes();
28
29        let bytes_name = format_ident!("PROTO_{}", tx_def.name.to_uppercase());
30
31        let struct_name =
32            format_ident!("{}Params", tx_def.name.to_case(convert_case::Case::Pascal));
33
34        // Convert bytes to a byte string literal
35        let proto_bytes_literal =
36            syn::LitByteStr::new(&proto_bytes, proc_macro2::Span::call_site());
37
38        let fn_name = format_ident!("new_{}_tx", tx_def.name.to_lowercase());
39
40        let param_names: Vec<Ident> = proto_tx
41            .find_params()
42            .keys()
43            .map(|name| format_ident!("{}", name.to_case(convert_case::Case::Snake)))
44            .collect();
45
46        let param_types: Vec<syn::Type> =
47            proto_tx.find_params().values().map(to_syn_type).collect();
48
49        let tokens = quote! {
50            pub const #bytes_name: &[u8] = #proto_bytes_literal;
51
52            pub struct #struct_name {
53                #(#param_names: #param_types),*
54            }
55
56            pub fn #fn_name(params: #struct_name) -> Result<tx3_lang::ProtoTx, tx3_lang::applying::Error> {
57                let mut proto_tx = tx3_lang::ProtoTx::from_ir_bytes(#bytes_name).unwrap();
58
59                #(proto_tx.set_arg(stringify!(#param_names), params.#param_names.into());)*
60
61                proto_tx.apply()
62            }
63        };
64
65        output.push_str(&tokens.to_string());
66        output.push_str("\n\n");
67    }
68
69    std::fs::write(job.dest_path.join(format!("{}.rs", job.name)), output).unwrap();
70}