anchor_client_gen_utils/generator/
mod.rs1use std::str::FromStr;
2
3use inflector::Inflector;
4use proc_macro2::TokenStream;
5use quote::quote;
6
7use crate::idl::{FieldJsonDefinition, FieldTypeJsonDefinition, IdlJsonDefinition};
8
9pub mod events;
10pub mod instructions;
11pub mod state;
12
13pub fn generate_doc_comments(docs: Option<Vec<String>>) -> TokenStream {
14 match docs {
15 None => quote! {},
16 Some(docs) => {
17 let mut generated = TokenStream::new();
18 docs.iter().for_each(|comment| {
19 let doc = TokenStream::from_str(&format!("/// {}", comment)).unwrap();
20 generated.extend(doc);
21 });
22 generated
23 }
24 }
25}
26
27#[derive(Clone, Copy, PartialEq)]
28pub enum Module {
29 Accounts,
30 Types,
31 Instructions,
32 Events,
33}
34
35impl Module {
36 pub fn get_prefix(&self) -> String {
37 match self {
38 Self::Accounts => "crate::accounts::".to_owned(),
39 Self::Types => "crate::types::".to_owned(),
40 Self::Instructions => "crate::instructions::".to_owned(),
41 Self::Events => "crate::events::".to_owned(),
42 }
43 }
44}
45
46pub fn generate_field_type(
47 idl: &IdlJsonDefinition,
48 field_type: &FieldTypeJsonDefinition,
49 generate_for: Module,
50) -> TokenStream {
51 let generated = match field_type {
52 FieldTypeJsonDefinition::Primitive(primitive) => {
53 let primitive = TokenStream::from_str(match primitive.as_str() {
54 "publicKey" => "::anchor_lang::prelude::Pubkey",
55 "string" => "String",
56 _ => &primitive,
57 })
58 .unwrap();
59
60 quote! {
61 #primitive
62 }
63 }
64 FieldTypeJsonDefinition::Array { array } => {
65 let inner_type = array.0.clone();
66 let inner = generate_field_type(idl, &inner_type, generate_for);
67 let count = TokenStream::from_str(&array.1.to_string()).unwrap();
68
69 quote! {
70 [#inner; #count]
71 }
72 }
73 FieldTypeJsonDefinition::Defined { defined } => {
74 let pascal_case = &defined.to_pascal_case();
75 let defined = match idl.get_typedef_module(defined) {
76 None => pascal_case.clone(),
77 Some(module) => {
78 if module == generate_for {
79 pascal_case.clone()
80 } else {
81 let module_prefix = module.get_prefix();
82 let type_with_prefix = format!("{}{}", module_prefix, pascal_case);
83 type_with_prefix
84 }
85 }
86 };
87 let defined = TokenStream::from_str(&defined).unwrap();
88
89 quote! {
90 #defined
91 }
92 }
93 FieldTypeJsonDefinition::Option { option } => {
94 let inner = generate_field_type(idl, option, generate_for);
95 quote! {
96 Option<#inner>
97 }
98 }
99 FieldTypeJsonDefinition::Vec { vec } => {
100 let inner = generate_field_type(idl, vec, generate_for);
101 quote! {
102 Vec<#inner>
103 }
104 }
105 };
106
107 generated
108}
109
110pub fn generate_fields(
111 idl: &IdlJsonDefinition,
112 fields: &Vec<FieldJsonDefinition>,
113 generate_for: Module,
114 is_enum_struct_field: bool,
115) -> TokenStream {
116 let mut generated = TokenStream::new();
117
118 for field in fields {
119 let name = TokenStream::from_str(&field.name.to_snake_case()).unwrap();
120 let doc = generate_doc_comments(field.docs.clone());
121 let field_type = generate_field_type(idl, &field.field_type, generate_for);
122
123 let _pub = if is_enum_struct_field {
124 quote! {}
125 } else {
126 quote! { pub }
127 };
128
129 generated.extend(quote! {
130 #doc
131 #_pub #name: #field_type,
132 });
133 }
134
135 generated
136}