1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
mod code;
mod custom;
mod data;
mod dump;
mod elements;
mod exports;
mod functions;
mod globals;
mod imports;
mod linking;
mod memories;
mod names;
mod producers;
mod start;
mod tables;
mod tags;
mod types;

pub use code::*;
pub use custom::*;
pub use data::*;
pub use dump::*;
pub use elements::*;
pub use exports::*;
pub use functions::*;
pub use globals::*;
pub use imports::*;
pub use linking::*;
pub use memories::*;
pub use names::*;
pub use producers::*;
pub use start::*;
pub use tables::*;
pub use tags::*;
pub use types::*;

use crate::Encode;

pub(crate) const CORE_FUNCTION_SORT: u8 = 0x00;
pub(crate) const CORE_TABLE_SORT: u8 = 0x01;
pub(crate) const CORE_MEMORY_SORT: u8 = 0x02;
pub(crate) const CORE_GLOBAL_SORT: u8 = 0x03;
pub(crate) const CORE_TAG_SORT: u8 = 0x04;

/// A WebAssembly module section.
///
/// Various builders defined in this crate already implement this trait, but you
/// can also implement it yourself for your own custom section builders, or use
/// `RawSection` to use a bunch of raw bytes as a section.
pub trait Section: Encode {
    /// Gets the section identifier for this section.
    fn id(&self) -> u8;

    /// Appends this section to the specified destination list of bytes.
    fn append_to(&self, dst: &mut Vec<u8>) {
        dst.push(self.id());
        self.encode(dst);
    }
}

/// Known section identifiers of WebAssembly modules.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[repr(u8)]
pub enum SectionId {
    /// The custom section.
    Custom = 0,
    /// The type section.
    Type = 1,
    /// The import section.
    Import = 2,
    /// The function section.
    Function = 3,
    /// The table section.
    Table = 4,
    /// The memory section.
    Memory = 5,
    /// The global section.
    Global = 6,
    /// The export section.
    Export = 7,
    /// The start section.
    Start = 8,
    /// The element section.
    Element = 9,
    /// The code section.
    Code = 10,
    /// The data section.
    Data = 11,
    /// The data count section.
    DataCount = 12,
    /// The tag section.
    ///
    /// This section is supported by the exception handling proposal.
    Tag = 13,
}

impl From<SectionId> for u8 {
    #[inline]
    fn from(id: SectionId) -> u8 {
        id as u8
    }
}

impl Encode for SectionId {
    fn encode(&self, sink: &mut Vec<u8>) {
        sink.push(*self as u8);
    }
}

/// Represents a WebAssembly component that is being encoded.
///
/// Sections within a WebAssembly module are encoded in a specific order.
///
/// Modules may also added as a section to a WebAssembly component.
#[derive(Clone, Debug)]
pub struct Module {
    pub(crate) bytes: Vec<u8>,
}

impl Module {
    /// The 8-byte header at the beginning of all core wasm modules.
    #[rustfmt::skip]
    pub const HEADER: [u8; 8] = [
        // Magic
        0x00, 0x61, 0x73, 0x6D,
        // Version
        0x01, 0x00, 0x00, 0x00,
    ];

    /// Begin writing a new `Module`.
    #[rustfmt::skip]
    pub fn new() -> Self {
        Module {
            bytes: Self::HEADER.to_vec(),
        }
    }

    /// Write a section into this module.
    ///
    /// It is your responsibility to define the sections in the [proper
    /// order](https://webassembly.github.io/spec/core/binary/modules.html#binary-module),
    /// and to ensure that each kind of section (other than custom sections) is
    /// only defined once. While this is a potential footgun, it also allows you
    /// to use this crate to easily construct test cases for bad Wasm module
    /// encodings.
    pub fn section(&mut self, section: &impl Section) -> &mut Self {
        self.bytes.push(section.id());
        section.encode(&mut self.bytes);
        self
    }

    /// Get the encoded Wasm module as a slice.
    pub fn as_slice(&self) -> &[u8] {
        &self.bytes
    }

    /// Finish writing this Wasm module and extract ownership of the encoded
    /// bytes.
    pub fn finish(self) -> Vec<u8> {
        self.bytes
    }
}

impl Default for Module {
    fn default() -> Self {
        Self::new()
    }
}