clockwork_anchor_idl/
program.rs1use std::{
2 collections::{BTreeMap, HashSet},
3 env, fs,
4 path::PathBuf,
5};
6
7use darling::{util::PathList, FromMeta};
8use proc_macro2::{Ident, TokenStream};
9use quote::{format_ident, quote};
10
11use crate::{
12 generate_accounts, generate_ix_handlers, generate_ix_structs, generate_typedefs, GEN_VERSION,
13};
14
15#[derive(Default, FromMeta)]
16pub struct GeneratorOptions {
17 pub idl_path: String,
19 pub zero_copy: Option<PathList>,
21 pub packed: Option<PathList>,
23}
24
25fn path_list_to_string(list: Option<&PathList>) -> HashSet<String> {
26 list.map(|el| {
27 el.iter()
28 .map(|el| el.get_ident().unwrap().to_string())
29 .collect()
30 })
31 .unwrap_or_default()
32}
33
34impl GeneratorOptions {
35 pub fn to_generator(&self) -> Generator {
36 let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
37 let path = PathBuf::from(cargo_manifest_dir).join(&self.idl_path);
38 let idl_contents = fs::read_to_string(&path).unwrap();
39 let idl: anchor_syn::idl::Idl = serde_json::from_str(&idl_contents).unwrap();
40
41 let zero_copy = path_list_to_string(self.zero_copy.as_ref());
42 let packed = path_list_to_string(self.packed.as_ref());
43
44 let mut struct_opts: BTreeMap<String, StructOpts> = BTreeMap::new();
45 let all_structs: HashSet<&String> = zero_copy.union(&packed).collect::<HashSet<_>>();
46 all_structs.into_iter().for_each(|name| {
47 struct_opts.insert(
48 name.to_string(),
49 StructOpts {
50 zero_copy: zero_copy.contains(name),
51 packed: packed.contains(name),
52 },
53 );
54 });
55
56 Generator { idl, struct_opts }
57 }
58}
59
60#[derive(Clone, Copy, Default)]
61pub struct StructOpts {
62 pub packed: bool,
63 pub zero_copy: bool,
64}
65
66pub struct Generator {
67 pub idl: anchor_syn::idl::Idl,
68 pub struct_opts: BTreeMap<String, StructOpts>,
69}
70
71impl Generator {
72 pub fn generate_cpi_interface(&self) -> TokenStream {
73 let idl = &self.idl;
74 let program_name: Ident = format_ident!("{}", idl.name);
75
76 let accounts = generate_accounts(&idl.types, &idl.accounts, &self.struct_opts);
77 let typedefs = generate_typedefs(&idl.types, &self.struct_opts);
78 let ix_handlers = generate_ix_handlers(&idl.instructions);
79 let ix_structs = generate_ix_structs(&idl.instructions);
80
81 let docs = format!(
82 " Anchor CPI crate generated from {} v{} using [anchor-gen](https://crates.io/crates/anchor-gen) v{}.",
83 &idl.name,
84 &idl.version,
85 &GEN_VERSION.unwrap_or("unknown")
86 );
87
88 quote! {
89 use anchor_lang::prelude::*;
90
91 pub mod typedefs {
92 use super::*;
94 #typedefs
95 }
96
97 pub mod state {
98 use super::*;
100 #accounts
101 }
102
103 pub mod ix_accounts {
104 use super::*;
106 #ix_structs
107 }
108
109 use ix_accounts::*;
110 pub use state::*;
111 pub use typedefs::*;
112
113 #[program]
114 pub mod #program_name {
115 #![doc = #docs]
116
117 use super::*;
118 #ix_handlers
119 }
120 }
121 }
122}