multiversx_sc_meta_lib/contract/sc_config/
wasm_crate_gen.rs1use multiversx_sc::{abi::EndpointAbi, external_view_contract::EXTERNAL_VIEW_CONSTRUCTOR_FLAG};
2use std::{
3 fs::{self, File},
4 io::Write,
5 path::{Path, PathBuf},
6};
7
8use super::ContractVariant;
9
10const PREFIX_AUTO_GENERATED: &str =
11 "// Code generated by the multiversx-sc build system. DO NOT EDIT.
12
13////////////////////////////////////////////////////
14////////////////// AUTO-GENERATED //////////////////
15////////////////////////////////////////////////////
16";
17
18const NO_STD_ANNOTATION: &str = "#![no_std]
19";
20
21const NUM_INIT: usize = 1;
22const NUM_UPGRADE: usize = 1;
23const NUM_ASYNC_CB: usize = 1;
24
25impl ContractVariant {
26 pub fn create_wasm_crate_dir(&self) {
28 fs::create_dir_all(PathBuf::from(&self.wasm_crate_path()).join("src")).unwrap();
29 }
30
31 fn allocator_macro_invocation(&self) -> String {
32 format!(
33 "multiversx_sc_wasm_adapter::allocator!({});",
34 self.settings.allocator.to_allocator_macro_selector()
35 )
36 }
37
38 #[allow(clippy::collapsible_else_if)]
39 fn panic_handler_macro_invocation(&self) -> &'static str {
40 if self.settings.std {
41 if self.settings.panic_message {
42 "multiversx_sc_wasm_adapter::panic_handler_std_with_message!();"
43 } else {
44 "multiversx_sc_wasm_adapter::panic_handler_std!();"
45 }
46 } else {
47 if self.settings.panic_message {
48 "multiversx_sc_wasm_adapter::panic_handler_with_message!();"
49 } else {
50 "multiversx_sc_wasm_adapter::panic_handler!();"
51 }
52 }
53 }
54
55 fn endpoint_macro_name(&self) -> &'static str {
56 if self.settings.external_view {
57 "multiversx_sc_wasm_adapter::external_view_endpoints!"
58 } else {
59 "multiversx_sc_wasm_adapter::endpoints!"
60 }
61 }
62
63 pub fn generate_wasm_src_lib_file(&self) {
65 let lib_path = Path::new(&self.wasm_crate_path())
66 .join("src")
67 .join("lib.rs");
68 let mut wasm_lib_file = File::create(lib_path).unwrap();
69 self.write_wasm_src_lib_contents(&mut wasm_lib_file);
70 }
71
72 fn write_wasm_src_lib_contents(&self, wasm_lib_file: &mut File) {
73 writeln!(wasm_lib_file, "{PREFIX_AUTO_GENERATED}").unwrap();
74 self.write_stat_comments(wasm_lib_file);
75 self.write_no_std_annotation(wasm_lib_file);
76 writeln!(wasm_lib_file, "{}", self.allocator_macro_invocation()).unwrap();
77 writeln!(wasm_lib_file, "{}", self.panic_handler_macro_invocation()).unwrap();
78
79 if self.settings.external_view {
80 write_external_view_init(wasm_lib_file);
81 }
82
83 let contract_module_name = self.abi.get_crate_name_for_code();
84 write_endpoints_macro(
85 self.endpoint_macro_name(),
86 wasm_lib_file,
87 &contract_module_name,
88 self.abi.iter_all_exports(),
89 );
90
91 write_async_callback_macro(wasm_lib_file, self.abi.has_callback, &contract_module_name);
92 }
93}
94
95fn write_stat_comment(wasm_lib_file: &mut File, label: &str, number: usize) {
96 writeln!(wasm_lib_file, "// {label:<35} {number:3}").unwrap();
97}
98
99impl ContractVariant {
100 fn write_stat_comments(&self, wasm_lib_file: &mut File) {
102 let mut total = self.abi.endpoints.len() + NUM_ASYNC_CB + self.abi.promise_callbacks.len();
103
104 if !self.abi.constructors.is_empty() {
105 write_stat_comment(wasm_lib_file, "Init:", NUM_INIT);
106 total += NUM_INIT;
107 }
108 if !self.abi.upgrade_constructors.is_empty() {
109 write_stat_comment(wasm_lib_file, "Upgrade:", NUM_UPGRADE);
110 total += NUM_UPGRADE;
111 }
112
113 write_stat_comment(wasm_lib_file, "Endpoints:", self.abi.endpoints.len());
114 if self.abi.has_callback {
115 write_stat_comment(wasm_lib_file, "Async Callback:", NUM_ASYNC_CB);
116 } else {
117 write_stat_comment(wasm_lib_file, "Async Callback (empty):", NUM_ASYNC_CB);
118 }
119 if !self.abi.promise_callbacks.is_empty() {
120 write_stat_comment(
121 wasm_lib_file,
122 "Promise callbacks:",
123 self.abi.promise_callbacks.len(),
124 );
125 }
126
127 write_stat_comment(wasm_lib_file, "Total number of exported functions:", total);
128
129 writeln!(wasm_lib_file).unwrap();
130 }
131
132 fn write_no_std_annotation(&self, wasm_lib_file: &mut File) {
133 if !self.settings.std {
134 write_prefix(wasm_lib_file, NO_STD_ANNOTATION);
135 }
136 }
137}
138
139fn write_prefix(wasm_lib_file: &mut File, features: &str) {
140 writeln!(wasm_lib_file, "{}", features).unwrap();
141}
142
143fn write_endpoints_macro<'a, I>(
144 full_macro_name: &str,
145 wasm_lib_file: &mut File,
146 contract_module_name: &str,
147 endpoint_iter: I,
148) where
149 I: Iterator<Item = &'a EndpointAbi>,
150{
151 writeln!(wasm_lib_file).unwrap();
152 writeln!(wasm_lib_file, "{full_macro_name} {{").unwrap();
153 writeln!(wasm_lib_file, " {contract_module_name}").unwrap();
154 writeln!(wasm_lib_file, " (").unwrap();
155 for endpoint in endpoint_iter {
156 if endpoint.rust_method_name == EXTERNAL_VIEW_CONSTRUCTOR_FLAG {
157 continue;
158 }
159 writeln!(
160 wasm_lib_file,
161 " {} => {}",
162 endpoint.name, endpoint.rust_method_name
163 )
164 .unwrap();
165 }
166 writeln!(wasm_lib_file, " )").unwrap();
167 writeln!(wasm_lib_file, "}}").unwrap();
168}
169
170fn write_async_callback_macro(
171 wasm_lib_file: &mut File,
172 has_callback: bool,
173 contract_module_name: &str,
174) {
175 writeln!(wasm_lib_file).unwrap();
176 if has_callback {
177 writeln!(
178 wasm_lib_file,
179 "multiversx_sc_wasm_adapter::async_callback! {{ {contract_module_name} }}"
180 )
181 .unwrap();
182 } else {
183 writeln!(
184 wasm_lib_file,
185 "multiversx_sc_wasm_adapter::async_callback_empty! {{}}",
186 )
187 .unwrap();
188 }
189}
190
191fn write_external_view_init(wasm_lib_file: &mut File) {
192 writeln!(wasm_lib_file).unwrap();
193 writeln!(
194 wasm_lib_file,
195 "multiversx_sc_wasm_adapter::external_view_init! {{}}",
196 )
197 .unwrap();
198}