1use std::borrow::Cow;
18use std::collections::BTreeMap;
19use time::OffsetDateTime;
21use super::Value;
23use crate::message::{PostcardReader as Reader, PostcardValue, decoding_add, decoding_multiply};
24use crate::schema::declaration::{Definition, Field, Kind};
25use crate::schema::{Cardinality, Described};
26use crate::{MessageError, btree_map_memory};
27
28pub const VALUE_DEPTH: usize = 4;
31
32const NULL: u32 = 0;
34const BOOL: u32 = 1;
35const INTEGER: u32 = 2;
36const UNSIGNED: u32 = 3;
37const NUMBER: u32 = 4;
38const TEXT: u32 = 5;
39const DATETIME: u32 = 6;
40const ARRAY: u32 = 7;
41const OBJECT: u32 = 8;
42
43pub(crate) const TIMESTAMP_DEFINITION: Definition = Timestamp::DEFINITION;
44pub(crate) const VALUE_FIELDS: &[Field] = Value4::FIELDS;
45pub(crate) const ENTRY_DEFINITION: Definition = Entry4::DEFINITION;
46
47macro_rules! shape {
50 ($name:ident, $fields:expr) => {
51 pub(crate) struct $name;
52 impl Described for $name {
53 const NAME: &'static str = concat!(module_path!(), "::", stringify!($name));
54 const FIELDS: &'static [Field] = $fields;
55 const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
56 { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
57 >(Self::NAME, Self::FIELDS);
58 }
59 };
60}
61
62macro_rules! level {
63 ($level:ident, $entry:ident, $array:ident, $object:ident, $inner:ident) => {
64 shape!($array, &[field("items", 1, message($inner::DEFINITION), Cardinality::Repeated)]);
65 shape!(
66 $entry,
67 &[field("key", 1, Kind::String, Cardinality::Required), field("value", 2, message($inner::DEFINITION), Cardinality::Required),]
68 );
69 shape!($object, &[field("entries", 1, message($entry::DEFINITION), Cardinality::Repeated)]);
70 shape!(
71 $level,
72 &[
73 field("null", 1, message(<()>::DEFINITION), Cardinality::Variant),
74 field("bool", 2, message(<bool>::DEFINITION), Cardinality::Variant),
75 field("integer", 3, message(<i64>::DEFINITION), Cardinality::Variant),
76 field("unsigned", 4, message(<u64>::DEFINITION), Cardinality::Variant),
77 field("number", 5, message(<f64>::DEFINITION), Cardinality::Variant),
78 field("text", 6, message(String::DEFINITION), Cardinality::Variant),
79 field("datetime", 7, message(Timestamp::DEFINITION), Cardinality::Variant),
80 field("array", 8, message($array::DEFINITION), Cardinality::Variant),
81 field("object", 9, message($object::DEFINITION), Cardinality::Variant),
82 ]
83 );
84 };
85}
86
87shape!(Timestamp, &[field("seconds", 1, Kind::I64, Cardinality::Required), field("nanos", 2, Kind::U32, Cardinality::Required),]);
88shape!(
89 Value0,
90 &[
91 field("null", 1, message(<()>::DEFINITION), Cardinality::Variant),
92 field("bool", 2, message(<bool as Described>::DEFINITION), Cardinality::Variant,),
93 field("integer", 3, message(<i64 as Described>::DEFINITION), Cardinality::Variant,),
94 field("unsigned", 4, message(<u64 as Described>::DEFINITION), Cardinality::Variant,),
95 field("number", 5, message(<f64 as Described>::DEFINITION), Cardinality::Variant,),
96 field("text", 6, message(<String as Described>::DEFINITION), Cardinality::Variant,),
97 field("datetime", 7, message(Timestamp::DEFINITION), Cardinality::Variant,),
98 ]
99);
100level!(Value1, Entry1, Array1, Object1, Value0);
101level!(Value2, Entry2, Array2, Object2, Value1);
102level!(Value3, Entry3, Array3, Object3, Value2);
103level!(Value4, Entry4, Array4, Object4, Value3);
104
105impl Described for Value {
116 const NAME: &'static str = "harmos::Value";
117 const FIELDS: &'static [Field] = VALUE_FIELDS;
118 const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
119 { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
120 >(Self::NAME, Self::FIELDS);
121}
122
123impl PostcardValue for Value {
124 fn write(&self, bytes: &mut Vec<u8>) {
125 match self {
126 Self::Null => NULL.write(bytes),
127 Self::Bool(value) => {
128 BOOL.write(bytes);
129 value.write(bytes);
130 }
131 Self::Integer(value) => {
132 INTEGER.write(bytes);
133 value.write(bytes);
134 }
135 Self::Unsigned(value) => {
136 UNSIGNED.write(bytes);
137 value.write(bytes);
138 }
139 Self::Number(value) => {
140 NUMBER.write(bytes);
141 value.write(bytes);
142 }
143 Self::Text(value) => {
144 TEXT.write(bytes);
145 value.write(bytes);
146 }
147 Self::Datetime(value) => {
148 DATETIME.write(bytes);
149 write_timestamp(*value, bytes);
150 }
151 Self::Array(values) => {
152 ARRAY.write(bytes);
153 values.len().write(bytes);
154 for value in values {
155 value.write(bytes);
156 }
157 }
158 Self::Object(entries) => {
159 OBJECT.write(bytes);
160 write_entries(entries, bytes);
161 }
162 }
163 }
164
165 fn size(&self) -> usize {
166 let payload = match self {
167 Self::Null => 0,
168 Self::Bool(value) => value.size(),
169 Self::Integer(value) => value.size(),
170 Self::Unsigned(value) => value.size(),
171 Self::Number(value) => value.size(),
172 Self::Text(value) => value.size(),
173 Self::Datetime(value) => timestamp_size(*value),
174 Self::Array(values) => values.iter().fold(values.len().size(), |size, value| size.saturating_add(value.size())),
175 Self::Object(entries) => entries_size(entries),
176 };
177 variant(self).size().saturating_add(payload)
178 }
179
180 fn memory(input: &mut Reader<'_>) -> Result<usize, MessageError> {
181 memory_at(input, VALUE_DEPTH)
182 }
183
184 fn read(input: &mut Reader<'_>) -> Result<Self, MessageError> {
185 read_at(input, VALUE_DEPTH)
186 }
187}
188
189const fn field(name: &'static str, tag: u32, kind: Kind, cardinality: Cardinality) -> Field {
194 Field { name: Cow::Borrowed(name), tag, kind, cardinality }
195}
196
197const fn message(definition: Definition) -> Kind {
198 Kind::Message { definition }
199}
200
201fn variant(value: &Value) -> u32 {
202 match value {
203 Value::Null => NULL,
204 Value::Bool(_) => BOOL,
205 Value::Integer(_) => INTEGER,
206 Value::Unsigned(_) => UNSIGNED,
207 Value::Number(_) => NUMBER,
208 Value::Text(_) => TEXT,
209 Value::Datetime(_) => DATETIME,
210 Value::Array(_) => ARRAY,
211 Value::Object(_) => OBJECT,
212 }
213}
214
215fn depth_error() -> MessageError {
216 MessageError::borrowed("value nests deeper than its portable depth")
217}
218
219pub(crate) fn timestamp_parts(value: OffsetDateTime) -> (i64, u32) {
220 (value.unix_timestamp(), value.nanosecond())
221}
222
223pub(crate) fn from_parts(seconds: i64, nanos: u64) -> Result<OffsetDateTime, MessageError> {
224 let nanos = u32::try_from(nanos)
225 .ok()
226 .filter(|nanos| *nanos < 1_000_000_000)
227 .ok_or_else(|| MessageError::borrowed("timestamp nanoseconds out of range"))?;
228 OffsetDateTime::from_unix_timestamp(seconds)
229 .ok()
230 .and_then(|value| value.replace_nanosecond(nanos).ok())
231 .ok_or_else(|| MessageError::borrowed("timestamp out of range"))
232}
233
234pub(crate) fn write_timestamp(value: OffsetDateTime, bytes: &mut Vec<u8>) {
235 let (seconds, nanos) = timestamp_parts(value);
236 seconds.write(bytes);
237 nanos.write(bytes);
238}
239
240pub(crate) fn timestamp_size(value: OffsetDateTime) -> usize {
241 let (seconds, nanos) = timestamp_parts(value);
242 seconds.size().saturating_add(nanos.size())
243}
244
245pub(crate) fn read_timestamp(input: &mut Reader<'_>) -> Result<OffsetDateTime, MessageError> {
246 let seconds = i64::read(input)?;
247 let nanos = u32::read(input)?;
248 from_parts(seconds, u64::from(nanos))
249}
250
251pub(crate) fn write_entries(entries: &BTreeMap<String, Value>, bytes: &mut Vec<u8>) {
252 entries.len().write(bytes);
253 for (key, value) in entries {
254 key.write(bytes);
255 value.write(bytes);
256 }
257}
258
259pub(crate) fn entries_size(entries: &BTreeMap<String, Value>) -> usize {
260 entries.iter().fold(entries.len().size(), |size, (key, value)| size.saturating_add(key.size()).saturating_add(value.size()))
261}
262
263pub(crate) fn entries_memory(input: &mut Reader<'_>, depth: usize) -> Result<usize, MessageError> {
264 input.nested(|input| {
265 let count: usize = input.value()?;
266 input.claim(count)?;
267 let mut owned = btree_map_memory::<String, Value>(count);
268 for _ in 0..count {
269 let key = String::memory(input)?.saturating_sub(std::mem::size_of::<String>());
270 let value = memory_at(input, depth)?.saturating_sub(std::mem::size_of::<Value>());
271 owned = decoding_add(owned, decoding_add(key, value)?)?;
272 }
273 Ok(owned)
274 })
275}
276
277pub(crate) fn read_entries(input: &mut Reader<'_>, depth: usize) -> Result<BTreeMap<String, Value>, MessageError> {
278 input.nested(|input| {
279 let count: usize = input.value()?;
280 input.claim(count)?;
281 let mut entries = BTreeMap::new();
282 for _ in 0..count {
283 let key = String::read(input)?;
284 let value = read_at(input, depth)?;
285 if entries.insert(key, value).is_some() {
286 return Err(MessageError::borrowed("duplicate value object key"));
287 }
288 }
289 Ok(entries)
290 })
291}
292
293fn memory_at(input: &mut Reader<'_>, depth: usize) -> Result<usize, MessageError> {
294 input.nested(|input| {
295 let owned = std::mem::size_of::<Value>();
296 let allocation = match u32::read(input)? {
297 NULL => 0,
298 BOOL => {
299 bool::read(input)?;
300 0
301 }
302 INTEGER => {
303 i64::read(input)?;
304 0
305 }
306 UNSIGNED => {
307 u64::read(input)?;
308 0
309 }
310 NUMBER => {
311 f64::read(input)?;
312 0
313 }
314 TEXT => String::memory(input)?.saturating_sub(std::mem::size_of::<String>()),
315 DATETIME => {
316 read_timestamp(input)?;
317 0
318 }
319 ARRAY => {
320 let depth = depth.checked_sub(1).ok_or_else(depth_error)?;
321 let count: usize = input.value()?;
322 input.claim(count)?;
323 let mut items = decoding_multiply(count, std::mem::size_of::<Value>())?;
324 for _ in 0..count {
325 let item = memory_at(input, depth)?;
326 items = decoding_add(items, item.saturating_sub(std::mem::size_of::<Value>()))?;
327 }
328 items
329 }
330 OBJECT => {
331 let depth = depth.checked_sub(1).ok_or_else(depth_error)?;
332 entries_memory(input, depth)?
333 }
334 _ => return Err(MessageError::borrowed("unknown value variant")),
335 };
336 decoding_add(owned, allocation)
337 })
338}
339
340fn read_at(input: &mut Reader<'_>, depth: usize) -> Result<Value, MessageError> {
341 input.nested(|input| {
342 Ok(match u32::read(input)? {
343 NULL => Value::Null,
344 BOOL => Value::Bool(bool::read(input)?),
345 INTEGER => Value::Integer(i64::read(input)?),
346 UNSIGNED => Value::Unsigned(u64::read(input)?),
347 NUMBER => Value::Number(f64::read(input)?),
348 TEXT => Value::Text(String::read(input)?),
349 DATETIME => Value::Datetime(read_timestamp(input)?),
350 ARRAY => {
351 let depth = depth.checked_sub(1).ok_or_else(depth_error)?;
352 let count: usize = input.value()?;
353 input.claim(count)?;
354 let mut items = crate::message::decoding_vector(count)?;
355 for _ in 0..count {
356 items.push(read_at(input, depth)?);
357 }
358 Value::Array(items)
359 }
360 OBJECT => {
361 let depth = depth.checked_sub(1).ok_or_else(depth_error)?;
362 Value::Object(read_entries(input, depth)?)
363 }
364 _ => return Err(MessageError::borrowed("unknown value variant")),
365 })
366 })
367}
368
369