1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
use crate::*;
use elrond_codec::*;
use core::marker::PhantomData;

pub fn load_single_arg<A, BigInt, BigUint, T>(api: &A, index: i32, arg_id: ArgId) -> T 
where
    T: Decode,
    BigUint: BigUintApi + 'static,
    BigInt: BigIntApi<BigUint> + 'static,
    A: ContractIOApi<BigInt, BigUint> + 'static
{
    // the compiler is smart enough to evaluate this match at compile time
    match T::TYPE_INFO {
        TypeInfo::BigInt => {
            let big_int_arg = api.get_argument_big_int(index);
            let cast_big_int: T = unsafe { core::mem::transmute_copy(&big_int_arg) };
            cast_big_int
        },
        TypeInfo::BigUint => {
            let big_uint_arg = api.get_argument_big_uint(index);
            let cast_big_uint: T = unsafe { core::mem::transmute_copy(&big_uint_arg) };
            cast_big_uint
        },
        _ => {
            // the compiler is also smart enough to evaluate this if let at compile time
            if let Some(res_i64) = T::top_decode_from_i64(|| api.get_argument_i64(index)) {
                match res_i64 {
                    Ok(from_i64) => from_i64,
                    Err(de_err) => {
                        let mut decode_err_message: Vec<u8> = Vec::new();
                        decode_err_message.extend_from_slice(err_msg::ARG_DECODE_ERROR_1);
                        decode_err_message.extend_from_slice(arg_id);
                        decode_err_message.extend_from_slice(err_msg::ARG_DECODE_ERROR_2);
                        decode_err_message.extend_from_slice(de_err.message_bytes());
                        api.signal_error(decode_err_message.as_slice())
                    }
                }
            } else {
                let arg_bytes = api.get_argument_vec(index);
                match elrond_codec::decode_from_byte_slice(arg_bytes.as_slice()) {
                    Ok(v) => v,
                    Err(de_err) => {
                        let mut decode_err_message: Vec<u8> = Vec::new();
                        decode_err_message.extend_from_slice(err_msg::ARG_DECODE_ERROR_1);
                        decode_err_message.extend_from_slice(arg_id);
                        decode_err_message.extend_from_slice(err_msg::ARG_DECODE_ERROR_2);
                        decode_err_message.extend_from_slice(de_err.message_bytes());
                        api.signal_error(decode_err_message.as_slice())
                    }
                }
            }
        }
    }
}

pub struct DynEndpointArgLoader<'a, A, BigInt, BigUint>
where
    BigUint: BigUintApi + 'static,
    BigInt: BigIntApi<BigUint> + 'static,
    A: ContractIOApi<BigInt, BigUint> + 'a 
{
    api: &'a A,
    current_index: i32,
    num_arguments: i32,
    _phantom1: PhantomData<BigInt>,
    _phantom2: PhantomData<BigUint>,
}

impl<'a, A, BigInt, BigUint> DynEndpointArgLoader<'a, A, BigInt, BigUint>
where
    BigUint: BigUintApi + 'static,
    BigInt: BigIntApi<BigUint> + 'static,
    A: ContractIOApi<BigInt, BigUint> + 'a 
{
    pub fn new(api: &'a A) -> Self {
        DynEndpointArgLoader {
            api,
            current_index : 0,
            num_arguments: api.get_num_arguments(),
            _phantom1: PhantomData,
            _phantom2: PhantomData,
        }
    }
}

impl<'a, A, BigInt, BigUint, T> DynArgLoader<T> for DynEndpointArgLoader<'a, A, BigInt, BigUint>
where
    T: Decode,
    BigUint: BigUintApi + 'static,
    BigInt: BigIntApi<BigUint> + 'static,
    A: ContractIOApi<BigInt, BigUint> + 'static
{
    #[inline]
    fn has_next(&self) -> bool {
        self.current_index < self.num_arguments
    }

    fn next_arg(&mut self, arg_id: ArgId) -> Result<Option<T>, SCError> {
        if self.current_index >= self.num_arguments {
            Ok(None)
        } else {
            let arg: T = load_single_arg(self.api, self.current_index, arg_id);
            self.current_index += 1;
            Ok(Some(arg))
        }
    }
}