fuels_types/
unresolved_bytes.rs

1use crate::constants::WORD_SIZE;
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4pub enum Data {
5    // Write the enclosed data immediately.
6    Inline(Vec<u8>),
7    // The enclosed data should be written somewhere else and only a pointer
8    // should be left behind to point to it.
9    Dynamic(Vec<Data>),
10}
11
12// To get the final encoded bytes, we need to know the address at which these
13// bytes are going to be loaded at. Once the address is given to `resolve`
14// normal bytes can be retrieved.
15#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
16pub struct UnresolvedBytes {
17    data: Vec<Data>,
18}
19
20impl UnresolvedBytes {
21    pub fn new(data: Vec<Data>) -> Self {
22        Self { data }
23    }
24
25    #[allow(clippy::should_implement_trait)]
26    pub fn default() -> Self {
27        Default::default()
28    }
29
30    /// Uses the `start_addr` to resolve any pointers contained within. Once
31    /// they are resolved the raw bytes are returned.
32    ///
33    /// # Arguments
34    ///
35    /// * `start_addr`: The address at which the encoded bytes are to be loaded
36    ///                 in.
37    pub fn resolve(&self, start_addr: u64) -> Vec<u8> {
38        Self::resolve_data(&self.data, start_addr)
39    }
40
41    fn resolve_data(data: &[Data], start_addr: u64) -> Vec<u8> {
42        // We must find a place for the dynamic data where it will not bother
43        // anyone. Best place for it is immediately after all the inline/normal
44        // data is encoded.
45
46        let start_of_dynamic_data = start_addr + Self::amount_of_inline_bytes(data);
47
48        let mut inline_data: Vec<u8> = vec![];
49        let mut dynamic_data: Vec<u8> = vec![];
50        for chunk in data {
51            match chunk {
52                Data::Inline(bytes) => inline_data.extend(bytes),
53                Data::Dynamic(chunk_of_dynamic_data) => {
54                    let ptr_to_next_free_location: u64 =
55                        start_of_dynamic_data + dynamic_data.len() as u64;
56
57                    // If this is a vector, its `ptr` will now be encoded, the
58                    // `cap` and `len` parts should follow as two Data::Inline
59                    // chunks.
60                    inline_data.extend(ptr_to_next_free_location.to_be_bytes().to_vec());
61
62                    // The dynamic data could have had more dynamic data inside
63                    // of it -- think of a Vec<Vec<...>>. Hence Data::Dynamic
64                    // doesn't contain bytes but rather more `Data`.
65                    let resolved_dynamic_data =
66                        Self::resolve_data(chunk_of_dynamic_data, ptr_to_next_free_location);
67
68                    dynamic_data.extend(resolved_dynamic_data)
69                }
70            }
71        }
72
73        let mut data = inline_data;
74        data.extend(dynamic_data);
75        data
76    }
77
78    fn amount_of_inline_bytes(data: &[Data]) -> u64 {
79        data.iter()
80            .map(|chunk| match chunk {
81                Data::Inline(bytes) => bytes.len(),
82                Data::Dynamic(_) => {
83                    // Only the ptr is encoded inline
84                    WORD_SIZE
85                }
86            } as u64)
87            .sum()
88    }
89}