Coverage Report

Created: 2026-10-12 08:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wasm-encoder/src/lib.rs
Line
Count
Source
1
//! A WebAssembly encoder.
2
//!
3
//! The main builder is the [`Module`]. You can build a section with a
4
//! section-specific builder, like [`TypeSection`] or [`ImportSection`], and
5
//! then add it to the module with [`Module::section`]. When you are finished
6
//! building the module, call either [`Module::as_slice`] or [`Module::finish`]
7
//! to get the encoded bytes. The former gives a shared reference to the
8
//! underlying bytes as a slice, while the latter gives you ownership of them as
9
//! a vector.
10
//!
11
//! # Example
12
//!
13
//! If we wanted to build this module:
14
//!
15
//! ```wasm
16
//! (module
17
//!   (type (func (param i32 i32) (result i32)))
18
//!   (func (type 0)
19
//!     local.get 0
20
//!     local.get 1
21
//!     i32.add)
22
//!   (export "f" (func 0)))
23
//! ```
24
//!
25
//! then we would do this:
26
//!
27
//! ```
28
//! use wasm_encoder::{
29
//!     CodeSection, ExportKind, ExportSection, Function, FunctionSection,
30
//!     Module, TypeSection, ValType,
31
//! };
32
//!
33
//! let mut module = Module::new();
34
//!
35
//! // Encode the type section.
36
//! let mut types = TypeSection::new();
37
//! let params = vec![ValType::I32, ValType::I32];
38
//! let results = vec![ValType::I32];
39
//! types.ty().function(params, results);
40
//! module.section(&types);
41
//!
42
//! // Encode the function section.
43
//! let mut functions = FunctionSection::new();
44
//! let type_index = 0;
45
//! functions.function(type_index);
46
//! module.section(&functions);
47
//!
48
//! // Encode the export section.
49
//! let mut exports = ExportSection::new();
50
//! exports.export("f", ExportKind::Func, 0);
51
//! module.section(&exports);
52
//!
53
//! // Encode the code section.
54
//! let mut codes = CodeSection::new();
55
//! let locals = vec![];
56
//! let mut f = Function::new(locals);
57
//! f.instructions()
58
//!     .local_get(0)
59
//!     .local_get(1)
60
//!     .i32_add()
61
//!     .end();
62
//! codes.function(&f);
63
//! module.section(&codes);
64
//!
65
//! // Extract the encoded Wasm bytes for this module.
66
//! let wasm_bytes = module.finish();
67
//!
68
//! // We generated a valid Wasm module!
69
//! assert!(wasmparser::validate(&wasm_bytes).is_ok());
70
//! ```
71
72
#![cfg_attr(docsrs, feature(doc_cfg))]
73
#![no_std]
74
#![deny(missing_docs, missing_debug_implementations)]
75
76
extern crate alloc;
77
#[cfg(feature = "std")]
78
#[macro_use]
79
extern crate std;
80
81
#[cfg(feature = "component-model")]
82
mod component;
83
mod core;
84
mod raw;
85
#[cfg(feature = "wasmparser")]
86
pub mod reencode;
87
88
#[cfg(feature = "component-model")]
89
pub use self::component::*;
90
pub use self::core::*;
91
pub use self::raw::*;
92
93
use alloc::vec::Vec;
94
95
/// Implemented by types that can be encoded into a byte sink.
96
pub trait Encode {
97
    /// Encode the type into the given byte sink.
98
    fn encode(&self, sink: &mut Vec<u8>);
99
}
100
101
impl<T: Encode + ?Sized> Encode for &'_ T {
102
167k
    fn encode(&self, sink: &mut Vec<u8>) {
103
167k
        T::encode(self, sink)
104
167k
    }
<&wasm_encoder::core::code::ConstExpr as wasm_encoder::Encode>::encode
Line
Count
Source
102
55.3k
    fn encode(&self, sink: &mut Vec<u8>) {
103
55.3k
        T::encode(self, sink)
104
55.3k
    }
<&str as wasm_encoder::Encode>::encode
Line
Count
Source
102
112k
    fn encode(&self, sink: &mut Vec<u8>) {
103
112k
        T::encode(self, sink)
104
112k
    }
105
}
106
107
impl<T: Encode> Encode for [T] {
108
407k
    fn encode(&self, sink: &mut Vec<u8>) {
109
407k
        self.len().encode(sink);
110
407k
        for item in self {
111
275k
            item.encode(sink);
112
275k
        }
113
407k
    }
<[wasm_encoder::core::types::ValType] as wasm_encoder::Encode>::encode
Line
Count
Source
108
507
    fn encode(&self, sink: &mut Vec<u8>) {
109
507
        self.len().encode(sink);
110
507
        for item in self {
111
507
            item.encode(sink);
112
507
        }
113
507
    }
<[u32] as wasm_encoder::Encode>::encode
Line
Count
Source
108
407k
    fn encode(&self, sink: &mut Vec<u8>) {
109
407k
        self.len().encode(sink);
110
407k
        for item in self {
111
274k
            item.encode(sink);
112
274k
        }
113
407k
    }
114
}
115
116
impl Encode for [u8] {
117
986k
    fn encode(&self, sink: &mut Vec<u8>) {
118
986k
        self.len().encode(sink);
119
986k
        sink.extend(self);
120
986k
    }
121
}
122
123
impl Encode for str {
124
2.53M
    fn encode(&self, sink: &mut Vec<u8>) {
125
2.53M
        self.len().encode(sink);
126
2.53M
        sink.extend_from_slice(self.as_bytes());
127
2.53M
    }
128
}
129
130
impl Encode for usize {
131
6.61M
    fn encode(&self, sink: &mut Vec<u8>) {
132
6.61M
        assert!(*self <= u32::MAX as usize);
133
6.61M
        (*self as u32).encode(sink)
134
6.61M
    }
135
}
136
137
impl Encode for u32 {
138
25.1M
    fn encode(&self, sink: &mut Vec<u8>) {
139
25.1M
        let (value, pos) = leb128fmt::encode_u32(*self).unwrap();
140
25.1M
        sink.extend_from_slice(&value[..pos]);
141
25.1M
    }
142
}
143
144
impl Encode for i32 {
145
901k
    fn encode(&self, sink: &mut Vec<u8>) {
146
901k
        let (value, pos) = leb128fmt::encode_s32(*self).unwrap();
147
901k
        sink.extend_from_slice(&value[..pos]);
148
901k
    }
149
}
150
151
impl Encode for u64 {
152
655k
    fn encode(&self, sink: &mut Vec<u8>) {
153
655k
        let (value, pos) = leb128fmt::encode_u64(*self).unwrap();
154
655k
        sink.extend_from_slice(&value[..pos]);
155
655k
    }
156
}
157
158
impl Encode for i64 {
159
4.28M
    fn encode(&self, sink: &mut Vec<u8>) {
160
4.28M
        let (value, pos) = leb128fmt::encode_s64(*self).unwrap();
161
4.28M
        sink.extend_from_slice(&value[..pos]);
162
4.28M
    }
163
}
164
165
353k
fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
166
353k
where
167
353k
    T: Encode,
168
353k
    V: IntoIterator<Item = T>,
169
353k
    V::IntoIter: ExactSizeIterator,
170
{
171
353k
    let elements = elements.into_iter();
172
353k
    u32::try_from(elements.len()).unwrap().encode(sink);
173
1.35M
    for x in elements {
174
1.35M
        x.encode(sink);
175
1.35M
    }
176
353k
}
wasm_encoder::encode_vec::<wasm_encoder::core::code::Catch, core::iter::adapters::map::Map<core::slice::iter::Iter<wast::core::expr::TryTableCatch>, wast::core::binary::custom_encoders::try_table::{closure#0}>>
Line
Count
Source
165
89.1k
fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
166
89.1k
where
167
89.1k
    T: Encode,
168
89.1k
    V: IntoIterator<Item = T>,
169
89.1k
    V::IntoIter: ExactSizeIterator,
170
{
171
89.1k
    let elements = elements.into_iter();
172
89.1k
    u32::try_from(elements.len()).unwrap().encode(sink);
173
311k
    for x in elements {
174
311k
        x.encode(sink);
175
311k
    }
176
89.1k
}
Unexecuted instantiation: wasm_encoder::encode_vec::<wasm_encoder::core::code::Handle, core::iter::adapters::map::Map<core::slice::iter::Iter<wast::core::expr::Handle>, <wast::core::expr::ResumeTable>::handles::{closure#0}>>
wasm_encoder::encode_vec::<u32, core::iter::adapters::map::Map<core::slice::iter::Iter<wast::token::Index>, wast::core::binary::custom_encoders::br_table::{closure#0}>>
Line
Count
Source
165
3.79k
fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
166
3.79k
where
167
3.79k
    T: Encode,
168
3.79k
    V: IntoIterator<Item = T>,
169
3.79k
    V::IntoIter: ExactSizeIterator,
170
{
171
3.79k
    let elements = elements.into_iter();
172
3.79k
    u32::try_from(elements.len()).unwrap().encode(sink);
173
15.4k
    for x in elements {
174
15.4k
        x.encode(sink);
175
15.4k
    }
176
3.79k
}
wasm_encoder::encode_vec::<wasm_encoder::core::code::Catch, core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<wasm_encoder::core::code::Catch>>>
Line
Count
Source
165
250k
fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
166
250k
where
167
250k
    T: Encode,
168
250k
    V: IntoIterator<Item = T>,
169
250k
    V::IntoIter: ExactSizeIterator,
170
{
171
250k
    let elements = elements.into_iter();
172
250k
    u32::try_from(elements.len()).unwrap().encode(sink);
173
991k
    for x in elements {
174
991k
        x.encode(sink);
175
991k
    }
176
250k
}
Unexecuted instantiation: wasm_encoder::encode_vec::<wasm_encoder::core::code::Handle, core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<wasm_encoder::core::code::Handle>>>
wasm_encoder::encode_vec::<u32, core::iter::adapters::copied::Copied<core::slice::iter::Iter<u32>>>
Line
Count
Source
165
9.65k
fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
166
9.65k
where
167
9.65k
    T: Encode,
168
9.65k
    V: IntoIterator<Item = T>,
169
9.65k
    V::IntoIter: ExactSizeIterator,
170
{
171
9.65k
    let elements = elements.into_iter();
172
9.65k
    u32::try_from(elements.len()).unwrap().encode(sink);
173
40.2k
    for x in elements {
174
40.2k
        x.encode(sink);
175
40.2k
    }
176
9.65k
}
177
178
impl<T> Encode for Option<T>
179
where
180
    T: Encode,
181
{
182
106k
    fn encode(&self, sink: &mut Vec<u8>) {
183
106k
        match self {
184
86.8k
            Some(v) => {
185
86.8k
                sink.push(0x01);
186
86.8k
                v.encode(sink);
187
86.8k
            }
188
19.1k
            None => sink.push(0x00),
189
        }
190
106k
    }
191
}
192
193
424k
fn encoding_size(n: u32) -> usize {
194
424k
    let (_value, pos) = leb128fmt::encode_u32(n).unwrap();
195
424k
    pos
196
424k
}
197
198
353k
fn encode_section(sink: &mut Vec<u8>, count: u32, bytes: &[u8]) {
199
353k
    (encoding_size(count) + bytes.len()).encode(sink);
200
353k
    count.encode(sink);
201
353k
    sink.extend(bytes);
202
353k
}
203
204
#[cfg(test)]
205
mod test {
206
    use super::*;
207
208
    #[test]
209
    fn test_encoding_size() {
210
        assert_eq!(encoding_size(624485), 3);
211
    }
212
213
    #[test]
214
    fn it_encodes_an_empty_module() {
215
        let bytes = Module::new().finish();
216
        assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00]);
217
    }
218
219
    #[test]
220
    fn it_encodes_an_empty_component() {
221
        let bytes = Component::new().finish();
222
        assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0d, 0x00, 0x01, 0x00]);
223
    }
224
}