Revision control
Copy as Markdown
Other Tools
//! A WebAssembly encoder.
//!
//! The main builder is the [`Module`]. You can build a section with a
//! section-specific builder, like [`TypeSection`] or [`ImportSection`], and
//! then add it to the module with [`Module::section`]. When you are finished
//! building the module, call either [`Module::as_slice`] or [`Module::finish`]
//! to get the encoded bytes. The former gives a shared reference to the
//! underlying bytes as a slice, while the latter gives you ownership of them as
//! a vector.
//!
//! # Example
//!
//! If we wanted to build this module:
//!
//! ```wasm
//! (module
//! (type (func (param i32 i32) (result i32)))
//! (func (type 0)
//! local.get 0
//! local.get 1
//! i32.add)
//! (export "f" (func 0)))
//! ```
//!
//! then we would do this:
//!
//! ```
//! use wasm_encoder::{
//! CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction,
//! Module, TypeSection, ValType,
//! };
//!
//! let mut module = Module::new();
//!
//! // Encode the type section.
//! let mut types = TypeSection::new();
//! let params = vec![ValType::I32, ValType::I32];
//! let results = vec![ValType::I32];
//! types.ty().function(params, results);
//! module.section(&types);
//!
//! // Encode the function section.
//! let mut functions = FunctionSection::new();
//! let type_index = 0;
//! functions.function(type_index);
//! module.section(&functions);
//!
//! // Encode the export section.
//! let mut exports = ExportSection::new();
//! exports.export("f", ExportKind::Func, 0);
//! module.section(&exports);
//!
//! // Encode the code section.
//! let mut codes = CodeSection::new();
//! let locals = vec![];
//! let mut f = Function::new(locals);
//! f.instruction(&Instruction::LocalGet(0));
//! f.instruction(&Instruction::LocalGet(1));
//! f.instruction(&Instruction::I32Add);
//! f.instruction(&Instruction::End);
//! codes.function(&f);
//! module.section(&codes);
//!
//! // Extract the encoded Wasm bytes for this module.
//! let wasm_bytes = module.finish();
//!
//! // We generated a valid Wasm module!
//! assert!(wasmparser::validate(&wasm_bytes).is_ok());
//! ```
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![deny(missing_docs, missing_debug_implementations)]
#[cfg(feature = "component-model")]
mod component;
mod core;
mod raw;
#[cfg(feature = "wasmparser")]
pub mod reencode;
#[cfg(feature = "component-model")]
pub use self::component::*;
pub use self::core::*;
pub use self::raw::*;
/// Implemented by types that can be encoded into a byte sink.
pub trait Encode {
/// Encode the type into the given byte sink.
fn encode(&self, sink: &mut Vec<u8>);
}
impl<T: Encode + ?Sized> Encode for &'_ T {
fn encode(&self, sink: &mut Vec<u8>) {
T::encode(self, sink)
}
}
impl<T: Encode> Encode for [T] {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
for item in self {
item.encode(sink);
}
}
}
impl Encode for [u8] {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
sink.extend(self);
}
}
impl Encode for str {
fn encode(&self, sink: &mut Vec<u8>) {
self.len().encode(sink);
sink.extend_from_slice(self.as_bytes());
}
}
impl Encode for usize {
fn encode(&self, sink: &mut Vec<u8>) {
assert!(*self <= u32::max_value() as usize);
(*self as u32).encode(sink)
}
}
impl Encode for u32 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::unsigned(sink, (*self).into()).unwrap();
}
}
impl Encode for i32 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::signed(sink, (*self).into()).unwrap();
}
}
impl Encode for u64 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::unsigned(sink, *self).unwrap();
}
}
impl Encode for i64 {
fn encode(&self, sink: &mut Vec<u8>) {
leb128::write::signed(sink, *self).unwrap();
}
}
impl Encode for f32 {
fn encode(&self, sink: &mut Vec<u8>) {
let bits = self.to_bits();
sink.extend(bits.to_le_bytes())
}
}
impl Encode for f64 {
fn encode(&self, sink: &mut Vec<u8>) {
let bits = self.to_bits();
sink.extend(bits.to_le_bytes())
}
}
fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
where
T: Encode,
V: IntoIterator<Item = T>,
V::IntoIter: ExactSizeIterator,
{
let elements = elements.into_iter();
u32::try_from(elements.len()).unwrap().encode(sink);
for x in elements {
x.encode(sink);
}
}
impl<T> Encode for Option<T>
where
T: Encode,
{
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Some(v) => {
sink.push(0x01);
v.encode(sink);
}
None => sink.push(0x00),
}
}
}
fn encoding_size(n: u32) -> usize {
let mut buf = [0u8; 5];
leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap()
}
fn encode_section(sink: &mut Vec<u8>, count: u32, bytes: &[u8]) {
(encoding_size(count) + bytes.len()).encode(sink);
count.encode(sink);
sink.extend(bytes);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_encodes_an_empty_module() {
let bytes = Module::new().finish();
assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00]);
}
#[test]
fn it_encodes_an_empty_component() {
let bytes = Component::new().finish();
assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0d, 0x00, 0x01, 0x00]);
}
}