fuels_core/
codec.rs

1mod abi_decoder;
2mod abi_encoder;
3mod abi_formatter;
4mod function_selector;
5mod logs;
6mod utils;
7
8use std::io::Read;
9
10pub use abi_decoder::*;
11pub use abi_encoder::*;
12pub use abi_formatter::*;
13pub use function_selector::*;
14pub use logs::*;
15
16use crate::{
17    traits::{Parameterize, Tokenizable},
18    types::errors::Result,
19};
20
21/// Decodes `bytes` into type `T` following the schema defined by T's `Parameterize` impl
22pub fn try_from_bytes<T>(bytes: impl Read, decoder_config: DecoderConfig) -> Result<T>
23where
24    T: Parameterize + Tokenizable,
25{
26    let token = ABIDecoder::new(decoder_config).decode(&T::param_type(), bytes)?;
27
28    T::from_token(token)
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34    use crate::{
35        constants::WORD_SIZE,
36        types::{Address, AsciiString, AssetId, ContractId},
37    };
38
39    #[test]
40    fn convert_all_from_bool_to_u64() -> Result<()> {
41        let bytes = [255; WORD_SIZE];
42
43        macro_rules! test_decode {
44            ($($for_type: ident),*) => {
45                $(assert_eq!(
46                        try_from_bytes::<$for_type>(bytes.as_slice(), DecoderConfig::default())?,
47                        $for_type::MAX
48                );)*
49            };
50        }
51
52        assert!(try_from_bytes::<bool>(
53            bytes.as_slice(),
54            DecoderConfig::default()
55        )?);
56
57        test_decode!(u8, u16, u32, u64);
58
59        Ok(())
60    }
61
62    #[test]
63    fn convert_bytes_into_tuple() -> Result<()> {
64        let tuple_in_bytes = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2];
65
66        let the_tuple: (u64, u32) =
67            try_from_bytes(tuple_in_bytes.as_slice(), DecoderConfig::default())?;
68
69        assert_eq!(the_tuple, (1, 2));
70
71        Ok(())
72    }
73
74    #[test]
75    fn convert_native_types() -> Result<()> {
76        let bytes = [255; 32];
77
78        macro_rules! test_decode {
79            ($($for_type: ident),*) => {
80                $(assert_eq!(
81                        try_from_bytes::<$for_type>(bytes.as_slice(), DecoderConfig::default())?,
82                        $for_type::new(bytes.as_slice().try_into()?)
83                );)*
84            };
85        }
86
87        test_decode!(Address, ContractId, AssetId);
88
89        Ok(())
90    }
91
92    #[test]
93    fn string_slice_is_read_in_total() {
94        // This was a bug where the decoder read more bytes than it reported, causing the next
95        // element to be read incorrectly.
96
97        // given
98        #[derive(
99            fuels_macros::Tokenizable, fuels_macros::Parameterize, Clone, PartialEq, Debug,
100        )]
101        #[FuelsCorePath = "crate"]
102        #[FuelsTypesPath = "crate::types"]
103        struct Test {
104            name: AsciiString,
105            age: u64,
106        }
107
108        let input = Test {
109            name: AsciiString::new("Alice".to_owned()).unwrap(),
110            age: 42,
111        };
112
113        let encoded = ABIEncoder::default()
114            .encode(&[input.clone().into_token()])
115            .unwrap();
116
117        // when
118        let decoded = try_from_bytes::<Test>(encoded.as_slice(), DecoderConfig::default()).unwrap();
119
120        // then
121        assert_eq!(decoded, input);
122    }
123}