Skip to main content

wasmtime_environ/
bytes.rs

1//! Helpers for workign with encoding/decoding bytes w.r.t. wasmtime's
2//! custom-encoded sections.
3
4use alloc::vec::Vec;
5
6/// Writes the uleb-encoded `value` to `data`.
7pub fn write_uleb(data: &mut Vec<u8>, mut value: u64) {
8    while value >= 0x80 {
9        data.push(0x80 | (value as u8 & 0x7f));
10        value >>= 7;
11    }
12    data.push(value as u8);
13}
14
15/// Writes the sleb-encoded `value` to `data`.
16pub fn write_sleb(data: &mut Vec<u8>, mut value: i64) {
17    loop {
18        let byte = value.cast_unsigned() as u8 & 0x7f;
19        value >>= 7;
20        // Termination requires that the remaining bits of `value` all match
21        // the encoded sign bit, i.e. that sign extension of what's been
22        // written reproduces `value` exactly.
23        let done = (value == 0 && byte & 0x40 == 0) || (value == -1 && byte & 0x40 != 0);
24        if done {
25            data.push(byte);
26            return;
27        }
28        data.push(byte | 0x80);
29    }
30}
31
32/// Reads a uleb-encoded value from `data`, returning the value and consuming
33/// the bytes read from `data`. Returns `None` if the encoding is invalid.
34pub fn read_uleb(data: &mut &[u8]) -> Option<u64> {
35    let mut result = 0;
36    let mut shift = 0;
37    while shift < 64 {
38        let byte = pop(data)?;
39        result |= u64::from(byte & 0x7f) << shift;
40        if byte & 0x80 == 0 {
41            return Some(result);
42        }
43        shift += 7;
44    }
45    None
46}
47
48/// Reads a sleb-encoded value from `data`, returning the value and consuming
49/// the bytes read from `data`. Returns `None` if the encoding is invalid.
50pub fn read_sleb(data: &mut &[u8]) -> Option<i64> {
51    let mut result = 0;
52    let mut shift = 0;
53    while shift < 64 {
54        let byte = pop(data)?;
55        result |= i64::from(byte & 0x7f) << shift;
56        shift += 7;
57        if byte & 0x80 == 0 {
58            // Sign-extend from the topmost bit that was encoded.
59            if shift < 64 && byte & 0x40 != 0 {
60                result |= -1 << shift;
61            }
62            return Some(result);
63        }
64    }
65    None
66}
67
68/// Pops a single byte from the front of `data`, returning it and consuming it
69/// from `data`. Returns `None` if `data` is empty.
70pub fn pop(data: &mut &[u8]) -> Option<u8> {
71    let (&byte, rest) = data.split_first()?;
72    *data = rest;
73    Some(byte)
74}