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
use crate::{
    api::{EndpointArgumentApi, ManagedTypeApi},
    types::{BigInt, BigUint, ManagedBuffer, ManagedBufferNestedDecodeInput, ManagedType},
    Box,
};
use dharitri_codec::{try_execute_then_cast, DecodeError, TopDecodeInput, TryStaticCast};

/// Adapter from the API to the TopDecodeInput trait.
/// Allows objects to be deserialized directly from the API as arguments.
///
/// Of course the implementation provides shortcut deserialization computation paths directly from API:
/// into_u64, into_i64, ...
///
/// This is a performance-critical struct.
/// Since the wasm EndpointArgumentApi (VmApiImpl) is zero-size,
/// it means that this structures translates to a single glorified i32 in wasm.
pub struct ArgDecodeInput<AA>
where
    AA: ManagedTypeApi + EndpointArgumentApi,
{
    api: AA,
    arg_index: i32,
}

impl<AA> ArgDecodeInput<AA>
where
    AA: ManagedTypeApi + EndpointArgumentApi,
{
    #[inline]
    pub fn new(api: AA, arg_index: i32) -> Self {
        ArgDecodeInput { api, arg_index }
    }

    #[inline]
    fn to_managed_buffer(&self) -> ManagedBuffer<AA> {
        let mbuf_handle = self.api.get_argument_managed_buffer_raw(self.arg_index);
        ManagedBuffer::from_raw_handle(self.api.clone(), mbuf_handle)
    }

    #[inline]
    fn to_big_int(&self) -> BigInt<AA> {
        let bi_handle = self.api.get_argument_big_int_raw(self.arg_index);
        BigInt::from_raw_handle(self.api.clone(), bi_handle)
    }

    #[inline]
    fn to_big_uint(&self) -> BigUint<AA> {
        let bi_handle = self.api.get_argument_big_uint_raw(self.arg_index);
        BigUint::from_raw_handle(self.api.clone(), bi_handle)
    }
}

impl<AA> TopDecodeInput for ArgDecodeInput<AA>
where
    AA: ManagedTypeApi + EndpointArgumentApi,
{
    type NestedBuffer = ManagedBufferNestedDecodeInput<AA>;

    #[inline]
    fn byte_len(&self) -> usize {
        self.api.get_argument_len(self.arg_index)
    }

    #[inline]
    fn into_boxed_slice_u8(self) -> Box<[u8]> {
        self.api.get_argument_boxed_bytes(self.arg_index).into_box()
    }

    #[inline]
    fn into_u64(self) -> u64 {
        self.api.get_argument_u64(self.arg_index)
    }

    #[inline]
    fn into_i64(self) -> i64 {
        self.api.get_argument_i64(self.arg_index)
    }

    #[inline]
    fn into_specialized<T, F>(self, else_deser: F) -> Result<T, DecodeError>
    where
        T: TryStaticCast,
        F: FnOnce(Self) -> Result<T, DecodeError>,
    {
        if let Some(result) = try_execute_then_cast(|| self.to_managed_buffer()) {
            Ok(result)
        } else if let Some(result) = try_execute_then_cast(|| self.to_big_uint()) {
            Ok(result)
        } else if let Some(result) = try_execute_then_cast(|| self.to_big_int()) {
            Ok(result)
        } else {
            else_deser(self)
        }
    }

    #[inline]
    fn into_nested_buffer(self) -> Self::NestedBuffer {
        ManagedBufferNestedDecodeInput::new(self.to_managed_buffer())
    }
}