1use core::marker::PhantomData;
16use ink_prelude::vec::Vec;
17use ink_primitives::{
18 abi::{
19 AbiEncodeWith,
20 Ink,
21 Sol,
22 },
23 SolEncode,
24};
25
26use super::{
27 selector::Selector,
28 utils::{
29 DecodeMessageResult,
30 ReturnType,
31 },
32};
33use crate::Environment;
34
35pub struct Execution<Args, Output, Abi> {
37 pub input: ExecutionInput<Args, Abi>,
39 pub output: ReturnType<Output>,
41}
42
43impl<Args, Output, Abi> Execution<Args, Output, Abi>
44where
45 Args: AbiEncodeWith<Abi>,
46 Output: DecodeMessageResult<Abi>,
47{
48 pub fn new(input: ExecutionInput<Args, Abi>) -> Self {
50 Self {
51 input,
52 output: ReturnType::default(),
53 }
54 }
55
56 pub fn exec<I, E>(
58 self,
59 executor: &I,
60 ) -> Result<ink_primitives::MessageResult<Output>, I::Error>
61 where
62 E: Environment,
63 I: Executor<E>,
64 {
65 executor.exec(&self.input)
66 }
67}
68
69pub trait Executor<E: Environment> {
71 type Error;
73 fn exec<Args, Output, Abi>(
75 &self,
76 input: &ExecutionInput<Args, Abi>,
77 ) -> Result<ink_primitives::MessageResult<Output>, Self::Error>
78 where
79 Args: AbiEncodeWith<Abi>,
80 Output: DecodeMessageResult<Abi>;
81}
82
83#[derive(Clone, Default, Debug)]
85pub struct ExecutionInput<Args, Abi> {
86 selector: Option<Selector>,
88 args: Args,
90 _marker: PhantomData<Abi>,
91}
92
93impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
94 #[inline]
96 pub fn new(selector: Selector) -> Self {
97 Self {
98 selector: Some(selector),
99 args: ArgumentList::empty(),
100 _marker: Default::default(),
101 }
102 }
103}
104
105impl ExecutionInput<EmptyArgumentList<Sol>, Sol> {
106 #[inline]
112 pub fn no_selector() -> Self {
113 Self {
114 selector: None,
115 args: ArgumentList::empty(),
116 _marker: Default::default(),
117 }
118 }
119}
120
121impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
122 #[inline]
124 pub fn push_arg<T>(
125 self,
126 arg: T,
127 ) -> ExecutionInput<ArgumentList<Argument<T>, EmptyArgumentList<Abi>, Abi>, Abi>
128 where
129 T: AbiEncodeWith<Abi>,
130 {
131 ExecutionInput {
132 selector: self.selector,
133 args: self.args.push_arg(arg),
134 _marker: Default::default(),
135 }
136 }
137}
138
139impl<Head, Rest, Abi> ExecutionInput<ArgumentList<Argument<Head>, Rest, Abi>, Abi> {
140 #[allow(clippy::type_complexity)]
142 #[inline]
143 pub fn push_arg<T>(
144 self,
145 arg: T,
146 ) -> ExecutionInput<ArgsList<T, ArgsList<Head, Rest, Abi>, Abi>, Abi>
147 where
148 T: AbiEncodeWith<Abi>,
149 {
150 ExecutionInput {
151 selector: self.selector,
152 args: self.args.push_arg(arg),
153 _marker: Default::default(),
154 }
155 }
156}
157
158impl<Args, Abi> ExecutionInput<Args, Abi> {
159 pub fn update_selector(&mut self, selector: Selector) {
164 self.selector = Some(selector);
165 }
166}
167
168impl<Args, Abi> ExecutionInput<Args, Abi>
169where
170 Args: AbiEncodeWith<Abi>,
171{
172 pub fn encode(&self) -> Vec<u8> {
175 let mut encoded = Vec::new();
176 if let Some(selector) = &self.selector {
177 encoded.extend(selector.to_bytes());
178 }
179 self.args.encode_to_vec(&mut encoded);
180 encoded
181 }
182
183 pub fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
186 let selector_len = if let Some(selector) = &self.selector {
187 let selector_bytes = selector.to_bytes();
188 let selector_len = selector_bytes.len();
189 buffer[..selector_len].copy_from_slice(&selector_bytes);
190 selector_len
191 } else {
192 0
193 };
194 let args_len = self.args.encode_to_slice(&mut buffer[selector_len..]);
195 selector_len + args_len
196 }
197}
198
199#[derive(Clone, Default, Debug)]
207pub struct ArgumentList<Head, Rest, Abi> {
208 head: Head,
210 rest: Rest,
212 _marker: PhantomData<Abi>,
213}
214
215pub type ArgsList<Head, Rest, Abi> = ArgumentList<Argument<Head>, Rest, Abi>;
217
218#[derive(Clone, Debug)]
220pub struct Argument<T> {
221 arg: T,
225}
226
227impl<T> Argument<T> {
228 #[inline]
230 fn new(arg: T) -> Self {
231 Self { arg }
232 }
233}
234
235#[derive(Clone, Default, Debug)]
237pub struct ArgumentListEnd;
238
239pub type EmptyArgumentList<Abi> = ArgumentList<ArgumentListEnd, ArgumentListEnd, Abi>;
241
242impl<Abi> EmptyArgumentList<Abi> {
243 #[inline]
245 pub fn empty() -> EmptyArgumentList<Abi> {
246 ArgumentList {
247 head: ArgumentListEnd,
248 rest: ArgumentListEnd,
249 _marker: Default::default(),
250 }
251 }
252
253 #[inline]
255 pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
256 where
257 T: AbiEncodeWith<Abi>,
258 {
259 ArgumentList {
260 head: Argument::new(arg),
261 rest: self,
262 _marker: Default::default(),
263 }
264 }
265}
266
267impl<Head, Rest, Abi> ArgumentList<Argument<Head>, Rest, Abi> {
268 #[inline]
270 pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
271 where
272 T: AbiEncodeWith<Abi>,
273 {
274 ArgumentList {
275 head: Argument::new(arg),
276 rest: self,
277 _marker: Default::default(),
278 }
279 }
280}
281
282impl<T> scale::Encode for Argument<T>
283where
284 T: scale::Encode,
285{
286 #[inline]
287 fn size_hint(&self) -> usize {
288 <T as scale::Encode>::size_hint(&self.arg)
289 }
290
291 #[inline]
292 fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
293 <T as scale::Encode>::encode_to(&self.arg, output)
294 }
295}
296
297impl scale::Encode for EmptyArgumentList<Ink> {
298 #[inline]
299 fn size_hint(&self) -> usize {
300 0
301 }
302
303 #[inline]
304 fn encode_to<O: scale::Output + ?Sized>(&self, _output: &mut O) {}
305}
306
307impl<Head, Rest> scale::Encode for ArgumentList<Argument<Head>, Rest, Ink>
308where
309 Head: scale::Encode,
310 Rest: scale::Encode,
311{
312 #[inline]
313 fn size_hint(&self) -> usize {
314 scale::Encode::size_hint(&self.head)
315 .checked_add(scale::Encode::size_hint(&self.rest))
316 .expect("unable to checked_add")
317 }
318
319 #[inline]
320 fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
321 scale::Encode::encode_to(&self.rest, output);
326 scale::Encode::encode_to(&self.head, output);
327 }
328}
329
330impl<Args> scale::Encode for ExecutionInput<Args, Ink>
331where
332 Args: scale::Encode,
333{
334 #[inline]
335 fn size_hint(&self) -> usize {
336 let selector_size = match &self.selector {
337 None => 0,
338 Some(_) => scale::Encode::size_hint(&self.selector),
339 };
340 selector_size
341 .checked_add(scale::Encode::size_hint(&self.args))
342 .expect("unable to checked_add")
343 }
344
345 #[inline]
346 fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
347 if let Some(selector) = &self.selector {
348 scale::Encode::encode_to(selector, output);
349 }
350 scale::Encode::encode_to(&self.args, output);
351 }
352}
353
354impl<'a, T> SolEncode<'a> for Argument<T>
355where
356 T: SolEncode<'a>,
357{
358 type SolType = <T as SolEncode<'a>>::SolType;
359
360 fn to_sol_type(&'a self) -> Self::SolType {
361 self.arg.to_sol_type()
362 }
363}
364
365impl SolEncode<'_> for EmptyArgumentList<Sol> {
366 type SolType = ();
367
368 fn encode(&self) -> Vec<u8> {
369 Vec::new()
370 }
371
372 fn to_sol_type(&self) {}
374}
375
376impl<Head, Rest> SolEncode<'_> for ArgumentList<Argument<Head>, Rest, Sol>
377where
378 Self: SolEncodeArgsList,
379{
380 type SolType = ();
382
383 fn encode(&self) -> Vec<u8> {
384 let mut head = Vec::new();
386 let mut tail = Vec::new();
387 let mut offset = self.encode_args(&mut head, &mut tail);
388
389 head.into_iter()
392 .flat_map(|info| {
393 match info {
394 SolEncodeHeadInfo::Bytes(encoded) => encoded,
395 SolEncodeHeadInfo::Size(size) => {
396 let encoded_offset = SolEncode::encode(&(offset as u128));
397 offset += size;
398 encoded_offset
399 }
400 }
401 })
402 .chain(tail)
403 .collect()
404 }
405
406 fn to_sol_type(&self) {}
408}
409
410trait SolEncodeArgsList {
412 fn encode_args(&self, head: &mut Vec<SolEncodeHeadInfo>, tail: &mut Vec<u8>)
417 -> usize;
418}
419
420enum SolEncodeHeadInfo {
422 Bytes(Vec<u8>),
424 Size(usize),
426}
427
428impl SolEncodeArgsList for EmptyArgumentList<Sol> {
429 fn encode_args(&self, _: &mut Vec<SolEncodeHeadInfo>, _: &mut Vec<u8>) -> usize {
430 0
431 }
432}
433
434impl<Head, Rest> SolEncodeArgsList for ArgumentList<Argument<Head>, Rest, Sol>
435where
436 Head: for<'a> SolEncode<'a>,
437 Rest: SolEncodeArgsList,
438{
439 fn encode_args(
440 &self,
441 head: &mut Vec<SolEncodeHeadInfo>,
442 tail: &mut Vec<u8>,
443 ) -> usize {
444 let mut offset = self.rest.encode_args(head, tail);
445 let encoded = self.head.arg.encode();
446 if <Head as SolEncode>::DYNAMIC {
447 offset += 32;
450 let data = &encoded[32..];
452 head.push(SolEncodeHeadInfo::Size(data.len()));
453 tail.extend(data);
454 } else {
455 offset += encoded.len();
456 head.push(SolEncodeHeadInfo::Bytes(encoded));
457 }
458
459 offset
460 }
461}
462
463#[cfg(test)]
464mod tests {
465 use super::*;
466
467 #[test]
468 fn empty_exec_input_works() {
469 let selector = Selector::new([0x01, 0x02, 0x03, 0x04]);
470 let exec_input = ExecutionInput::new(selector);
471 let encoded = scale::Encode::encode(&exec_input);
472 assert!(!encoded.is_empty());
473 let decoded = <Selector as scale::Decode>::decode(&mut &encoded[..]).unwrap();
474 assert_eq!(decoded, selector);
475 }
476
477 #[test]
478 fn empty_args_works() {
479 let empty_list = ArgumentList::empty();
480 let encoded = scale::Encode::encode(&empty_list);
481 assert_eq!(encoded, <Vec<u8>>::new());
482 }
483
484 #[test]
485 fn single_argument_works() {
486 let empty_list = ArgumentList::empty().push_arg(&1i32);
487 let encoded = scale::Encode::encode(&empty_list);
488 assert!(!encoded.is_empty());
489 let decoded = <i32 as scale::Decode>::decode(&mut &encoded[..]).unwrap();
490 assert_eq!(decoded, 1i32);
491 }
492
493 #[test]
494 fn multiple_arguments_works() {
495 let empty_list = ArgumentList::empty()
496 .push_arg(&42i32)
497 .push_arg(&true)
498 .push_arg(&[0x66u8; 4]);
499 let encoded = scale::Encode::encode(&empty_list);
500 assert!(!encoded.is_empty());
501 let decoded =
502 <(i32, bool, [u8; 4]) as scale::Decode>::decode(&mut &encoded[..]).unwrap();
503 assert_eq!(decoded, (42i32, true, [0x66; 4]));
504 }
505
506 #[test]
507 fn sol_encoding_arguments_works() {
508 let args_list = EmptyArgumentList::<Sol>::empty()
509 .push_arg(100u8)
510 .push_arg(vec![1, 2, 3, 4])
511 .push_arg(String::from("Hello, world!"))
512 .push_arg(true);
513 let encoded_args_list = SolEncode::encode(&args_list);
514
515 let args_tuple = (100u8, vec![1, 2, 3, 4], String::from("Hello, world!"), true);
516 let encoded_args_tuple =
517 ink_primitives::sol::SolParamsEncode::encode(&args_tuple);
518
519 assert_eq!(encoded_args_list, encoded_args_tuple);
520 }
521}