use super::{
utils::ReturnType,
Selector,
};
use crate::{
call::utils::DecodeMessageResult,
Environment,
};
use core::marker::PhantomData;
use ink_prelude::vec::Vec;
use ink_primitives::{
reflect::{
AbiDecodeWith,
AbiEncodeWith,
ScaleEncoding,
SolEncoding,
},
SolEncode,
};
pub struct Execution<Args, Output, Abi> {
pub input: ExecutionInput<Args, Abi>,
pub output: ReturnType<Output>,
}
impl<Args, Output, Abi> Execution<Args, Output, Abi>
where
Args: AbiEncodeWith<Abi>,
Output: AbiDecodeWith<Abi> + DecodeMessageResult<Abi>,
{
pub fn new(input: ExecutionInput<Args, Abi>) -> Self {
Self {
input,
output: ReturnType::default(),
}
}
pub fn exec<I, E>(
self,
executor: &I,
) -> Result<ink_primitives::MessageResult<Output>, I::Error>
where
E: Environment,
I: Executor<E>,
{
executor.exec(&self.input)
}
}
pub trait Executor<E: Environment> {
type Error;
fn exec<Args, Output, Abi>(
&self,
input: &ExecutionInput<Args, Abi>,
) -> Result<ink_primitives::MessageResult<Output>, Self::Error>
where
Args: AbiEncodeWith<Abi>,
Output: AbiDecodeWith<Abi> + DecodeMessageResult<Abi>;
}
#[derive(Clone, Default, Debug)]
pub struct ExecutionInput<Args, Abi> {
selector: Selector,
args: Args,
_marker: PhantomData<Abi>,
}
impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
#[inline]
pub fn new(selector: Selector) -> Self {
Self {
selector,
args: ArgumentList::empty(),
_marker: Default::default(),
}
}
#[inline]
pub fn push_arg<T>(
self,
arg: T,
) -> ExecutionInput<ArgumentList<Argument<T>, EmptyArgumentList<Abi>, Abi>, Abi>
where
T: AbiEncodeWith<Abi>,
{
ExecutionInput {
selector: self.selector,
args: self.args.push_arg(arg),
_marker: Default::default(),
}
}
}
impl<Head, Rest, Abi> ExecutionInput<ArgumentList<Argument<Head>, Rest, Abi>, Abi> {
#[allow(clippy::type_complexity)]
#[inline]
pub fn push_arg<T>(
self,
arg: T,
) -> ExecutionInput<ArgsList<T, ArgsList<Head, Rest, Abi>, Abi>, Abi>
where
T: AbiEncodeWith<Abi>,
{
ExecutionInput {
selector: self.selector,
args: self.args.push_arg(arg),
_marker: Default::default(),
}
}
}
impl<Args, Abi> ExecutionInput<Args, Abi> {
pub fn update_selector(&mut self, selector: Selector) {
self.selector = selector;
}
}
impl<Args, Abi> ExecutionInput<Args, Abi>
where
Args: AbiEncodeWith<Abi>,
{
pub fn encode(&self) -> Vec<u8> {
let mut encoded = Vec::new();
encoded.extend(self.selector.to_bytes());
self.args.encode_to_vec(&mut encoded);
encoded
}
pub fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
let selector_bytes = self.selector.to_bytes();
let selector_len = selector_bytes.len();
buffer[..selector_len].copy_from_slice(&selector_bytes);
let args_len = self.args.encode_to_slice(&mut buffer[selector_len..]);
selector_len + args_len
}
}
#[derive(Clone, Default, Debug)]
pub struct ArgumentList<Head, Rest, Abi> {
head: Head,
rest: Rest,
_marker: PhantomData<Abi>,
}
pub type ArgsList<Head, Rest, Abi> = ArgumentList<Argument<Head>, Rest, Abi>;
#[derive(Clone, Debug)]
pub struct Argument<T> {
arg: T,
}
impl<T> Argument<T> {
#[inline]
fn new(arg: T) -> Self {
Self { arg }
}
}
#[derive(Clone, Default, Debug)]
pub struct ArgumentListEnd;
pub type EmptyArgumentList<Abi> = ArgumentList<ArgumentListEnd, ArgumentListEnd, Abi>;
impl<Abi> EmptyArgumentList<Abi> {
#[inline]
pub fn empty() -> EmptyArgumentList<Abi> {
ArgumentList {
head: ArgumentListEnd,
rest: ArgumentListEnd,
_marker: Default::default(),
}
}
#[inline]
pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
where
T: AbiEncodeWith<Abi>,
{
ArgumentList {
head: Argument::new(arg),
rest: self,
_marker: Default::default(),
}
}
}
impl<Head, Rest, Abi> ArgumentList<Argument<Head>, Rest, Abi> {
#[inline]
pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
where
T: AbiEncodeWith<Abi>,
{
ArgumentList {
head: Argument::new(arg),
rest: self,
_marker: Default::default(),
}
}
}
impl<T> scale::Encode for Argument<T>
where
T: scale::Encode,
{
#[inline]
fn size_hint(&self) -> usize {
<T as scale::Encode>::size_hint(&self.arg)
}
#[inline]
fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
<T as scale::Encode>::encode_to(&self.arg, output)
}
}
impl scale::Encode for EmptyArgumentList<ScaleEncoding> {
#[inline]
fn size_hint(&self) -> usize {
0
}
#[inline]
fn encode_to<O: scale::Output + ?Sized>(&self, _output: &mut O) {}
}
impl<Head, Rest> scale::Encode for ArgumentList<Argument<Head>, Rest, ScaleEncoding>
where
Head: scale::Encode,
Rest: scale::Encode,
{
#[inline]
fn size_hint(&self) -> usize {
scale::Encode::size_hint(&self.head)
.checked_add(scale::Encode::size_hint(&self.rest))
.expect("unable to checked_add")
}
#[inline]
fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
scale::Encode::encode_to(&self.rest, output);
scale::Encode::encode_to(&self.head, output);
}
}
impl<Args> scale::Encode for ExecutionInput<Args, ScaleEncoding>
where
Args: scale::Encode,
{
#[inline]
fn size_hint(&self) -> usize {
scale::Encode::size_hint(&self.selector)
.checked_add(scale::Encode::size_hint(&self.args))
.expect("unable to checked_add")
}
#[inline]
fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
scale::Encode::encode_to(&self.selector, output);
scale::Encode::encode_to(&self.args, output);
}
}
impl<'a, T> SolEncode<'a> for Argument<T>
where
T: SolEncode<'a>,
{
type SolType = <T as SolEncode<'a>>::SolType;
fn to_sol_type(&'a self) -> Self::SolType {
self.arg.to_sol_type()
}
}
impl SolEncode<'_> for EmptyArgumentList<SolEncoding> {
type SolType = ();
fn encode(&self) -> Vec<u8> {
Vec::new()
}
fn to_sol_type(&self) {}
}
impl<'a, Head, Rest> SolEncode<'a> for ArgumentList<Argument<Head>, Rest, SolEncoding>
where
Head: SolEncode<'a>,
Rest: SolEncode<'a>,
{
type SolType = (Rest::SolType, Head::SolType);
fn encode(&'a self) -> Vec<u8> {
let mut encoded = Vec::new();
encoded.extend(Rest::encode(&self.rest));
encoded.extend(Head::encode(&self.head.arg));
encoded
}
fn to_sol_type(&'a self) -> Self::SolType {
(self.rest.to_sol_type(), self.head.arg.to_sol_type())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_exec_input_works() {
let selector = Selector::new([0x01, 0x02, 0x03, 0x04]);
let exec_input = ExecutionInput::new(selector);
let encoded = scale::Encode::encode(&exec_input);
assert!(!encoded.is_empty());
let decoded = <Selector as scale::Decode>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, selector);
}
#[test]
fn empty_args_works() {
let empty_list = ArgumentList::empty();
let encoded = scale::Encode::encode(&empty_list);
assert_eq!(encoded, <Vec<u8>>::new());
}
#[test]
fn single_argument_works() {
let empty_list = ArgumentList::empty().push_arg(&1i32);
let encoded = scale::Encode::encode(&empty_list);
assert!(!encoded.is_empty());
let decoded = <i32 as scale::Decode>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, 1i32);
}
#[test]
fn multiple_arguments_works() {
let empty_list = ArgumentList::empty()
.push_arg(&42i32)
.push_arg(&true)
.push_arg(&[0x66u8; 4]);
let encoded = scale::Encode::encode(&empty_list);
assert!(!encoded.is_empty());
let decoded =
<(i32, bool, [u8; 4]) as scale::Decode>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, (42i32, true, [0x66; 4]));
}
}