pallet_evm_polkavm_uapi/
macros.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18/// Utility macro to read input passed to a contract.
19///
20/// Example:
21/// ```ignore
22/// input!(
23///         var1: u32,      // [0, 4)   var1 decoded as u32
24///         var2: [u8; 32], // [4, 36)  var2 decoded as a [u8] slice
25///         var3: u8,       // [36, 37) var3 decoded as a u8
26/// );
27///
28/// // Input and size can be specified as well:
29/// input!(
30///         input,      // input buffer (optional)
31///         512,        // input size (optional)
32///         var4: u32,  // [0, 4)  var4 decoded as u32
33///         var5: [u8], // [4, ..) var5 decoded as a [u8] slice
34/// );
35/// ```
36#[macro_export]
37macro_rules! input {
38	(@inner $input:expr, $cursor:expr,) => {};
39	(@size $size:expr, ) => { $size };
40
41	// Match a u8 variable.
42	// e.g input!(var1: u8, );
43	(@inner $input:expr, $cursor:expr, $var:ident: u8, $($rest:tt)*) => {
44		let $var = $input[$cursor];
45		input!(@inner $input, $cursor + 1, $($rest)*);
46	};
47
48	// Size of u8 variable.
49	(@size $size:expr, $var:ident: u8, $($rest:tt)*) => {
50		input!(@size $size + 1, $($rest)*)
51	};
52
53	// Match a u64 variable.
54	// e.g input!(var1: u64, );
55	(@inner $input:expr, $cursor:expr, $var:ident: u64, $($rest:tt)*) => {
56		let $var = u64::from_le_bytes($input[$cursor..$cursor + 8].try_into().unwrap());
57		input!(@inner $input, $cursor + 8, $($rest)*);
58	};
59
60	// Size of u64 variable.
61	(@size $size:expr, $var:ident: u64, $($rest:tt)*) => {
62		input!(@size $size + 8, $($rest)*)
63	};
64
65	// Match a u32 variable.
66	// e.g input!(var1: u32, );
67	(@inner $input:expr, $cursor:expr, $var:ident: u32, $($rest:tt)*) => {
68		let $var = u32::from_le_bytes($input[$cursor..$cursor + 4].try_into().unwrap());
69		input!(@inner $input, $cursor + 4, $($rest)*);
70	};
71
72	// Size of u32 variable.
73	(@size $size:expr, $var:ident: u32, $($rest:tt)*) => {
74		input!(@size $size + 4, $($rest)*)
75	};
76
77	// Match a u8 slice with the remaining bytes.
78	// e.g input!(512, var1: [u8; 32], var2: [u8], );
79	(@inner $input:expr, $cursor:expr, $var:ident: [u8],) => {
80		let $var = &$input[$cursor..];
81	};
82
83	// Match a u8 slice of the given size.
84	// e.g input!(var1: [u8; 32], );
85	(@inner $input:expr, $cursor:expr, $var:ident: [u8; $n:expr], $($rest:tt)*) => {
86		let $var = &$input[$cursor..$cursor+$n];
87		input!(@inner $input, $cursor + $n, $($rest)*);
88	};
89
90	// Match an array reference of the given size.
91	// e.g input!(var1: &[u8; 32], );
92	(@inner $input:expr, $cursor:expr, $var:ident: &[u8; $n:expr], $($rest:tt)*) => {
93		let $var: &[u8; $n] = &$input[$cursor..$cursor+$n].try_into().unwrap();
94		input!(@inner $input, $cursor + $n, $($rest)*);
95	};
96
97	// Size of a u8 slice.
98	(@size $size:expr, $var:ident: [u8; $n:expr], $($rest:tt)*) => {
99		input!(@size $size + $n, $($rest)*)
100	};
101
102	// Size of an array reference.
103	(@size $size:expr, $var:ident: &[u8; $n:expr], $($rest:tt)*) => {
104		input!(@size $size + $n, $($rest)*)
105	};
106
107	// Entry point, with the buffer and it's size specified first.
108	// e.g input!(buffer, 512, var1: u32, var2: [u8], );
109	($buffer:ident, $size:expr, $($rest:tt)*) => {
110		let mut $buffer = [0u8; $size];
111		let input_size = $crate::HostFnImpl::call_data_size();
112		let $buffer = &mut &mut $buffer[..$size.min(input_size as usize)];
113		$crate::HostFnImpl::call_data_copy($buffer, 0);
114		input!(@inner $buffer, 0, $($rest)*);
115	};
116
117	// Entry point, with the name of the buffer specified and size of the input buffer computed.
118	// e.g input!(buffer, var1: u32, var2: u64, );
119	($buffer: ident, $($rest:tt)*) => {
120		input!($buffer, input!(@size 0, $($rest)*), $($rest)*);
121	};
122
123	// Entry point, with the size of the input buffer computed.
124	// e.g input!(var1: u32, var2: u64, );
125	($($rest:tt)*) => {
126		input!(buffer, $($rest)*);
127	};
128}
129
130/// Utility macro to invoke a host function that expect a `output: &mut &mut [u8]` as last argument.
131///
132/// Example:
133/// ```ignore
134/// use pallet_revive_uapi::{output, HostFn, HostFnImpl as api};
135///
136/// // call `api::caller` and store the output in `caller`
137/// output!(caller, [0u8; 32], api::caller,);
138///
139/// // call `api::get_storage` and store the output in `address`
140/// output!(address, [0u8; 32], api::get_storage, &[1u8; 32]);
141/// ```
142#[macro_export]
143macro_rules! output {
144	($output: ident, $buffer: expr, $host_fn:path, $($arg:expr),*) => {
145		let mut $output = $buffer;
146		let $output = &mut &mut $output[..];
147		$host_fn($($arg,)* $output);
148	};
149}
150
151/// Similar to `output!` but unwraps the result.
152#[macro_export]
153macro_rules! unwrap_output {
154	($output: ident, $buffer: expr, $host_fn:path, $($arg:expr),*) => {
155		let mut $output = $buffer;
156		let $output = &mut &mut $output[..];
157		$host_fn($($arg,)* $output).unwrap();
158	};
159}
160
161/// Call the host function and convert the [u8; 32] output to u64.
162#[macro_export]
163macro_rules! u64_output {
164	($host_fn:path, $($arg:expr),*) => {{
165		let mut buffer = [1u8; 32];
166		$host_fn($($arg,)* &mut buffer);
167		assert!(buffer[8..].iter().all(|&x| x == 0));
168		u64::from_le_bytes(buffer[..8].try_into().unwrap())
169	}};
170}