revm_primitives/bytecode/eof/
body.rs

1use super::{Eof, EofDecodeError, EofHeader, TypesSection};
2use crate::Bytes;
3use std::vec::Vec;
4
5/// EOF container body.
6///
7/// Contains types, code, container and data sections.
8///
9/// Can be used to create a new EOF container using the [`into_eof`](EofBody::into_eof) method.
10#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct EofBody {
13    pub types_section: Vec<TypesSection>,
14    pub code_section: Vec<Bytes>,
15    pub container_section: Vec<Bytes>,
16    pub data_section: Bytes,
17    pub is_data_filled: bool,
18}
19
20impl EofBody {
21    /// Returns the code section at the given index.
22    pub fn code(&self, index: usize) -> Option<&Bytes> {
23        self.code_section.get(index)
24    }
25
26    /// Creates an EOF container from this body.
27    pub fn into_eof(self) -> Eof {
28        // TODO add bounds checks.
29        let header = EofHeader {
30            types_size: self.types_section.len() as u16 * 4,
31            code_sizes: self.code_section.iter().map(|x| x.len() as u16).collect(),
32            container_sizes: self
33                .container_section
34                .iter()
35                .map(|x| x.len() as u16)
36                .collect(),
37            data_size: self.data_section.len() as u16,
38            sum_code_sizes: self.code_section.iter().map(|x| x.len()).sum(),
39            sum_container_sizes: self.container_section.iter().map(|x| x.len()).sum(),
40        };
41        let mut buffer = Vec::new();
42        header.encode(&mut buffer);
43        self.encode(&mut buffer);
44        Eof {
45            header,
46            body: self,
47            raw: buffer.into(),
48        }
49    }
50
51    /// Encodes this body into the given buffer.
52    pub fn encode(&self, buffer: &mut Vec<u8>) {
53        for types_section in &self.types_section {
54            types_section.encode(buffer);
55        }
56
57        for code_section in &self.code_section {
58            buffer.extend_from_slice(code_section);
59        }
60
61        for container_section in &self.container_section {
62            buffer.extend_from_slice(container_section);
63        }
64
65        buffer.extend_from_slice(&self.data_section);
66    }
67
68    /// Decodes an EOF container body from the given buffer and header.
69    pub fn decode(input: &Bytes, header: &EofHeader) -> Result<Self, EofDecodeError> {
70        let header_len = header.size();
71        let partial_body_len =
72            header.sum_code_sizes + header.sum_container_sizes + header.types_size as usize;
73        let full_body_len = partial_body_len + header.data_size as usize;
74
75        if input.len() < header_len + partial_body_len {
76            return Err(EofDecodeError::MissingBodyWithoutData);
77        }
78
79        if input.len() > header_len + full_body_len {
80            return Err(EofDecodeError::DanglingData);
81        }
82
83        let mut body = EofBody::default();
84
85        let mut types_input = &input[header_len..];
86        for _ in 0..header.types_count() {
87            let (types_section, local_input) = TypesSection::decode(types_input)?;
88            types_input = local_input;
89            body.types_section.push(types_section);
90        }
91
92        // extract code section
93        let mut start = header_len + header.types_size as usize;
94        for size in header.code_sizes.iter().map(|x| *x as usize) {
95            body.code_section.push(input.slice(start..start + size));
96            start += size;
97        }
98
99        // extract container section
100        for size in header.container_sizes.iter().map(|x| *x as usize) {
101            body.container_section
102                .push(input.slice(start..start + size));
103            start += size;
104        }
105
106        body.data_section = input.slice(start..);
107        body.is_data_filled = body.data_section.len() == header.data_size as usize;
108
109        Ok(body)
110    }
111}