use super::*;
#[derive(Clone, Debug)]
pub struct ElementSection {
bytes: Vec<u8>,
num_added: u32,
}
#[derive(Clone, Copy, Debug)]
pub enum Elements<'a> {
Functions(&'a [u32]),
Expressions(&'a [Element]),
}
#[derive(Clone, Copy, Debug)]
pub enum Element {
Null,
Func(u32),
}
#[derive(Clone, Copy, Debug)]
pub enum ElementMode<'a> {
Passive,
Declared,
Active {
table: Option<u32>,
offset: Instruction<'a>,
},
}
#[derive(Clone, Copy, Debug)]
pub struct ElementSegment<'a> {
pub mode: ElementMode<'a>,
pub element_type: ValType,
pub elements: Elements<'a>,
}
impl ElementSection {
pub fn new() -> ElementSection {
ElementSection {
bytes: vec![],
num_added: 0,
}
}
pub fn len(&self) -> u32 {
self.num_added
}
pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self {
let expr_bit = match segment.elements {
Elements::Expressions(_) => 0b100,
Elements::Functions(_) => 0b000,
};
match &segment.mode {
ElementMode::Active {
table: None,
offset,
} => {
self.bytes.extend(encoders::u32(0x00 | expr_bit));
offset.encode(&mut self.bytes);
Instruction::End.encode(&mut self.bytes);
}
ElementMode::Passive => {
self.bytes.extend(encoders::u32(0x01 | expr_bit));
if expr_bit == 0 {
self.bytes.push(0x00); } else {
self.bytes.push(segment.element_type.into());
}
}
ElementMode::Active {
table: Some(i),
offset,
} => {
self.bytes.extend(encoders::u32(0x02 | expr_bit));
self.bytes.extend(encoders::u32(*i));
offset.encode(&mut self.bytes);
Instruction::End.encode(&mut self.bytes);
if expr_bit == 0 {
self.bytes.push(0x00); } else {
self.bytes.push(segment.element_type.into());
}
}
ElementMode::Declared => {
self.bytes.extend(encoders::u32(0x03 | expr_bit));
if expr_bit == 0 {
self.bytes.push(0x00); } else {
self.bytes.push(segment.element_type.into());
}
}
}
match segment.elements {
Elements::Functions(fs) => {
self.bytes
.extend(encoders::u32(u32::try_from(fs.len()).unwrap()));
for f in fs {
self.bytes.extend(encoders::u32(*f));
}
}
Elements::Expressions(e) => {
self.bytes.extend(encoders::u32(e.len() as u32));
for expr in e {
match expr {
Element::Func(i) => Instruction::RefFunc(*i).encode(&mut self.bytes),
Element::Null => {
Instruction::RefNull(segment.element_type).encode(&mut self.bytes)
}
}
Instruction::End.encode(&mut self.bytes);
}
}
}
self.num_added += 1;
self
}
pub fn active<'a>(
&mut self,
table_index: Option<u32>,
offset: Instruction,
element_type: ValType,
elements: Elements<'a>,
) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Active {
table: table_index,
offset,
},
element_type,
elements,
})
}
pub fn passive<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Passive,
element_type,
elements,
})
}
pub fn declared<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Declared,
element_type,
elements,
})
}
}
impl Section for ElementSection {
fn id(&self) -> u8 {
SectionId::Element.into()
}
fn encode<S>(&self, sink: &mut S)
where
S: Extend<u8>,
{
let num_added = encoders::u32(self.num_added);
let n = num_added.len();
sink.extend(
encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
.chain(num_added)
.chain(self.bytes.iter().copied()),
);
}
}