use crate::call::Selector;
#[derive(Clone, Default, Debug)]
pub struct ExecutionInput<Args> {
selector: Selector,
args: Args,
}
impl ExecutionInput<EmptyArgumentList> {
#[inline]
pub fn new(selector: Selector) -> Self {
Self {
selector,
args: ArgumentList::empty(),
}
}
#[inline]
pub fn push_arg<T>(
self,
arg: T,
) -> ExecutionInput<ArgumentList<Argument<T>, EmptyArgumentList>>
where
T: scale::Encode,
{
ExecutionInput {
selector: self.selector,
args: self.args.push_arg(arg),
}
}
}
impl<Head, Rest> ExecutionInput<ArgumentList<Argument<Head>, Rest>> {
#[inline]
pub fn push_arg<T>(self, arg: T) -> ExecutionInput<ArgsList<T, ArgsList<Head, Rest>>>
where
T: scale::Encode,
{
ExecutionInput {
selector: self.selector,
args: self.args.push_arg(arg),
}
}
}
impl<Args> ExecutionInput<Args> {
pub fn update_selector(&mut self, selector: Selector) {
self.selector = selector;
}
}
#[derive(Clone, Default, Debug)]
pub struct ArgumentList<Head, Rest> {
head: Head,
rest: Rest,
}
pub type ArgsList<Head, Rest> = ArgumentList<Argument<Head>, Rest>;
#[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 = ArgumentList<ArgumentListEnd, ArgumentListEnd>;
impl EmptyArgumentList {
#[inline]
pub fn empty() -> EmptyArgumentList {
ArgumentList {
head: ArgumentListEnd,
rest: ArgumentListEnd,
}
}
#[inline]
pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self>
where
T: scale::Encode,
{
ArgumentList {
head: Argument::new(arg),
rest: self,
}
}
}
impl<Head, Rest> ArgumentList<Argument<Head>, Rest> {
#[inline]
pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self>
where
T: scale::Encode,
{
ArgumentList {
head: Argument::new(arg),
rest: self,
}
}
}
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 {
#[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>
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))
.unwrap()
}
#[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>
where
Args: scale::Encode,
{
#[inline]
fn size_hint(&self) -> usize {
scale::Encode::size_hint(&self.selector)
.checked_add(scale::Encode::size_hint(&self.args))
.unwrap()
}
#[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);
}
}
#[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]));
}
}