trn_pact/types/
data_table.rs

1// Copyright 2019 Centrality Investments Limited
2// This file is part of Pact.
3//
4// Licensed under the Apache License v2.0;
5// you may not use this file except in compliance with the License.
6// Unless required by applicable law or agreed to in writing, software
7// distributed under the License is distributed on an "AS IS" BASIS,
8// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9// See the License for the specific language governing permissions and
10// limitations under the License.
11
12// You should have received a copy of the Apache License v2.0
13// along with Pact. If not, see:
14//   <https://futureverse.com/licenses/apachev2.txt>
15
16use crate::types::PactType;
17use alloc::vec::Vec;
18use bit_reverse::ParallelReverse;
19
20/// A pact contract's static data table
21#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
22pub struct DataTable(Vec<PactType>);
23
24impl DataTable {
25    /// Create a new `DataTable` with `values`
26    pub fn new(values: Vec<PactType>) -> Self {
27        Self { 0: values }
28    }
29    /// Push a PactType value into the table
30    pub fn push(&mut self, val: PactType) {
31        self.0.push(val);
32    }
33    /// Encode the data table
34    pub fn encode(&self, buf: &mut Vec<u8>) {
35        buf.push((self.0.len() as u8).swap_bits());
36        for t in self.0.iter() {
37            t.encode(buf);
38        }
39    }
40    /// Decode a DataTable from `buf`.
41    /// Return the DataTable and # of bytes read or error on failure.
42    pub fn decode(buf: Vec<u8>) -> Result<(Self, usize), &'static str> {
43        let mut table = DataTable(Default::default());
44        let mut offset: usize = 1;
45        let l = buf[0].swap_bits();
46        for _ in 0..l {
47            let (pact_type, read) = PactType::decode(buf[offset..].to_vec())?;
48            table.push(pact_type);
49            offset += read;
50        }
51        Ok((table, offset))
52    }
53}
54
55impl AsRef<[PactType]> for DataTable {
56    fn as_ref(&self) -> &[PactType] {
57        &(self.0)
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use crate::types::{Numeric, StringLike};
65
66    #[test]
67    fn it_encodes() {
68        let table = DataTable::new(vec![
69            PactType::Numeric(Numeric(111)),
70            PactType::Numeric(Numeric(333)),
71            PactType::StringLike(StringLike(b"testing".to_vec())),
72        ]);
73        let mut encoded: Vec<u8> = Vec::new();
74        table.encode(&mut encoded);
75
76        // DataTable should simply encode to a concatenated list of it's encoded PactTypes
77        let mut expected: Vec<u8> = vec![
78            3, // length
79            1, 8, 111, 0, 0, 0, 0, 0, 0, 0, // Numeric(111)
80            1, 8, 77, 1, 0, 0, 0, 0, 0, 0, // Numeric(333)
81        ];
82        // StringLike("testing")
83        expected.extend(&[0, 7]);
84        expected = expected.into_iter().map(|b| b.swap_bits()).collect();
85        expected.extend("testing".as_bytes());
86
87        println!("expected: {:?}", expected);
88
89        assert_eq!(encoded, expected,);
90    }
91
92    #[test]
93    fn it_decodes() {
94        let mut buf: Vec<u8> = vec![
95            3, // lengths
96            1, 8, 111, 0, 0, 0, 0, 0, 0, 0, // Numeric(111)
97            1, 8, 77, 1, 0, 0, 0, 0, 0, 0, // Numeric(333)
98        ];
99        // StringLike("testing")
100        buf.extend(&[0, 7]);
101        buf = buf.into_iter().map(|b| b.swap_bits()).collect();
102        buf.extend("testing".as_bytes());
103
104        let expected = DataTable::new(vec![
105            PactType::Numeric(Numeric(111)),
106            PactType::Numeric(Numeric(333)),
107            PactType::StringLike(StringLike(b"testing".to_vec())),
108        ]);
109        let (result, bytes_read) = DataTable::decode(buf.clone()).expect("it decodes");
110
111        assert_eq!(result, expected);
112        assert_eq!(bytes_read, buf.len() as usize);
113    }
114}