use crate::{
BinaryReader, Error, FromReader, Result, SectionLimited, SectionLimitedIntoIter, Subsection,
Subsections,
};
use core::ops::Range;
#[derive(Debug, Clone)]
pub struct NameMap<'a> {
pub names: SectionLimitedIntoIter<'a, Naming<'a>>,
last_index: Option<u32>,
}
impl<'a> NameMap<'a> {
pub fn new(data: BinaryReader<'a>) -> Result<Self> {
let names = SectionLimited::new(data)?;
Ok(NameMap {
names: names.into_iter(),
last_index: None,
})
}
}
impl<'a> Iterator for NameMap<'a> {
type Item = Result<Naming<'a>>;
fn next(&mut self) -> Option<Self::Item> {
let start = self.names.original_position();
let name = self.names.next()?;
if let Ok(name) = &name {
let index = name.index;
if let Some(prev) = self.last_index {
if index <= prev {
return Some(Err(Error::new("names out of order", start)));
}
}
self.last_index = Some(index);
}
Some(name)
}
}
#[derive(Debug, Copy, Clone)]
pub struct Naming<'a> {
pub index: u32,
pub name: &'a str,
}
impl<'a> FromReader<'a> for Naming<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
let index = reader.read_var_u32()?;
let name = reader.read_unlimited_string()?;
Ok(Naming { index, name })
}
}
#[derive(Clone)]
pub struct IndirectNameMap<'a> {
pub names: SectionLimitedIntoIter<'a, IndirectNaming<'a>>,
last_index: Option<u32>,
}
impl<'a> IndirectNameMap<'a> {
pub fn new(data: BinaryReader<'a>) -> Result<Self> {
let names = SectionLimited::new(data)?.into_iter();
Ok(IndirectNameMap {
names,
last_index: None,
})
}
}
impl<'a> Iterator for IndirectNameMap<'a> {
type Item = Result<IndirectNaming<'a>>;
fn next(&mut self) -> Option<Self::Item> {
let start = self.names.original_position();
let name = self.names.next()?;
if let Ok(name) = &name {
let index = name.index;
if let Some(prev) = self.last_index {
if index <= prev {
return Some(Err(Error::new("indirect names out of order", start)));
}
}
self.last_index = Some(index);
}
Some(name)
}
}
#[derive(Debug, Clone)]
pub struct IndirectNaming<'a> {
pub index: u32,
pub names: NameMap<'a>,
}
impl<'a> FromReader<'a> for IndirectNaming<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
let index = reader.read_var_u32()?;
let names = reader.skip(|reader| {
let count = reader.read_var_u32()?;
for _ in 0..count {
reader.read_var_u32()?;
reader.skip_string()?;
}
Ok(())
})?;
Ok(IndirectNaming {
index,
names: NameMap::new(names)?,
})
}
}
#[derive(Clone)]
pub enum Name<'a> {
Module {
name: &'a str,
name_range: Range<u64>,
},
Function(NameMap<'a>),
Local(IndirectNameMap<'a>),
Label(IndirectNameMap<'a>),
Type(NameMap<'a>),
Table(NameMap<'a>),
Memory(NameMap<'a>),
Global(NameMap<'a>),
Element(NameMap<'a>),
Data(NameMap<'a>),
Field(IndirectNameMap<'a>),
Tag(NameMap<'a>),
Parameter(IndirectNameMap<'a>),
TagParameter(IndirectNameMap<'a>),
Unknown {
ty: u8,
data: &'a [u8],
range: Range<u64>,
},
}
impl Name<'_> {
fn id(&self) -> u8 {
match self {
Name::Module { .. } => 0,
Name::Function(_) => 1,
Name::Local(_) => 2,
Name::Label(_) => 3,
Name::Type(_) => 4,
Name::Table(_) => 5,
Name::Memory(_) => 6,
Name::Global(_) => 7,
Name::Element(_) => 8,
Name::Data(_) => 9,
Name::Field(_) => 10,
Name::Tag(_) => 11,
Name::Parameter(_) => 12,
Name::TagParameter(_) => 13,
Name::Unknown { ty, .. } => *ty,
}
}
}
#[derive(Clone)]
pub struct NameSectionReader<'a> {
pub sections: Subsections<'a, Name<'a>>,
last_id: Option<u8>,
}
impl<'a> NameSectionReader<'a> {
pub fn new(data: BinaryReader<'a>) -> Self {
NameSectionReader {
sections: Subsections::new(data),
last_id: None,
}
}
}
impl<'a> Iterator for NameSectionReader<'a> {
type Item = Result<Name<'a>>;
fn next(&mut self) -> Option<Self::Item> {
let start = self.sections.original_position();
let section = self.sections.next()?;
if let Ok(section) = §ion {
let id = section.id();
if let Some(prev) = self.last_id {
if id <= prev {
return Some(Err(Error::new("name subsection out of order", start)));
}
}
self.last_id = Some(id);
}
Some(section)
}
}
impl<'a> Subsection<'a> for Name<'a> {
fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result<Self> {
Ok(match id {
0 => {
let offset = reader.original_position();
let name = reader.read_string()?;
if !reader.eof() {
return Err(Error::new(
"trailing data at the end of a name",
reader.original_position(),
));
}
Name::Module {
name,
name_range: offset..reader.original_position(),
}
}
1 => Name::Function(NameMap::new(reader)?),
2 => Name::Local(IndirectNameMap::new(reader)?),
3 => Name::Label(IndirectNameMap::new(reader)?),
4 => Name::Type(NameMap::new(reader)?),
5 => Name::Table(NameMap::new(reader)?),
6 => Name::Memory(NameMap::new(reader)?),
7 => Name::Global(NameMap::new(reader)?),
8 => Name::Element(NameMap::new(reader)?),
9 => Name::Data(NameMap::new(reader)?),
10 => Name::Field(IndirectNameMap::new(reader)?),
11 => Name::Tag(NameMap::new(reader)?),
12 => Name::Parameter(IndirectNameMap::new(reader)?),
13 => Name::TagParameter(IndirectNameMap::new(reader)?),
ty => Name::Unknown {
ty,
data: reader.remaining_buffer(),
range: reader.remaining_range(),
},
})
}
}