1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use std::io::Write;
use crate::{
consts::{
ARR_HEADER, DICT_HEADER, FALSE_VALUE, NULL_VALUE, NUM_HEADER, STR_HEADER, TAG_HEADER,
TRUE_VALUE,
},
util::{small_boxed_string::SmallBoxedStr, trunc_8_bytes::write_trunc_8_bytes},
DictKey, Litl, TaggedData,
};
impl Litl {
pub fn write<W: Write>(&self, out: &mut W) -> std::io::Result<()> {
match self {
Litl::String(str) => write_str(str, out),
Litl::Number(num) => write_trunc_8_bytes(NUM_HEADER, &num.to_bits().to_be_bytes(), out),
Litl::Array(items) => {
write_trunc_8_bytes(ARR_HEADER, &(items.len() as u64).to_le_bytes(), out)?;
for item in &**items {
item.write(out)?;
}
Ok(())
}
Litl::Dict(dict) => {
let (keys, values) = dict.keys_and_values();
write_trunc_8_bytes(DICT_HEADER, &(keys.len() as u64).to_le_bytes(), out)?;
for (key, value) in keys.iter().zip(values) {
match key {
DictKey::String(str) => write_str(str, out),
DictKey::TaggedData(tagged_data) => tagged_data.write(out),
}?;
value.write(out)?;
}
Ok(())
}
Litl::Bool(false) => out.write_all(&[FALSE_VALUE]),
Litl::Bool(true) => out.write_all(&[TRUE_VALUE]),
Litl::Null => out.write_all(&[NULL_VALUE]),
Litl::TaggedData(tagged_data) => tagged_data.write(out),
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
self.write(&mut bytes).unwrap();
bytes
}
pub fn write_all<'a, I: IntoIterator<Item = &'a Litl>>(values: I) -> Vec<u8> {
let mut bytes = Vec::new();
for value in values {
value.write(&mut bytes).unwrap();
}
bytes
}
}
impl TaggedData {
fn write<W: Write>(&self, out: &mut W) -> std::io::Result<()> {
match self {
TaggedData::Leaf (data) => {
write_trunc_8_bytes(TAG_HEADER, &("data".len() as u64).to_le_bytes(), out)?;
out.write_all("data".as_bytes())?;
write_trunc_8_bytes(0, &(data.len() as u64).to_le_bytes(), out)?;
out.write_all(data)?;
Ok(())
}
TaggedData::Nested { tag, inner } => {
write_trunc_8_bytes(TAG_HEADER, &(tag.len() as u64).to_le_bytes(), out)?;
out.write_all(tag.as_bytes())?;
match &**inner {
Litl::TaggedData(TaggedData::Leaf (data)) => {
write_trunc_8_bytes(0, &(data.len() as u64).to_le_bytes(), out)?;
out.write_all(data)?;
Ok(())
},
Litl::TaggedData(deeper) => deeper.write(out),
_ => unreachable!()
}
}
}
}
}
fn write_str<W: Write>(str: &SmallBoxedStr, out: &mut W) -> std::io::Result<()> {
let as_bytes = str.as_bytes();
if as_bytes.len() == 1
&& as_bytes[0] > NULL_VALUE
&& (as_bytes[0] & 0b1000_0000 == 0)
&& (as_bytes[0] & 0b0111_0000 != 0b0001_0000)
{
out.write_all(&as_bytes[0..1])
} else if as_bytes.len() == 2 && as_bytes[0] & 0b1110_0000 == 0b_1100_0000 {
out.write_all(&as_bytes[0..2])
} else if as_bytes.len() == 3 && as_bytes[0] & 0b1111_0000 == 0b_1110_0000 {
out.write_all(&as_bytes[0..3])
} else if as_bytes.len() == 4 && as_bytes[0] & 0b1111_1000 == 0b_1111_0000 {
out.write_all(&as_bytes[0..4])
} else {
write_trunc_8_bytes(STR_HEADER, &(as_bytes.len() as u64).to_le_bytes(), out)?;
out.write_all(as_bytes)
}
}