///| Bounds-checked binary cursor. WebAssembly bytes are modelled as integers
///| in the inclusive range 0..255 so callers can construct examples without
///|
/// relying on a filesystem or a host-specific byte type.
pub fn Cursor::read_u8(self : Cursor) -> Result[Int, DecodeError] {
if self.position >= self.limit {
Err(UnexpectedEof(self.position))
} else {
let value = self.bytes[self.position]
self.position = self.position + 1
Ok(value)
}
}
///|
pub fn Cursor::peek_u8(self : Cursor) -> Result[Int, DecodeError] {
if self.position >= self.limit {
Err(UnexpectedEof(self.position))
} else {
Ok(self.bytes[self.position])
}
}
///|
pub fn Cursor::skip(self : Cursor, count : Int) -> Result[Unit, DecodeError] {
if count < 0 || count > self.remaining() {
Err(UnexpectedEof(self.position))
} else {
self.position = self.position + count
Ok(())
}
}
///|
pub fn Cursor::read_slice(
self : Cursor,
count : Int,
) -> Result[Array[Int], DecodeError] {
if count < 0 || count > self.remaining() {
Err(UnexpectedEof(self.position))
} else {
let output : Array[Int] = []
let stop = self.position + count
while self.position < stop {
output.push(self.bytes[self.position])
self.position = self.position + 1
}
Ok(output)
}
}
///|
pub fn Cursor::subcursor(
self : Cursor,
count : Int,
) -> Result[Cursor, DecodeError] {
if count < 0 || count > self.remaining() {
Err(UnexpectedEof(self.position))
} else {
let start = self.position
self.position = self.position + count
Ok(Cursor::with_bounds(self.bytes, start, start + count))
}
}
///|
pub fn Cursor::read_var_u32(self : Cursor) -> Result[Int, DecodeError] {
let start = self.position
let mut result = 0
let mut shift = 0
let mut finished = false
while !finished {
if shift >= 35 {
return Err(InvalidLeb128(start, "more than five bytes"))
}
match self.read_u8() {
Err(error) => return Err(error)
Ok(byte) => {
let payload = byte & 0x7f
result = result | (payload << shift)
if (byte & 0x80) == 0 {
if shift == 28 && payload > 0x0f {
return Err(InvalidLeb128(start, "u32 overflow"))
}
finished = true
} else {
shift = shift + 7
}
}
}
}
Ok(result)
}
///|
pub fn Cursor::read_var_i32(self : Cursor) -> Result[Int, DecodeError] {
let start = self.position
let mut result = 0
let mut shift = 0
let mut final_byte = 0
let mut finished = false
while !finished {
if shift >= 35 {
return Err(InvalidLeb128(start, "more than five bytes"))
}
match self.read_u8() {
Err(error) => return Err(error)
Ok(byte) => {
final_byte = byte
result = result | ((byte & 0x7f) << shift)
shift = shift + 7
if (byte & 0x80) == 0 {
finished = true
}
}
}
}
if shift < 32 && (final_byte & 0x40) != 0 {
result = result | (-1 << shift)
}
Ok(result)
}
///|
pub fn Cursor::read_name(self : Cursor) -> Result[String, DecodeError] {
let start = self.position
match self.read_var_u32() {
Err(error) => Err(error)
Ok(length) =>
match self.read_slice(length) {
Err(error) => Err(error)
Ok(bytes) => {
let mut text = ""
for byte in bytes {
if byte < 0x20 || byte > 0x7e {
return Err(InvalidUtf8(start))
}
text = text + byte.unsafe_to_char().to_string()
}
Ok(text)
}
}
}
}