1use core::marker::PhantomData;
16use ink_prelude::vec::Vec;
17use ink_primitives::{
18 SolEncode,
19 abi::{
20 AbiEncodeWith,
21 Ink,
22 SizedOutput,
23 Sol,
24 },
25 impl_all_tuples,
26 sol::SolTypeParamsEncode,
27};
28
29use super::{
30 selector::Selector,
31 utils::{
32 DecodeMessageResult,
33 ReturnType,
34 },
35};
36use crate::Environment;
37
38pub struct Execution<Args, Output, Abi> {
40 pub input: ExecutionInput<Args, Abi>,
42 pub output: ReturnType<Output>,
44}
45
46impl<Args, Output, Abi> Execution<Args, Output, Abi>
47where
48 Args: EncodeArgsWith<Abi>,
49 Output: DecodeMessageResult<Abi>,
50{
51 pub fn new(input: ExecutionInput<Args, Abi>) -> Self {
53 Self {
54 input,
55 output: ReturnType::default(),
56 }
57 }
58
59 pub fn exec<I, E>(
61 self,
62 executor: &I,
63 ) -> Result<ink_primitives::MessageResult<Output>, I::Error>
64 where
65 E: Environment,
66 I: Executor<E>,
67 {
68 executor.exec(&self.input)
69 }
70}
71
72pub trait Executor<E: Environment> {
74 type Error;
76 fn exec<Args, Output, Abi>(
78 &self,
79 input: &ExecutionInput<Args, Abi>,
80 ) -> Result<ink_primitives::MessageResult<Output>, Self::Error>
81 where
82 Args: EncodeArgsWith<Abi>,
83 Output: DecodeMessageResult<Abi>;
84}
85
86#[derive(Clone, Default, Debug)]
88pub struct ExecutionInput<Args, Abi> {
89 selector: Option<Selector>,
91 args: Args,
93 _marker: PhantomData<Abi>,
94}
95
96impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
97 #[inline]
99 pub fn new(selector: Selector) -> Self {
100 Self {
101 selector: Some(selector),
102 args: ArgumentList::empty(),
103 _marker: Default::default(),
104 }
105 }
106}
107
108impl ExecutionInput<EmptyArgumentList<Sol>, Sol> {
109 #[inline]
115 pub fn no_selector() -> Self {
116 Self {
117 selector: None,
118 args: ArgumentList::empty(),
119 _marker: Default::default(),
120 }
121 }
122}
123
124impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
125 #[inline]
127 pub fn push_arg<T>(
128 self,
129 arg: T,
130 ) -> ExecutionInput<ArgumentList<Argument<T>, EmptyArgumentList<Abi>, Abi>, Abi>
131 where
132 T: AbiEncodeWith<Abi>,
133 {
134 ExecutionInput {
135 selector: self.selector,
136 args: self.args.push_arg(arg),
137 _marker: Default::default(),
138 }
139 }
140}
141
142impl<Head, Rest, Abi> ExecutionInput<ArgumentList<Argument<Head>, Rest, Abi>, Abi> {
143 #[allow(clippy::type_complexity)]
145 #[inline]
146 pub fn push_arg<T>(
147 self,
148 arg: T,
149 ) -> ExecutionInput<ArgsList<T, ArgsList<Head, Rest, Abi>, Abi>, Abi>
150 where
151 T: AbiEncodeWith<Abi>,
152 {
153 ExecutionInput {
154 selector: self.selector,
155 args: self.args.push_arg(arg),
156 _marker: Default::default(),
157 }
158 }
159}
160
161impl<Args, Abi> ExecutionInput<Args, Abi> {
162 pub fn update_selector(&mut self, selector: Selector) {
167 self.selector = Some(selector);
168 }
169}
170
171impl<Args, Abi> ExecutionInput<Args, Abi>
172where
173 Args: EncodeArgsWith<Abi>,
174{
175 pub fn encode(&self) -> Vec<u8> {
178 let mut encoded = Vec::new();
179 if let Some(selector) = &self.selector {
180 encoded.extend(selector.to_bytes());
181 }
182 self.args.encode_to_vec(&mut encoded);
183 encoded
184 }
185
186 pub fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
189 let selector_len = if let Some(selector) = &self.selector {
190 let selector_bytes = selector.to_bytes();
191 let selector_len = selector_bytes.len();
192 buffer[..selector_len].copy_from_slice(&selector_bytes);
193 selector_len
194 } else {
195 0
196 };
197 let args_len = self.args.encode_to(&mut buffer[selector_len..]);
198 selector_len + args_len
199 }
200}
201
202#[derive(Clone, Default, Debug)]
210pub struct ArgumentList<Head, Rest, Abi> {
211 head: Head,
213 rest: Rest,
215 _marker: PhantomData<Abi>,
216}
217
218pub type ArgsList<Head, Rest, Abi> = ArgumentList<Argument<Head>, Rest, Abi>;
220
221#[derive(Clone, Debug)]
223pub struct Argument<T> {
224 arg: T,
228}
229
230impl<T> Argument<T> {
231 #[inline]
233 fn new(arg: T) -> Self {
234 Self { arg }
235 }
236}
237
238#[derive(Clone, Default, Debug)]
240pub struct ArgumentListEnd;
241
242pub type EmptyArgumentList<Abi> = ArgumentList<ArgumentListEnd, ArgumentListEnd, Abi>;
244
245impl<Abi> EmptyArgumentList<Abi> {
246 #[inline]
248 pub fn empty() -> EmptyArgumentList<Abi> {
249 ArgumentList {
250 head: ArgumentListEnd,
251 rest: ArgumentListEnd,
252 _marker: Default::default(),
253 }
254 }
255
256 #[inline]
258 pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
259 where
260 T: AbiEncodeWith<Abi>,
261 {
262 ArgumentList {
263 head: Argument::new(arg),
264 rest: self,
265 _marker: Default::default(),
266 }
267 }
268}
269
270impl<Head, Rest, Abi> ArgumentList<Argument<Head>, Rest, Abi> {
271 #[inline]
273 pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
274 where
275 T: AbiEncodeWith<Abi>,
276 {
277 ArgumentList {
278 head: Argument::new(arg),
279 rest: self,
280 _marker: Default::default(),
281 }
282 }
283}
284
285impl<T> scale::Encode for Argument<T>
286where
287 T: scale::Encode,
288{
289 #[inline]
290 fn size_hint(&self) -> usize {
291 <T as scale::Encode>::size_hint(&self.arg)
292 }
293
294 #[inline]
295 fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
296 <T as scale::Encode>::encode_to(&self.arg, output)
297 }
298}
299
300impl scale::Encode for EmptyArgumentList<Ink> {
301 #[inline]
302 fn size_hint(&self) -> usize {
303 0
304 }
305
306 #[inline]
307 fn encode_to<O: scale::Output + ?Sized>(&self, _output: &mut O) {}
308}
309
310impl<Head, Rest> scale::Encode for ArgumentList<Argument<Head>, Rest, Ink>
311where
312 Head: scale::Encode,
313 Rest: scale::Encode,
314{
315 #[inline]
316 fn size_hint(&self) -> usize {
317 scale::Encode::size_hint(&self.head)
318 .checked_add(scale::Encode::size_hint(&self.rest))
319 .expect("unable to checked_add")
320 }
321
322 #[inline]
323 fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
324 scale::Encode::encode_to(&self.rest, output);
329 scale::Encode::encode_to(&self.head, output);
330 }
331}
332
333impl<Args> scale::Encode for ExecutionInput<Args, Ink>
334where
335 Args: scale::Encode,
336{
337 #[inline]
338 fn size_hint(&self) -> usize {
339 let selector_size = match &self.selector {
340 None => 0,
341 Some(_) => scale::Encode::size_hint(&self.selector),
342 };
343 selector_size
344 .checked_add(scale::Encode::size_hint(&self.args))
345 .expect("unable to checked_add")
346 }
347
348 #[inline]
349 fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
350 if let Some(selector) = &self.selector {
351 scale::Encode::encode_to(selector, output);
352 }
353 scale::Encode::encode_to(&self.args, output);
354 }
355}
356
357impl<'a, T> SolEncode<'a> for Argument<T>
358where
359 T: SolEncode<'a>,
360{
361 type SolType = <T as SolEncode<'a>>::SolType;
362
363 fn to_sol_type(&'a self) -> Self::SolType {
364 self.arg.to_sol_type()
365 }
366}
367
368pub trait EncodeArgsWith<Abi> {
370 fn encode(&self) -> Vec<u8>;
372
373 fn encode_to(&self, buffer: &mut [u8]) -> usize;
375
376 fn encode_to_vec(&self, buffer: &mut Vec<u8>);
378}
379
380impl<T: scale::Encode> EncodeArgsWith<Ink> for T {
381 fn encode(&self) -> Vec<u8> {
382 scale::Encode::encode(self)
383 }
384
385 fn encode_to(&self, buffer: &mut [u8]) -> usize {
386 let mut sized_output = SizedOutput::from(buffer);
387 scale::Encode::encode_to(self, &mut sized_output);
388 sized_output.len()
389 }
390
391 fn encode_to_vec(&self, buffer: &mut Vec<u8>) {
392 scale::Encode::encode_to(self, buffer);
393 }
394}
395
396impl EncodeArgsWith<Sol> for EmptyArgumentList<Sol> {
397 fn encode(&self) -> Vec<u8> {
398 Vec::new()
399 }
400
401 fn encode_to(&self, _buffer: &mut [u8]) -> usize {
402 0
403 }
404
405 fn encode_to_vec(&self, _buffer: &mut Vec<u8>) {}
406}
407
408impl<Head, Rest> EncodeArgsWith<Sol> for ArgumentList<Argument<Head>, Rest, Sol>
409where
410 for<'a> Self: ArgsListNestedTuple<'a>,
411 for<'a> <Self as ArgsListNestedTuple<'a>>::OutputType: ArgsListFlatTuple,
412 for<'a> <<Self as ArgsListNestedTuple<'a>>::OutputType as ArgsListFlatTuple>::OutputType:
413 SolTypeParamsEncode,
414{
415 fn encode(&self) -> Vec<u8> {
416 SolTypeParamsEncode::encode(&self.nested_tuple().flat_tuple())
417 }
418
419 fn encode_to(&self, buffer: &mut [u8]) -> usize {
420 SolTypeParamsEncode::encode_to(&self.nested_tuple().flat_tuple(), buffer)
421 }
422
423 fn encode_to_vec(&self, buffer: &mut Vec<u8>) {
424 buffer.extend(self.encode());
425 }
426}
427
428trait ArgsListNestedTuple<'a> {
430 type OutputType;
431
432 fn nested_tuple(&'a self) -> Self::OutputType;
433}
434
435impl ArgsListNestedTuple<'_> for EmptyArgumentList<Sol> {
436 type OutputType = ();
437
438 fn nested_tuple(&self) {}
439}
440
441impl<'a, Head, Rest> ArgsListNestedTuple<'a> for ArgumentList<Argument<Head>, Rest, Sol>
442where
443 Rest: ArgsListNestedTuple<'a>,
444 Head: SolEncode<'a>,
445{
446 type OutputType = (Rest::OutputType, <Head as SolEncode<'a>>::SolType);
447
448 fn nested_tuple(&'a self) -> Self::OutputType {
449 (self.rest.nested_tuple(), self.head.arg.to_sol_type())
450 }
451}
452
453trait ArgsListFlatTuple {
455 type OutputType;
456
457 fn flat_tuple(self) -> Self::OutputType;
458}
459
460impl ArgsListFlatTuple for () {
461 type OutputType = ();
462
463 fn flat_tuple(self) {}
464}
465
466macro_rules! args_list_nested_tuple {
468 ($($ty:ident),* $(,)?) => {
470 args_list_nested_tuple!(($($ty),*) @out: ())
471 };
472 (($Head:ident $(, $Rest:ident)*) @out: $Out:tt) => {
474 args_list_nested_tuple!(($($Rest),*) @out: ($Out, $Head))
475 };
476 (() @out: $Out:tt) => { $Out };
478}
479
480macro_rules! impl_flat_tuple {
481 ($( $ty: ident ),*) => {
482 impl<$( $ty ),*> ArgsListFlatTuple for args_list_nested_tuple!($( $ty ),*) {
483 type OutputType = ( $( $ty, )* );
484
485 fn flat_tuple(self) -> Self::OutputType {
486 #[allow(bad_style)]
487 let args_list_nested_tuple!($( $ty ),*) = self;
488 ( $( $ty, )* )
489 }
490 }
491 };
492}
493
494impl_all_tuples!(@nonempty impl_flat_tuple);
495
496#[cfg(test)]
497mod tests {
498 use super::*;
499
500 #[test]
501 fn empty_exec_input_works() {
502 let selector = Selector::new([0x01, 0x02, 0x03, 0x04]);
503 let exec_input = ExecutionInput::new(selector);
504 let encoded = scale::Encode::encode(&exec_input);
505 assert!(!encoded.is_empty());
506 let decoded = <Selector as scale::Decode>::decode(&mut &encoded[..]).unwrap();
507 assert_eq!(decoded, selector);
508 }
509
510 #[test]
511 fn empty_args_works() {
512 let empty_list = ArgumentList::empty();
513 let encoded = scale::Encode::encode(&empty_list);
514 assert_eq!(encoded, <Vec<u8>>::new());
515 }
516
517 #[test]
518 fn single_argument_works() {
519 let empty_list = ArgumentList::empty().push_arg(&1i32);
520 let encoded = scale::Encode::encode(&empty_list);
521 assert!(!encoded.is_empty());
522 let decoded = <i32 as scale::Decode>::decode(&mut &encoded[..]).unwrap();
523 assert_eq!(decoded, 1i32);
524 }
525
526 #[test]
527 fn multiple_arguments_works() {
528 let empty_list = ArgumentList::empty()
529 .push_arg(&42i32)
530 .push_arg(&true)
531 .push_arg(&[0x66u8; 4]);
532 let encoded = scale::Encode::encode(&empty_list);
533 assert!(!encoded.is_empty());
534 let decoded =
535 <(i32, bool, [u8; 4]) as scale::Decode>::decode(&mut &encoded[..]).unwrap();
536 assert_eq!(decoded, (42i32, true, [0x66; 4]));
537 }
538
539 #[test]
540 fn sol_empty_args_works() {
541 let empty_list = ArgumentList::empty();
542 let encoded = EncodeArgsWith::<Sol>::encode(&empty_list);
543 assert_eq!(encoded, Vec::<u8>::new());
544 }
545
546 #[test]
547 fn sol_single_argument_works() {
548 let args_list = ArgumentList::empty().push_arg(&1i32);
549 let encoded = EncodeArgsWith::<Sol>::encode(&args_list);
550 assert!(!encoded.is_empty());
551 let (decoded,) =
552 ink_primitives::sol::decode_sequence::<(i32,)>(&encoded).unwrap();
553 assert_eq!(decoded, 1i32);
554 }
555
556 #[test]
557 fn sol_encoding_arguments_works() {
558 let args_list = EmptyArgumentList::<Sol>::empty()
559 .push_arg(100u8)
560 .push_arg(vec![1, 2, 3, 4])
561 .push_arg(String::from("Hello, world!"))
562 .push_arg(true);
563 let encoded_args_list = EncodeArgsWith::<Sol>::encode(&args_list);
564
565 let args_tuple = (100u8, vec![1, 2, 3, 4], String::from("Hello, world!"), true);
566 let encoded_args_tuple = ink_primitives::sol::encode_sequence(&args_tuple);
567
568 assert_eq!(encoded_args_list, encoded_args_tuple);
569 }
570}