Skip to main content

strata/
encode.rs

1use crate::error::EncodeError;
2use crate::value::Value;
3
4pub fn encode_uleb128(mut value: u64, out: &mut Vec<u8>) {
5    loop {
6        let mut byte = (value & 0x7F) as u8;
7        value >>= 7;
8        if value != 0 {
9            byte |= 0x80;
10        }
11        out.push(byte);
12        if value == 0 {
13            break;
14        }
15    }
16}
17
18pub fn encode_sleb128(mut value: i64, out: &mut Vec<u8>) {
19    loop {
20        let byte = (value & 0x7F) as u8;
21        let sign_bit = byte & 0x40;
22        value >>= 7;
23
24        let done = (value == 0 && sign_bit == 0) || (value == -1 && sign_bit != 0);
25
26        out.push(if done { byte } else { byte | 0x80 });
27
28        if done {
29            break;
30        }
31    }
32}
33
34pub fn encode(value: &Value) -> Result<Vec<u8>, EncodeError> {
35    let mut out = Vec::new();
36    encode_into(value, &mut out)?;
37    Ok(out)
38}
39
40fn encode_into(value: &Value, out: &mut Vec<u8>) -> Result<(), EncodeError> {
41    match value {
42        Value::Null => {
43            out.push(0x00);
44        }
45
46        Value::Bool(false) => {
47            out.push(0x01);
48        }
49
50        Value::Bool(true) => {
51            out.push(0x02);
52        }
53
54        Value::Int(number) => {
55            out.push(0x10);
56            encode_sleb128(*number, out);
57        }
58
59        Value::String(string) => {
60            out.push(0x20);
61
62            if !string.is_char_boundary(string.len()) {
63                return Err(EncodeError::InvalidUtf8);
64            }
65
66            let bytes = string.as_bytes();
67            encode_uleb128(bytes.len() as u64, out);
68            out.extend_from_slice(bytes);
69        }
70
71        Value::Bytes(bytes) => {
72            out.push(0x21);
73            encode_uleb128(bytes.len() as u64, out);
74            out.extend_from_slice(bytes);
75        }
76
77        Value::List(items) => {
78            out.push(0x30);
79            encode_uleb128(items.len() as u64, out);
80            for item in items {
81                encode_into(item, out)?;
82            }
83        }
84
85        Value::Map(map) => {
86            out.push(0x40);
87            encode_uleb128(map.len() as u64, out);
88
89            // BTreeMap guarantees canonical order
90            for (key, value) in map {
91                // key encoded exactly like a String
92                out.push(0x20);
93
94                if !key.is_char_boundary(key.len()) {
95                    return Err(EncodeError::InvalidUtf8);
96                }
97
98                let key_bytes = key.as_bytes();
99                encode_uleb128(key_bytes.len() as u64, out);
100                out.extend_from_slice(key_bytes);
101
102                encode_into(value, out)?;
103            }
104        }
105    }
106
107    Ok(())
108}