1extern crate proc_macro;
2
3use concordium_contracts_common::{
4 AccountAddress, ContractAddress, ModuleReference, PublicKeyEcdsaSecp256k1, PublicKeyEd25519,
5 SignatureEcdsaSecp256k1, SignatureEd25519,
6};
7use proc_macro::TokenStream;
8use proc_macro2::{Group, Punct, Spacing, Span};
9use quote::{quote, ToTokens};
10use std::str::FromStr;
11use syn::LitStr;
12
13fn tokenize_slice(slice: &[u8]) -> proc_macro2::TokenStream {
17 let mut t = proc_macro2::TokenStream::new();
18 for byte in slice {
19 byte.to_tokens(&mut t);
20 Punct::new(',', Spacing::Alone).to_tokens(&mut t);
21 }
22 Group::new(proc_macro2::Delimiter::Bracket, t).to_token_stream()
23}
24
25fn parse_input(item: TokenStream, msg: &str) -> syn::Result<LitStr> {
28 match syn::parse::<LitStr>(item) {
29 Ok(string_literal) => Ok(string_literal),
30 Err(_) => Err(syn::Error::new(Span::call_site(), msg)),
31 }
32}
33
34fn get_token_res(
37 item: TokenStream,
38 msg: &str,
39 worker_fun: impl FnOnce(String, Span) -> syn::Result<TokenStream>,
40) -> syn::Result<TokenStream> {
41 let input = parse_input(item, msg)?;
42 worker_fun(input.value(), input.span())
43}
44
45fn get_token_res_env(
49 item: TokenStream,
50 msg: &str,
51 worker_fun: impl FnOnce(String, Span) -> syn::Result<TokenStream>,
52) -> syn::Result<TokenStream> {
53 let input = parse_input(item, msg)?;
54 let environment_var_value = match std::env::var(input.value()) {
55 Ok(value) => value,
56 Err(e) => {
57 return Err(syn::Error::new(
58 input.span(),
59 format!("Environment variable error: {:?}", e),
60 ))
61 }
62 };
63 worker_fun(environment_var_value, input.span())
64}
65
66fn unwrap_or_report(res: syn::Result<TokenStream>) -> TokenStream {
67 res.unwrap_or_else(|e| e.into_compile_error().into())
68}
69
70fn acc_address_worker(str: String, span: Span) -> syn::Result<TokenStream> {
73 let address = match AccountAddress::from_str(&str) {
74 Ok(addr) => tokenize_slice(&addr.0),
75 Err(e) => return Err(syn::Error::new(span, format!("Invalid account address: {}", e))),
76 };
77
78 Ok(quote!(concordium_std::AccountAddress(#address)).into())
79}
80
81fn pubkey_ed25519_worker(str: String, span: Span) -> syn::Result<TokenStream> {
82 let public_key = match PublicKeyEd25519::from_str(&str) {
83 Ok(pk) => tokenize_slice(&pk.0),
84 Err(e) => return Err(syn::Error::new(span, format!("Invalid Ed25519 public key: {}", e))),
85 };
86
87 Ok(quote!(concordium_std::PublicKeyEd25519(#public_key)).into())
88}
89
90fn pubkey_ecdsa_worker(str: String, span: Span) -> syn::Result<TokenStream> {
91 let public_key = match PublicKeyEcdsaSecp256k1::from_str(&str) {
92 Ok(pk) => tokenize_slice(&pk.0),
93 Err(e) => return Err(syn::Error::new(span, format!("Invalid ECDSA public key: {}", e))),
94 };
95
96 Ok(quote!(concordium_std::PublicKeyEcdsaSecp256k1(#public_key)).into())
97}
98
99fn signature_ed25519_worker(str: String, span: Span) -> syn::Result<TokenStream> {
100 let signature = match SignatureEd25519::from_str(&str) {
101 Ok(sig) => tokenize_slice(&sig.0),
102 Err(e) => return Err(syn::Error::new(span, format!("Invalid Ed25519 signature: {}", e))),
103 };
104
105 Ok(quote!(concordium_std::SignatureEd25519(#signature)).into())
106}
107
108fn signature_ecdsa_worker(str: String, span: Span) -> syn::Result<TokenStream> {
109 let signature = match SignatureEcdsaSecp256k1::from_str(&str) {
110 Ok(sig) => tokenize_slice(&sig.0),
111 Err(e) => return Err(syn::Error::new(span, format!("Invalid ECDSA signature: {}", e))),
112 };
113
114 Ok(quote!(concordium_std::SignatureEcdsaSecp256k1(#signature)).into())
115}
116
117fn contract_address_worker(str: String, span: Span) -> syn::Result<TokenStream> {
118 let (index, subindex) = match ContractAddress::from_str(&str) {
119 Ok(con) => (con.index, con.subindex),
120 Err(e) => return Err(syn::Error::new(span, format!("Invalid contract address: {}", e))),
121 };
122
123 Ok(quote!(concordium_std::ContractAddress::new(#index, #subindex)).into())
124}
125
126fn module_ref_worker(str: String, span: Span) -> syn::Result<TokenStream> {
127 let module_ref = match ModuleReference::from_str(&str) {
128 Ok(mod_ref) => tokenize_slice(&mod_ref.bytes),
129 Err(e) => return Err(syn::Error::new(span, format!("Invalid module reference: {}", e))),
130 };
131
132 Ok(quote!(concordium_std::ModuleReference::new(#module_ref)).into())
133}
134
135#[proc_macro]
138pub fn account_address(item: TokenStream) -> TokenStream {
139 let msg = "Expected a string literal of a hex-encoded account address";
140 unwrap_or_report(get_token_res(item, msg, acc_address_worker))
141}
142
143#[proc_macro]
147pub fn account_address_env(item: TokenStream) -> TokenStream {
148 let msg = "Expected a string literal of a hex-encoded account address";
149 unwrap_or_report(get_token_res_env(item, msg, acc_address_worker))
150}
151
152#[proc_macro]
156pub fn public_key_ed25519(item: TokenStream) -> TokenStream {
157 let msg = "Expected a string literal of a hex-encoded ED25519 public key";
158 unwrap_or_report(get_token_res(item, msg, pubkey_ed25519_worker))
159}
160
161#[proc_macro]
166pub fn public_key_ed25519_env(item: TokenStream) -> TokenStream {
167 let msg = "Expected a string literal of a hex-encoded ED25519 public key";
168 unwrap_or_report(get_token_res_env(item, msg, pubkey_ed25519_worker))
169}
170
171#[proc_macro]
175pub fn public_key_ecdsa(item: TokenStream) -> TokenStream {
176 let msg = "Expected a string literal of a hex-encoded ECDSA public key";
177 unwrap_or_report(get_token_res(item, msg, pubkey_ecdsa_worker))
178}
179
180#[proc_macro]
185pub fn public_key_ecdsa_env(item: TokenStream) -> TokenStream {
186 let msg = "Expected a string literal of a hex-encoded ECDSA public key";
187 unwrap_or_report(get_token_res_env(item, msg, pubkey_ecdsa_worker))
188}
189
190#[proc_macro]
194pub fn signature_ed25519(item: TokenStream) -> TokenStream {
195 let msg = "Expected a string literal of a hex-encoded ED25519 signature";
196 unwrap_or_report(get_token_res(item, msg, signature_ed25519_worker))
197}
198
199#[proc_macro]
204pub fn signature_ed25519_env(item: TokenStream) -> TokenStream {
205 let msg = "Expected a string literal of a hex-encoded ED25519 signature";
206 unwrap_or_report(get_token_res_env(item, msg, signature_ed25519_worker))
207}
208
209#[proc_macro]
213pub fn signature_ecdsa(item: TokenStream) -> TokenStream {
214 let msg = "Expected a string literal of a hex-encoded ECDSA signature";
215 unwrap_or_report(get_token_res(item, msg, signature_ecdsa_worker))
216}
217
218#[proc_macro]
223pub fn signature_ecdsa_env(item: TokenStream) -> TokenStream {
224 let msg = "Expected a string literal a hex-encoded ECDSA signature";
225 unwrap_or_report(get_token_res_env(item, msg, signature_ecdsa_worker))
226}
227
228#[proc_macro]
232pub fn contract_address(item: TokenStream) -> TokenStream {
233 let msg = "Expected string literal of a contract address in the form of \"<index,subindex>\"";
234 unwrap_or_report(get_token_res(item, msg, contract_address_worker))
235}
236
237#[proc_macro]
242pub fn contract_address_env(item: TokenStream) -> TokenStream {
243 let msg = "Expected string literal of a contract address in the form of \"<index,subindex>\"";
244 unwrap_or_report(get_token_res_env(item, msg, contract_address_worker))
245}
246
247#[proc_macro]
251pub fn module_reference(item: TokenStream) -> TokenStream {
252 let msg = "Expected string literal of a hex-encoded module reference";
253 unwrap_or_report(get_token_res(item, msg, module_ref_worker))
254}
255
256#[proc_macro]
261pub fn module_reference_env(item: TokenStream) -> TokenStream {
262 let msg = "Expected string literal of a hex-encoded module reference";
263 unwrap_or_report(get_token_res_env(item, msg, module_ref_worker))
264}