wasm/core/decoding/modules/
sections.rs

1use crate::{
2    core::{
3        decoding::reader::{span::Span, WasmDecoder},
4        utils::ToUsizeExt,
5    },
6    DecodingError,
7};
8
9#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
10pub enum SectionTy {
11    Custom = 0,
12    Type = 1,
13    Import = 2,
14    Function = 3,
15    Table = 4,
16    Memory = 5,
17    Global = 6,
18    Export = 7,
19    Start = 8,
20    Element = 9,
21    Code = 10,
22    Data = 11,
23    DataCount = 12,
24}
25
26impl TryFrom<u8> for SectionTy {
27    type Error = DecodingError;
28
29    fn try_from(value: u8) -> Result<Self, Self::Error> {
30        use SectionTy::*;
31        let ty = match value {
32            0 => Custom,
33            1 => Type,
34            2 => Import,
35            3 => Function,
36            4 => Table,
37            5 => Memory,
38            6 => Global,
39            7 => Export,
40            8 => Start,
41            9 => Element,
42            10 => Code,
43            11 => Data,
44            12 => DataCount,
45            other => return Err(DecodingError::MalformedSectionTypeDiscriminator(other)),
46        };
47        Ok(ty)
48    }
49}
50
51impl SectionTy {
52    pub fn decode(wasm: &mut WasmDecoder) -> Result<Self, DecodingError> {
53        wasm.decode_u8().and_then(Self::try_from)
54    }
55
56    pub fn peek(wasm: &WasmDecoder) -> Result<Self, DecodingError> {
57        wasm.peek_u8().and_then(Self::try_from)
58    }
59}
60
61/// Returns `None` if section types do not match or if the end of the bytecode was reached.
62pub fn decode_section_if_ty_matches<'wasm, T, E>(
63    wasm: &mut WasmDecoder<'wasm>,
64    expected_ty: SectionTy,
65    section_consumer: impl FnOnce(&mut WasmDecoder<'wasm>, Span) -> Result<T, E>,
66) -> Result<Option<T>, E>
67where
68    E: From<DecodingError>,
69{
70    let section_ty = match SectionTy::peek(wasm) {
71        Ok(section_ty) => section_ty,
72        Err(DecodingError::Eof) => return Ok(None),
73        Err(other) => return Err(other.into()),
74    };
75
76    if section_ty != expected_ty {
77        return Ok(None);
78    }
79    let _ = SectionTy::decode(wasm).expect("this to be Ok because of the previous peek call");
80
81    let size: u32 = wasm.decode_var_u32()?;
82    let contents_span = wasm.make_span(size.into_usize())?;
83
84    trace!("Handling section {:?}", section_ty);
85    let t = section_consumer(wasm, contents_span)?;
86
87    if wasm.pc != contents_span.from() + contents_span.len() {
88        return Err(DecodingError::SectionSizeMismatch.into());
89    }
90
91    Ok(Some(t))
92}