ethbind_rust/gen/
generator.rs

1use ethbind_gen::Generator;
2use ethbind_json::*;
3use heck::{ToSnakeCase, ToUpperCamelCase};
4use quote::{format_ident, quote};
5
6use crate::RustGenerator;
7
8impl Generator for RustGenerator {
9    fn begin<R: ethbind_gen::RuntimeBinder>(
10        &mut self,
11        _runtime_binder: &mut R,
12        name: &str,
13    ) -> anyhow::Result<()> {
14        self.new_contract(name);
15
16        Ok(())
17    }
18
19    fn end<R: ethbind_gen::RuntimeBinder>(
20        &mut self,
21        _runtime_binder: &mut R,
22        _name: &str,
23    ) -> anyhow::Result<()> {
24        Ok(())
25    }
26
27    fn finalize<R: ethbind_gen::RuntimeBinder>(
28        self,
29        runtime_binder: &mut R,
30    ) -> anyhow::Result<Vec<ethbind_gen::Contract>> {
31        let client_type = self.to_runtime_type_token_stream(runtime_binder, "rt_client")?;
32        let adress = self.to_runtime_type_token_stream(runtime_binder, "address")?;
33
34        let mut contracts = vec![];
35
36        for c in &self.contracts {
37            contracts.push(c.finalize(&client_type, &adress)?);
38        }
39
40        Ok(contracts)
41    }
42
43    fn generate_deploy<R: ethbind_gen::RuntimeBinder>(
44        &mut self,
45        runtime_binder: &mut R,
46        contructor: &Constructor,
47        deploy_bytes: &str,
48    ) -> anyhow::Result<()> {
49        let client_type = self.to_runtime_type_token_stream(runtime_binder, "rt_client")?;
50
51        let opts_type = self.to_runtime_type_token_stream(runtime_binder, "rt_opts")?;
52
53        let abi_encode = self.to_runtime_type_token_stream(runtime_binder, "rt_abi_serialize")?;
54
55        let error_type = self.to_runtime_type_token_stream(runtime_binder, "rt_error")?;
56
57        let generic_list = self.to_generic_list(runtime_binder, &contructor.inputs)?;
58
59        let param_list = self.to_param_list(runtime_binder, &contructor.inputs)?;
60
61        let where_clause_list = self.to_where_clause_list(runtime_binder, &contructor.inputs)?;
62
63        let try_into_list = self.to_try_into_list(runtime_binder, &contructor.inputs)?;
64
65        let abi_encode_list = self.to_abi_encode_list(runtime_binder, &contructor.inputs)?;
66
67        let fn_signature = contructor.signature();
68
69        self.current_contract().add_fn_token_stream(quote! {
70            pub async fn deploy_with<C, #(#generic_list,)* Ops>(client: C, #(#param_list,)* ops: Ops) -> std::result::Result<Self,#error_type>
71            where C: TryInto<#client_type>, C::Error: std::error::Error + Sync + Send + 'static,
72            Ops: TryInto<#opts_type>, Ops::Error: std::error::Error + Sync + Send + 'static,
73            #(#where_clause_list,)*
74            {
75                let mut client = client.try_into()?;
76                #(#try_into_list;)*
77                let ops = ops.try_into()?;
78
79                let outputs = #abi_encode(&#abi_encode_list)?;
80
81                let address = client.deploy_contract(#fn_signature, outputs,#deploy_bytes,ops).await?;
82
83                Ok(Self{ client, address })
84            }
85
86            pub async fn deploy<C, #(#generic_list,)* Ops>(client: C, #(#param_list,)*) -> std::result::Result<Self,#error_type>
87            where C: TryInto<#client_type>, C::Error: std::error::Error + Sync + Send + 'static,
88            #(#where_clause_list,)*
89            {
90                let mut client = client.try_into()?;
91                #(#try_into_list;)*
92            
93                let outputs = #abi_encode(&#abi_encode_list)?;
94
95                let address = client.deploy_contract(#fn_signature, outputs,#deploy_bytes, Default::default()).await?;
96
97                Ok(Self{ client, address })
98            }
99        });
100
101        Ok(())
102    }
103
104    fn generate_error<R: ethbind_gen::RuntimeBinder>(
105        &mut self,
106        _runtime_binder: &mut R,
107        _error: &Error,
108    ) -> anyhow::Result<()> {
109        // Skip generate error binding code
110        Ok(())
111    }
112
113    fn generate_event<R: ethbind_gen::RuntimeBinder>(
114        &mut self,
115        runtime_binder: &mut R,
116        event: &Event,
117    ) -> anyhow::Result<()> {
118        log::trace!("generate event {}", event.name);
119
120        let event_field_list = self.to_event_field_list(runtime_binder, &event.inputs)?;
121
122        let serialize_derive_macro =
123            self.to_runtime_type_token_stream(runtime_binder, "rt_serialize_derive")?;
124
125        let deserialize_derive_macro =
126            self.to_runtime_type_token_stream(runtime_binder, "rt_deserialize_derive")?;
127
128        let event_ident = format_ident!(
129            "{}{}",
130            self.current_contract().contract_name.to_upper_camel_case(),
131            event.name.to_upper_camel_case()
132        );
133
134        let abi_json = serde_json::to_string(event)?;
135
136        self.current_contract().add_event_token_stream(quote! {
137            #[derive(#serialize_derive_macro,#deserialize_derive_macro)]
138            pub struct #event_ident {
139                #(#event_field_list,)*
140            }
141
142            impl #event_ident {
143                pub fn abi_json() -> &'static str {
144                    #abi_json
145                }
146            }
147        });
148    
149        Ok(())
150    }
151
152    fn generate_fn<R: ethbind_gen::RuntimeBinder>(
153        &mut self,
154        runtime_binder: &mut R,
155        function: &Function,
156    ) -> anyhow::Result<()> {
157        log::trace!("genearte fn {}", function.name);
158
159        let opts_type = self.to_runtime_type_token_stream(runtime_binder, "rt_opts")?;
160
161        let error_type = self.to_runtime_type_token_stream(runtime_binder, "rt_error")?;
162
163        let abi_decode = self.to_runtime_type_token_stream(runtime_binder, "rt_abi_deserialize")?;
164
165        let abi_encode = self.to_runtime_type_token_stream(runtime_binder, "rt_abi_serialize")?;
166
167        let receipt_type = self.to_runtime_type_token_stream(runtime_binder, "rt_receipt")?;
168
169        let generic_list = self.to_generic_list(runtime_binder, &function.inputs)?;
170
171        let param_list = self.to_param_list(runtime_binder, &function.inputs)?;
172
173        let where_clause_list = self.to_where_clause_list(runtime_binder, &function.inputs)?;
174
175        let try_into_list = self.to_try_into_list(runtime_binder, &function.inputs)?;
176
177        let abi_encode_list = self.to_abi_encode_list(runtime_binder, &function.inputs)?;
178
179        let outputs_type = self.to_outputs_type(runtime_binder, &function.outputs)?;
180
181        let fn_ident = format_ident!("{}", function.name.to_snake_case());
182        let fn_with_ident = format_ident!("{}_with", function.name.to_snake_case());
183
184        let send_transaction = match function.state_mutability {
185            StateMutability::Pure | StateMutability::View => false,
186            _ => true,
187        };
188
189        let fn_signature = function.signature();
190
191        if send_transaction {
192            self.current_contract().add_fn_token_stream(quote! {
193                pub async fn #fn_with_ident<Ops, #(#generic_list,)* >(&self, #(#param_list,)* ops: Ops) -> std::result::Result<#receipt_type,#error_type>
194                where Ops: TryInto<#opts_type>, Ops::Error: std::error::Error + Sync + Send + 'static, #(#where_clause_list,)*
195                {
196                    #(#try_into_list;)*
197                    let ops = ops.try_into()?;
198
199                    let outputs = #abi_encode(&#abi_encode_list)?;
200
201                    self.client.send_raw_transaction(#fn_signature, &self.address, outputs,ops).await
202                }
203
204                pub async fn #fn_ident<#(#generic_list,)* >(&self, #(#param_list,)*) -> std::result::Result<#receipt_type,#error_type>
205                where #(#where_clause_list,)*
206                {
207                    #(#try_into_list;)*
208                  
209                    let outputs = #abi_encode(&#abi_encode_list)?;
210
211                    self.client.send_raw_transaction(#fn_signature, &self.address, outputs, Default::default()).await
212                }
213            });
214        } else {
215            self.current_contract().add_fn_token_stream(quote! {
216                pub async fn #fn_ident<#(#generic_list,)* >(&self, #(#param_list,)*) -> std::result::Result<#outputs_type,#error_type>
217                where #(#where_clause_list,)*
218                {
219                    #(#try_into_list;)*
220
221                    let outputs = #abi_encode(&#abi_encode_list)?;
222
223                    let inputs = self.client.eth_call(#fn_signature, &self.address, outputs).await?;
224
225                    Ok(#abi_decode(inputs)?)
226                }
227            });
228        }
229
230        Ok(())
231    }
232}