use crate::{CustomSection, Encode, Section, SectionId};
use alloc::borrow::Cow;
use alloc::vec::Vec;
#[derive(Clone, Debug)]
pub struct ProducersSection {
bytes: Vec<u8>,
num_fields: u32,
}
impl ProducersSection {
pub fn new() -> Self {
Self::default()
}
pub fn field(&mut self, name: &str, values: &ProducersField) -> &mut Self {
name.encode(&mut self.bytes);
values.encode(&mut self.bytes);
self.num_fields += 1;
self
}
}
impl Default for ProducersSection {
fn default() -> Self {
Self {
bytes: Vec::new(),
num_fields: 0,
}
}
}
impl Encode for ProducersSection {
fn encode(&self, sink: &mut Vec<u8>) {
let mut data = Vec::new();
self.num_fields.encode(&mut data);
data.extend(&self.bytes);
CustomSection {
name: "producers".into(),
data: Cow::Borrowed(&data),
}
.encode(sink);
}
}
impl Section for ProducersSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
#[derive(Clone, Debug)]
pub struct ProducersField {
bytes: Vec<u8>,
num_values: u32,
}
impl ProducersField {
pub fn new() -> Self {
ProducersField::default()
}
pub fn value(&mut self, name: &str, version: &str) -> &mut Self {
name.encode(&mut self.bytes);
version.encode(&mut self.bytes);
self.num_values += 1;
self
}
}
impl Default for ProducersField {
fn default() -> Self {
Self {
bytes: Vec::new(),
num_values: 0,
}
}
}
impl Encode for ProducersField {
fn encode(&self, sink: &mut Vec<u8>) {
self.num_values.encode(sink);
sink.extend(&self.bytes);
}
}
#[cfg(test)]
mod test {
#[test]
fn roundtrip_example() {
use crate::{Module, ProducersField, ProducersSection};
use wasmparser::{KnownCustom, Parser, Payload};
let mut field = ProducersField::new();
field.value("clang", "14.0.4");
field.value("rustc", "1.66.1");
let mut producers = ProducersSection::new();
producers.field("processed-by", &field);
let mut module = Module::new();
module.section(&producers);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::Version { .. } => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(c) => {
assert_eq!(c.name(), "producers");
let mut section = match c.as_known() {
KnownCustom::Producers(s) => s.into_iter(),
_ => panic!("unknown custom section"),
};
let field = section
.next()
.expect("section has an element")
.expect("element is a producers field");
assert_eq!(field.name, "processed-by");
let mut values = field.values.into_iter();
let value = values
.next()
.expect("values has an element")
.expect("element is a producers field value");
assert_eq!(value.name, "clang");
assert_eq!(value.version, "14.0.4");
let value = values
.next()
.expect("values has another element")
.expect("element is a producers field value");
assert_eq!(value.name, "rustc");
assert_eq!(value.version, "1.66.1");
}
_ => panic!("unexpected payload"),
}
}
}