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
// Copyright 2020 Conflux Foundation. All rights reserved.
// Conflux is free software and distributed under GNU General Public License.
// See http://www.gnu.org/licenses/

use super::{
    utils::{
        padded_big_endian, pull_slice, read_abi_list, ABIListWriter,
        LinkedBytes,
    },
    ABIDecodeError, ABIVariable,
};
use cfx_types::U256;
use std::{convert::TryFrom, fmt::Debug};

impl<T: ABIVariable> ABIVariable for Vec<T> {
    const BASIC_TYPE: bool = false;
    const STATIC_LENGTH: Option<usize> = None;

    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
        let pointer = &mut data.iter();

        let expected_length = U256::from_big_endian(pull_slice(
            pointer,
            32,
            "Incomplete length for dynamic input parameter",
        )?);
        let data_without_length = pointer.as_slice();
        let mut i = U256::zero();
        let mut results = Vec::new();
        while i < expected_length {
            results.push(read_abi_list::<T>(data_without_length, pointer)?);
            i = i + 1;
        }
        Ok(results)
    }

    fn to_abi(&self) -> LinkedBytes {
        let length = LinkedBytes::from_bytes(padded_big_endian(self.len()));
        let mut recorder = ABIListWriter::with_heads_length(
            T::STATIC_LENGTH.unwrap_or(32) * self.len(),
        );

        for item in self {
            recorder.write_down(item);
        }
        let mut answer = length;
        answer.append(&mut recorder.into_linked_bytes());
        answer
    }

    fn to_packed_abi(&self) -> LinkedBytes {
        let mut record = LinkedBytes::new();

        for item in self {
            record.append(&mut item.to_packed_abi())
        }
        record
    }
}

impl<T: ABIVariable + Debug, const N: usize> ABIVariable for [T; N] {
    const BASIC_TYPE: bool = false;
    const STATIC_LENGTH: Option<usize> = if let Some(length) = T::STATIC_LENGTH
    {
        Some(length * N)
    } else {
        None
    };

    fn from_abi(data: &[u8]) -> Result<Self, ABIDecodeError> {
        let pointer = &mut data.iter();

        let data_without_length = pointer.as_slice();
        let mut results = Vec::new();
        for _ in 0..N {
            results.push(read_abi_list::<T>(data_without_length, pointer)?);
        }
        let results =
            <[T; N]>::try_from(results).expect("Vector length must correct");
        Ok(results)
    }

    fn to_abi(&self) -> LinkedBytes {
        let mut recorder = ABIListWriter::with_heads_length(
            T::STATIC_LENGTH.unwrap_or(32) * N,
        );

        for item in self {
            recorder.write_down(item);
        }
        recorder.into_linked_bytes()
    }

    fn to_packed_abi(&self) -> LinkedBytes {
        let mut record = LinkedBytes::new();

        for item in self {
            record.append(&mut item.to_packed_abi())
        }
        record
    }
}