smart_contract/
payload.rs1use alloc::string::String;
2use alloc::{vec, vec::Vec};
3
4pub trait Writeable {
5 fn write_to(&self, buffer: &mut Vec<u8>);
6}
7
8macro_rules! writeable {
9 ( $($x:ident), *) => {
10 $(
11 impl Writeable for $x {
12 fn write_to(&self, buffer: &mut Vec<u8>) {
13 unsafe {
14 let x = ::alloc::slice::from_raw_parts(self as *const _ as *const u8, ::core::mem::size_of::<Self>());
15 buffer.extend_from_slice(x);
16 }
17 }
18 }
19 )*
20 }
21}
22
23macro_rules! writeable_array {
24 ( $n:expr) => {
25 impl<U: Writeable> Writeable for [U; $n] {
26 fn write_to(&self, buffer: &mut Vec<u8>) {
27 for i in self {
28 i.write_to(buffer);
29 }
30 }
31 }
32 };
33}
34
35writeable![usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64];
36writeable_array![32];
37
38impl Writeable for bool {
39 fn write_to(&self, buffer: &mut Vec<u8>) {
40 if *self {
41 1u8.write_to(buffer);
42 } else {
43 0u8.write_to(buffer);
44 }
45 }
46}
47
48impl Writeable for String {
49 fn write_to(&self, buffer: &mut Vec<u8>) {
50 for x in self.chars() {
51 (x as u8).write_to(buffer);
52 }
53
54 0u8.write_to(buffer);
55 }
56}
57
58impl Writeable for str {
59 fn write_to(&self, buffer: &mut Vec<u8>) {
60 for x in self.chars() {
61 (x as u8).write_to(buffer);
62 }
63
64 0u8.write_to(buffer);
65 }
66}
67
68impl<T: Writeable> Writeable for Vec<T> {
69 fn write_to(&self, buffer: &mut Vec<u8>) {
70 self.len().write_to(buffer);
71
72 for x in self {
73 x.write_to(buffer);
74 }
75 }
76}
77
78impl<T: Writeable> Writeable for [T] {
79 fn write_to(&self, buffer: &mut Vec<u8>) {
80 self.len().write_to(buffer);
81
82 for x in self {
83 x.write_to(buffer);
84 }
85 }
86}
87
88pub trait Readable {
89 fn read_from(buffer: &[u8], pos: &mut u64) -> Self;
90}
91
92macro_rules! readable {
93 ( $($x:ident), *) => {
94 $(
95 impl Readable for $x {
96 fn read_from(buffer: &[u8], pos: &mut u64) -> Self {
97 unsafe {
98 let ptr = buffer.as_ptr().offset(*pos as isize);
99
100 let size = ::core::mem::size_of::<$x>();
101
102 let x = ::alloc::slice::from_raw_parts(ptr, size);
103 *pos += size as u64;
104
105 let mut ret: $x = ::core::mem::MaybeUninit::uninit().assume_init();
106 ::core::ptr::copy(x.as_ptr(), &mut ret as *mut _ as *mut u8, ::core::mem::size_of::<$x>());
107
108 ret
109 }
110 }
111 }
112 )*
113 }
114}
115
116macro_rules! readable_array {
117 ( $n:expr) => {
118 impl<U: Readable + Copy + Default> Readable for [U; $n] {
119 fn read_from(buffer: &[u8], pos: &mut u64) -> [U; $n] {
120 let mut buf: [U; $n] = [U::default(); $n];
121
122 for i in 0..$n {
123 buf[i] = U::read_from(buffer, pos);
124 }
125
126 buf
127 }
128 }
129 };
130}
131
132readable![usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64];
133readable_array![32];
134
135impl Readable for bool {
136 fn read_from(buffer: &[u8], pos: &mut u64) -> bool {
137 u8::read_from(buffer, pos) == 1
138 }
139}
140
141impl Readable for String {
142 fn read_from(buffer: &[u8], pos: &mut u64) -> String {
143 let mut buf = vec![];
144
145 loop {
146 let chr = u8::read_from(buffer, pos);
147
148 if chr == 0 {
149 break;
150 }
151
152 buf.push(chr);
153 }
154
155 String::from_utf8(buf).unwrap()
156 }
157}
158
159impl<U: Readable> Readable for Vec<U> {
160 fn read_from(buffer: &[u8], pos: &mut u64) -> Vec<U> {
161 let mut buf: Vec<U> = vec![];
162 let len = usize::read_from(buffer, pos);
163
164 for _ in 0..len {
165 buf.push(U::read_from(buffer, pos));
166 }
167
168 buf
169 }
170}
171
172#[derive(Default)]
174pub struct Parameters {
175 pub round_idx: u64,
176 pub round_id: [u8; 32],
177 pub transaction_id: [u8; 32],
178 pub sender: [u8; 32],
179 pub amount: u64, parameters: Vec<u8>,
182 pos: u64,
183}
184
185impl Parameters {
186 pub fn load() -> Parameters {
187 let payload_len = unsafe { crate::sys::_payload_len() };
188 let mut payload_bytes = Vec::with_capacity(payload_len);
189
190 unsafe {
191 payload_bytes.set_len(payload_len);
192 crate::sys::_payload(payload_bytes.as_mut_ptr())
193 }
194
195 let mut parameters = Parameters::default();
196 parameters.parameters = payload_bytes;
197
198 parameters.round_idx = parameters.read();
199 parameters.round_id = parameters.read();
200 parameters.transaction_id = parameters.read();
201 parameters.sender = parameters.read();
202 parameters.amount = parameters.read();
203
204 parameters
205 }
206
207 pub fn read<T: Readable>(&mut self) -> T {
208 T::read_from(&self.parameters, &mut self.pos)
209 }
210}
211
212#[derive(Default)]
213pub struct ParametersBuilder {
214 params: Parameters,
215}
216
217impl ParametersBuilder {
218 pub fn new() -> ParametersBuilder {
219 Default::default()
220 }
221
222 pub fn with_round_idx(self, round_idx: u64) -> Self {
223 Self {
224 params: Parameters {
225 round_idx,
226 ..self.params
227 },
228 }
229 }
230
231 pub fn with_round_id(self, round_id: [u8; 32]) -> Self {
232 Self {
233 params: Parameters {
234 round_id,
235 ..self.params
236 },
237 }
238 }
239
240 pub fn with_transaction_id(self, transaction_id: [u8; 32]) -> Self {
241 Self {
242 params: Parameters {
243 transaction_id,
244 ..self.params
245 },
246 }
247 }
248
249 pub fn with_sender(self, sender: [u8; 32]) -> Self {
250 Self {
251 params: Parameters {
252 sender,
253 ..self.params
254 },
255 }
256 }
257
258 pub fn with_amount(self, amount: u64) -> Self {
259 Self {
260 params: Parameters {
261 amount,
262 ..self.params
263 },
264 }
265 }
266
267 pub fn write<T: Writeable + ?Sized>(&mut self, x: &T) {
268 x.write_to(&mut self.params.parameters);
269 }
270
271 pub fn build(self) -> Parameters {
272 self.params
273 }
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279
280 #[test]
281 fn test_parameters_builder() {
282 const ROUND_IDX: u64 = 100;
283 const ROUND_ID: [u8; 32] = [42; 32];
284 const TRANSACTION_ID: [u8; 32] = [0; 32];
285 const SENDER: [u8; 32] = [1; 32];
286 const AMOUNT: u64 = 20;
287
288 let mut builder = ParametersBuilder::new()
289 .with_round_idx(ROUND_IDX)
290 .with_round_id(ROUND_ID)
291 .with_transaction_id(TRANSACTION_ID)
292 .with_sender(SENDER)
293 .with_amount(AMOUNT);
294
295 builder.write(&100u64);
296 builder.write("Hello");
297
298 let mut params = builder.build();
299
300 assert_eq!(params.round_idx, ROUND_IDX);
301 assert_eq!(params.round_id, ROUND_ID);
302 assert_eq!(params.transaction_id, TRANSACTION_ID);
303 assert_eq!(params.sender, SENDER);
304 assert_eq!(params.amount, AMOUNT);
305
306 assert_eq!(params.read::<u64>(), 100);
307 assert_eq!(params.read::<String>(), "Hello");
308 }
309}