use crate::source::describe_position;
use std::fmt;
use std::str::Utf8Error;
#[cfg_attr(test, derive(Debug))]
pub enum ErrorKind {
IntOverflow {
ty: &'static str,
got: Option<u64>,
},
UnexpectedEof {
expected: &'static str,
},
WasmMagicNotFound,
VersionMismatch([u8; 4]),
LengthOutOfInput {
input: usize,
specified: usize,
what: &'static str,
},
InvalidUtf8 {
what: &'static str,
error: Utf8Error,
},
UnexpectedByte {
expected: Vec<u8>,
got: u8,
what: &'static str,
},
FuncCodeLengthMismatch {
num_funcs: usize,
num_codes: usize,
},
TooManyLocalVariables,
MalformedSectionSize,
ExpectedEof(u8),
}
#[cfg_attr(test, derive(Debug))]
pub struct Error<'source> {
pub kind: ErrorKind,
pub pos: usize,
pub source: &'source [u8],
pub when: &'static str,
}
impl<'s> Error<'s> {
pub(crate) fn new(
kind: ErrorKind,
pos: usize,
source: &'s [u8],
when: &'static str,
) -> Box<Error<'s>> {
Box::new(Error {
kind,
pos,
source,
when,
})
}
}
impl<'s> fmt::Display for Error<'s> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ErrorKind::*;
match &self.kind {
IntOverflow { ty, got: Some(got) } => write!(
f,
"LEB128-encoded integer '{:x}' is too large for {} value",
got, ty
)?,
IntOverflow { ty, got: None } => {
write!(f, "LEB128-encoded integer is too large for {} value", ty)?
}
UnexpectedEof { expected } => write!(
f,
"expected {} but reached end of current section or input",
expected
)?,
WasmMagicNotFound => write!(
f,
"WebAssembly binary must start with magic 0x00 0x61 0x73 0x6d"
)?,
VersionMismatch(v) => write!(f, "expected version [1, 0, 0, 0] but got {:?}", v)?,
LengthOutOfInput {
input,
specified,
what,
} => write!(
f,
"{} ({} bytes) is larger than the rest of input ({} bytes)",
what, specified, input
)?,
InvalidUtf8 { what, error } => write!(f, "{} must be UTF-8 sequence: {}", what, error)?,
UnexpectedByte {
expected,
got,
what,
} if expected.is_empty() => write!(f, "unexpected byte 0x{:02x} at {}", got, what,)?,
UnexpectedByte {
expected,
got,
what,
} if expected.len() == 1 => write!(
f,
"expected byte 0x{:02x} for {} but got 0x{:02x}",
expected[0], what, got
)?,
UnexpectedByte {
expected,
got,
what,
} => {
f.write_str("expected one of ")?;
let mut first = true;
for b in expected.iter() {
if !first {
f.write_str(", ")?;
}
write!(f, "0x{:02x}", b)?;
first = false;
}
write!(f, " for {} but got byte 0x{:02x}", what, got)?;
}
FuncCodeLengthMismatch {
num_funcs,
num_codes,
} => write!(
f,
"number of function sections '{}' does not match to number of code sections '{}'",
num_funcs, num_codes,
)?,
TooManyLocalVariables => write!(f, "too many local variables")?,
MalformedSectionSize => write!(f, "malformed section size")?,
ExpectedEof(b) => write!(
f,
"expected end of input but byte 0x{:02x} is still following",
b
)?,
}
write!(f, " while parsing {}.", self.when)?;
describe_position(f, self.source, self.pos)
}
}
pub type Result<'s, T> = ::std::result::Result<T, Box<Error<'s>>>;