1use crate::{Type, TypeTable, Value};
10use std::fmt;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct CodecError(pub String);
14
15impl fmt::Display for CodecError {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 f.write_str(&self.0)
18 }
19}
20
21impl std::error::Error for CodecError {}
22
23#[derive(Default)]
24pub struct Writer {
25 pub bytes: Vec<u8>,
26}
27
28impl Writer {
29 pub fn new() -> Self {
30 Self::default()
31 }
32 pub fn u8(&mut self, value: u8) {
33 self.bytes.push(value);
34 }
35 pub fn u32(&mut self, value: u32) {
36 self.bytes.extend_from_slice(&value.to_le_bytes());
37 }
38 pub fn u64(&mut self, value: u64) {
39 self.bytes.extend_from_slice(&value.to_le_bytes());
40 }
41 pub fn i64(&mut self, value: i64) {
42 self.bytes.extend_from_slice(&value.to_le_bytes());
43 }
44 pub fn f64(&mut self, value: f64) {
45 self.bytes.extend_from_slice(&value.to_le_bytes());
46 }
47 pub fn text(&mut self, value: &str) {
48 self.u32(value.len() as u32);
49 self.bytes.extend_from_slice(value.as_bytes());
50 }
51}
52
53pub struct Reader<'a> {
54 bytes: &'a [u8],
55 position: usize,
56}
57
58impl<'a> Reader<'a> {
59 pub fn new(bytes: &'a [u8]) -> Self {
60 Self { bytes, position: 0 }
61 }
62
63 fn take(&mut self, count: usize) -> Result<&'a [u8], CodecError> {
64 let end = self
65 .position
66 .checked_add(count)
67 .filter(|end| *end <= self.bytes.len())
68 .ok_or_else(|| CodecError("unexpected end of buffer".into()))?;
69 let slice = &self.bytes[self.position..end];
70 self.position = end;
71 Ok(slice)
72 }
73
74 pub fn u8(&mut self) -> Result<u8, CodecError> {
75 Ok(self.take(1)?[0])
76 }
77 pub fn u32(&mut self) -> Result<u32, CodecError> {
78 Ok(u32::from_le_bytes(self.take(4)?.try_into().unwrap()))
79 }
80 pub fn u64(&mut self) -> Result<u64, CodecError> {
81 Ok(u64::from_le_bytes(self.take(8)?.try_into().unwrap()))
82 }
83 pub fn i64(&mut self) -> Result<i64, CodecError> {
84 Ok(i64::from_le_bytes(self.take(8)?.try_into().unwrap()))
85 }
86 pub fn f64(&mut self) -> Result<f64, CodecError> {
87 Ok(f64::from_le_bytes(self.take(8)?.try_into().unwrap()))
88 }
89 pub fn text(&mut self) -> Result<String, CodecError> {
90 let length = self.u32()? as usize;
91 let bytes = self.take(length)?;
92 String::from_utf8(bytes.to_vec()).map_err(|_| CodecError("text is not UTF-8".into()))
93 }
94 pub fn is_finished(&self) -> bool {
95 self.position == self.bytes.len()
96 }
97}
98
99pub fn encode(value: &Value, ty: &Type, types: &TypeTable, writer: &mut Writer) {
101 match (value, ty) {
102 (Value::Unit, _) => {}
103 (Value::Bool(value), _) => writer.u8(u8::from(*value)),
104 (Value::Int(value), _) => writer.i64(*value),
105 (Value::Float(value), _) => writer.f64(*value),
106 (Value::Text(value), _) => writer.text(value),
107 (Value::Enum { variant, fields }, Type::Enum { name }) => {
108 writer.u32(*variant);
109 let def = types.enum_def(name).expect("checked enum");
110 for (field, def) in fields.iter().zip(&def.variants[*variant as usize].fields) {
111 encode(field, &def.ty, types, writer);
112 }
113 }
114 (Value::Optional(value), Type::Optional { inner }) => match value {
115 None => writer.u8(0),
116 Some(value) => {
117 writer.u8(1);
118 encode(value, inner, types, writer);
119 }
120 },
121 (Value::Record(fields), Type::Record { name }) => {
122 let def = types.record_def(name).expect("checked record");
123 for (field, def) in fields.iter().zip(&def.fields) {
124 encode(field, &def.ty, types, writer);
125 }
126 }
127 (Value::List(items), Type::List { inner }) => {
128 writer.u32(items.len() as u32);
129 for item in items {
130 encode(item, inner, types, writer);
131 }
132 }
133 _ => unreachable!("encode called with an unchecked value"),
134 }
135}
136
137pub fn decode(ty: &Type, types: &TypeTable, reader: &mut Reader<'_>) -> Result<Value, CodecError> {
139 Ok(match ty {
140 Type::Unit => Value::Unit,
141 Type::Bool => match reader.u8()? {
142 0 => Value::Bool(false),
143 1 => Value::Bool(true),
144 other => return Err(CodecError(format!("invalid bool byte {other}"))),
145 },
146 Type::Int => Value::Int(reader.i64()?),
147 Type::Float => {
148 let value = reader.f64()?;
149 if !value.is_finite() {
150 return Err(CodecError("float values must be finite".into()));
151 }
152 Value::Float(value)
153 }
154 Type::Text => Value::Text(reader.text()?),
155 Type::Enum { name } => {
156 let def = types
157 .enum_def(name)
158 .ok_or_else(|| CodecError(format!("unknown enum `{name}`")))?;
159 let variant = reader.u32()?;
160 let variant_def = def
161 .variants
162 .get(variant as usize)
163 .ok_or_else(|| CodecError(format!("`{name}` has no variant #{variant}")))?;
164 let fields = variant_def
165 .fields
166 .iter()
167 .map(|field| decode(&field.ty, types, reader))
168 .collect::<Result<_, _>>()?;
169 Value::Enum { variant, fields }
170 }
171 Type::Optional { inner } => match reader.u8()? {
172 0 => Value::Optional(None),
173 1 => Value::some(decode(inner, types, reader)?),
174 other => return Err(CodecError(format!("invalid optional flag {other}"))),
175 },
176 Type::Record { name } => {
177 let def = types
178 .record_def(name)
179 .ok_or_else(|| CodecError(format!("unknown record `{name}`")))?;
180 Value::Record(
181 def.fields
182 .iter()
183 .map(|field| decode(&field.ty, types, reader))
184 .collect::<Result<_, _>>()?,
185 )
186 }
187 Type::List { inner } => {
188 let count = reader.u32()? as usize;
189 let mut items = Vec::with_capacity(count.min(4096));
190 for _ in 0..count {
191 items.push(decode(inner, types, reader)?);
192 }
193 Value::List(items)
194 }
195 })
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201 use crate::{FieldDef, RecordDef};
202
203 #[test]
204 fn round_trip_preserves_values() {
205 let types = TypeTable {
206 enums: vec![],
207 records: vec![RecordDef {
208 name: "Row".into(),
209 fields: vec![
210 FieldDef {
211 name: "title".into(),
212 ty: Type::Text,
213 doc: String::new(),
214 content: false,
215 },
216 FieldDef {
217 name: "score".into(),
218 ty: Type::optional(Type::Float),
219 doc: String::new(),
220 content: false,
221 },
222 ],
223 }],
224 };
225 let ty = Type::list(Type::Record { name: "Row".into() });
226 let value = Value::List(vec![
227 Value::Record(vec![
228 Value::Text("你好".into()),
229 Value::some(Value::Float(1.5)),
230 ]),
231 Value::Record(vec![Value::Text(String::new()), Value::none()]),
232 ]);
233 value.check(&ty, &types).unwrap();
234 let mut writer = Writer::new();
235 encode(&value, &ty, &types, &mut writer);
236 let mut reader = Reader::new(&writer.bytes);
237 assert_eq!(decode(&ty, &types, &mut reader).unwrap(), value);
238 assert!(reader.is_finished());
239 let mut short = Reader::new(&writer.bytes[..writer.bytes.len() - 1]);
240 assert!(decode(&ty, &types, &mut short).is_err());
241 }
242}