Skip to main content

harmos_domain/model/storage/
codec.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12mod timestamp;
13
14/* === Re-Exports === */
15
16pub use timestamp::Time;
17
18/* === Imports === */
19
20// Standard Library Imports
21use std::borrow::Cow;
22use std::marker::PhantomData;
23use std::num::NonZeroU32;
24
25// Third Party Imports
26
27// Local Imports
28use crate::__private::{PostcardReader, PostcardValue};
29use crate::schema::declaration::{self, Field, Kind};
30use crate::schema::{Cardinality, Described};
31use crate::{Identifier, MemorySize, MessageError};
32
33/* === Constants === */
34
35/* === Macros === */
36
37macro_rules! product {
38    ($ty:ty { $($field:ident: $codec:ty => $tag:literal),* $(,)? }) => {
39        crate::model::storage::codec::product!($ty { $($field: $codec => $tag),* }, check = |_: &$ty| Ok(()));
40    };
41    ($ty:ty { $($field:ident: $codec:ty => $tag:literal),* $(,)? }, check = $check:expr) => {
42        impl crate::schema::Described for $ty {
43            const NAME: &'static str = concat!(module_path!(), "::", stringify!($ty));
44            const FIELDS: &'static [crate::schema::declaration::Field] = &[$(crate::schema::declaration::Field {
45                name: std::borrow::Cow::Borrowed(stringify!($field)),
46                tag: $tag,
47                kind: <$codec as crate::model::storage::codec::Value>::KIND,
48                cardinality: <$codec as crate::model::storage::codec::Value>::CARDINALITY,
49            }),*];
50
51            const MARKER: &'static [u8] = &crate::schema::declaration::encode::<{
52                crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS)
53            }>(Self::NAME, Self::FIELDS);
54}
55        #[allow(unused_variables)]
56        impl crate::__private::PostcardValue for $ty {
57            fn write(&self, bytes: &mut Vec<u8>) {
58                $(<$codec as crate::model::storage::codec::Value>::postcard_write(&self.$field, bytes);)*
59            }
60            fn size(&self) -> usize {
61                0usize$(.saturating_add(<$codec as crate::model::storage::codec::Value>::postcard_size(&self.$field)))*
62            }
63            fn memory(input: &mut crate::__private::PostcardReader<'_>) -> std::result::Result<usize, crate::MessageError> {
64                input.nested(|input| {
65                    let memory = std::mem::size_of::<Self>();
66                    $(let memory = crate::__private::decoding_add(memory, <$codec as crate::model::storage::codec::Value>::postcard_memory(input)?)?;)*
67                    Ok(memory)
68                })
69            }
70            fn read(input: &mut crate::__private::PostcardReader<'_>) -> std::result::Result<Self, crate::MessageError> {
71                let value = input.nested(|input| Ok(Self { $($field: <$codec as crate::model::storage::codec::Value>::postcard_read(input)?),* }))?;
72                let check: fn(&Self) -> std::result::Result<(), crate::MessageError> = $check;
73                check(&value)?;
74                Ok(value)
75            }
76        }
77    };
78}
79
80pub(crate) use product;
81
82macro_rules! postcard_field {
83    () => {
84        fn postcard_write(value: &Self::Native, bytes: &mut Vec<u8>) {
85            crate::__private::PostcardValue::write(value, bytes);
86        }
87        fn postcard_size(value: &Self::Native) -> usize {
88            crate::__private::PostcardValue::size(value)
89        }
90        fn postcard_memory(input: &mut crate::__private::PostcardReader<'_>) -> std::result::Result<usize, crate::MessageError> {
91            Ok(<Self::Native as crate::__private::PostcardValue>::memory(input)?.saturating_sub(std::mem::size_of::<Self::Native>()))
92        }
93        fn postcard_read(input: &mut crate::__private::PostcardReader<'_>) -> std::result::Result<Self::Native, crate::MessageError> {
94            <Self::Native as crate::__private::PostcardValue>::read(input)
95        }
96    };
97}
98pub(crate) use postcard_field;
99
100macro_rules! variants {
101    ($ty:ty { $($index:literal, $tag:literal, $name:literal: $pat:pat => { $($field:ident: $codec:ty => $ftag:literal),* $(,)? } => $build:expr;)+ }) => {
102        const _: () = {
103        struct Variant<const TAG: u32>;
104        $(impl crate::schema::Described for Variant<$tag> {
105            const NAME: &'static str = concat!(module_path!(), "::", stringify!($ty), "::", $name);
106            const FIELDS: &'static [crate::schema::declaration::Field] = &[$(crate::schema::declaration::Field {
107                name: std::borrow::Cow::Borrowed(stringify!($field)), tag: $ftag,
108                kind: <$codec as crate::model::storage::codec::Value>::KIND,
109                cardinality: <$codec as crate::model::storage::codec::Value>::CARDINALITY,
110            }),*];
111            const MARKER: &'static [u8] = &crate::schema::declaration::encode::<{
112                crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS)
113            }>(Self::NAME, Self::FIELDS);
114        })+
115        impl crate::schema::Described for $ty {
116            const NAME: &'static str = concat!(module_path!(), "::", stringify!($ty));
117            const FIELDS: &'static [crate::schema::declaration::Field] = &[$(crate::schema::declaration::Field {
118                name: std::borrow::Cow::Borrowed($name),
119                tag: $tag,
120                cardinality: crate::schema::Cardinality::Variant,
121                kind: crate::schema::declaration::Kind::Message {
122                    definition: <Variant<$tag> as crate::schema::Described>::DEFINITION,
123                },
124            }),+];
125
126            // Every Storage Oneof Requires Its Variant; An Absent One Is Refused.
127            const DEFAULT_VARIANT: Option<usize> = None;
128            const MARKER: &'static [u8] = &crate::schema::declaration::encode::<{
129                crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS)
130            }>(Self::NAME, Self::FIELDS);
131}
132        impl crate::__private::PostcardValue for $ty {
133            #[allow(unused_variables)]
134            fn write(&self, bytes: &mut Vec<u8>) {
135                match self {
136                    $($pat => {
137                        crate::__private::PostcardValue::write(&($index as u32), bytes);
138                        $(<$codec as crate::model::storage::codec::Value>::postcard_write($field, bytes);)*
139                    })+
140                }
141            }
142            #[allow(unused_variables)]
143            fn size(&self) -> usize {
144                match self {
145                    $($pat => crate::__private::PostcardValue::size(&($index as u32))
146                        $(.saturating_add(<$codec as crate::model::storage::codec::Value>::postcard_size($field)))*,)+
147                }
148            }
149            fn memory(input: &mut crate::__private::PostcardReader<'_>) -> std::result::Result<usize, crate::MessageError> {
150                input.nested(|input| {
151                    let memory = std::mem::size_of::<Self>();
152                    match input.value::<u32>()? {
153                        $($index => {
154                            $(let memory = crate::__private::decoding_add(memory, <$codec as crate::model::storage::codec::Value>::postcard_memory(input)?)?;)*
155                            Ok(memory)
156                        })+
157                        _ => Err(crate::MessageError::borrowed(concat!("unknown ", stringify!($ty), " variant"))),
158                    }
159                })
160            }
161            fn read(input: &mut crate::__private::PostcardReader<'_>) -> std::result::Result<Self, crate::MessageError> {
162                input.nested(|input| match input.value::<u32>()? {
163                    $($index => {
164                        $(let $field = <$codec as crate::model::storage::codec::Value>::postcard_read(input)?;)*
165                        Ok($build)
166                    })+
167                    _ => Err(crate::MessageError::borrowed(concat!("unknown ", stringify!($ty), " variant"))),
168                })
169            }
170        }
171        };
172    };
173}
174pub(crate) use variants;
175
176macro_rules! coded {
177    ($ty:ident { $($variant:ident),+ $(,)? }) => {
178        impl crate::model::storage::codec::Coded for $ty {
179            const NAME: &'static str = concat!(module_path!(), "::", stringify!($ty));
180            const VARIANTS: &'static [Self] = &[$(Self::$variant),+];
181        }
182    };
183}
184pub(crate) use coded;
185
186/* === Type Aliases === */
187
188type Result<T, E = MessageError> = std::result::Result<T, E>;
189
190/* === Structs === */
191
192pub struct Repeated<T>(PhantomData<fn() -> T>);
193pub struct Nested<T>(PhantomData<fn() -> T>);
194pub struct Optional<T>(PhantomData<fn() -> T>);
195pub struct Id;
196pub struct Bytes;
197pub struct Unsigned;
198pub struct Percent;
199pub struct Version;
200pub struct Flag;
201pub struct Signed;
202pub struct Float;
203pub struct Text;
204pub struct Code<E>(PhantomData<fn() -> E>);
205pub struct Index;
206pub struct Wide;
207pub struct WideNonZero;
208pub struct WideSigned;
209pub struct Wrap<A>(PhantomData<fn() -> A>);
210pub struct Many<A>(PhantomData<fn() -> A>);
211
212/* === Enums === */
213
214/* === Traits === */
215
216pub trait Native: PostcardValue + MemorySize + Described {}
217impl<T: PostcardValue + MemorySize + Described> Native for T {}
218
219pub trait Coded: Copy + PartialEq + Send + Sync + 'static {
220    const NAME: &'static str;
221    const VARIANTS: &'static [Self];
222    fn code(&self) -> u32 {
223        Self::VARIANTS
224            .iter()
225            .position(|variant| variant == self)
226            .and_then(|index| u32::try_from(index).ok())
227            .expect("a coded variant is listed")
228    }
229
230    fn from_code(code: u64) -> Result<Self> {
231        usize::try_from(code)
232            .ok()
233            .and_then(|index| Self::VARIANTS.get(index).copied())
234            .ok_or_else(|| MessageError::borrowed("unknown storage enum code"))
235    }
236}
237
238pub trait Value: 'static {
239    const NAME: &'static str;
240    type Native;
241    const KIND: Kind;
242    const CARDINALITY: Cardinality = Cardinality::Required;
243    fn postcard_write(value: &Self::Native, bytes: &mut Vec<u8>);
244    fn postcard_size(value: &Self::Native) -> usize;
245    fn postcard_memory(input: &mut PostcardReader<'_>) -> Result<usize>;
246    fn postcard_read(input: &mut PostcardReader<'_>) -> Result<Self::Native>;
247}
248
249/* === Implementations === */
250
251impl<T: Native> Value for Repeated<T> {
252    const NAME: &'static str = declaration::Name::new(concat!(module_path!(), "::", stringify!(Repeated)), &[T::NAME]).as_str();
253    postcard_field!();
254    type Native = Vec<T>;
255    const KIND: Kind = Nested::<T>::KIND;
256    const CARDINALITY: Cardinality = Cardinality::Repeated;
257}
258
259impl<T: Native> Value for Nested<T> {
260    const NAME: &'static str = declaration::Name::new(concat!(module_path!(), "::", stringify!(Nested)), &[T::NAME]).as_str();
261    postcard_field!();
262    type Native = T;
263    const KIND: Kind = Kind::Message { definition: T::DEFINITION };
264}
265
266impl<T: Value> Value for Optional<T> {
267    const NAME: &'static str = declaration::Name::new(concat!(module_path!(), "::", stringify!(Optional)), &[T::NAME]).as_str();
268    fn postcard_write(value: &Self::Native, bytes: &mut Vec<u8>) {
269        PostcardValue::write(&value.is_some(), bytes);
270        if let Some(value) = value {
271            T::postcard_write(value, bytes);
272        }
273    }
274
275    fn postcard_size(value: &Self::Native) -> usize {
276        1usize.saturating_add(value.as_ref().map_or(0, T::postcard_size))
277    }
278
279    fn postcard_memory(input: &mut PostcardReader<'_>) -> Result<usize> {
280        input.nested(|input| if input.value::<bool>()? { T::postcard_memory(input) } else { Ok(0) })
281    }
282
283    fn postcard_read(input: &mut PostcardReader<'_>) -> Result<Self::Native> {
284        input.nested(|input| if input.value::<bool>()? { T::postcard_read(input).map(Some) } else { Ok(None) })
285    }
286
287    type Native = Option<T::Native>;
288    const KIND: Kind = T::KIND;
289    const CARDINALITY: Cardinality = Cardinality::Optional;
290}
291
292impl Value for Id {
293    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Id));
294    postcard_field!();
295    type Native = Identifier;
296    const KIND: Kind = Kind::String;
297}
298
299impl Value for Bytes {
300    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Bytes));
301    postcard_field!();
302    type Native = Vec<u8>;
303    const KIND: Kind = Kind::Bytes;
304}
305
306impl Value for Unsigned {
307    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Unsigned));
308    postcard_field!();
309    type Native = u64;
310    const KIND: Kind = Kind::U64;
311}
312
313// A whole percentage rank, carried as a protobuf `uint32`; the rank's range is
314// a plan rule, so any byte decodes and the plan check refuses above 100.
315impl Value for Percent {
316    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Percent));
317    postcard_field!();
318    type Native = u8;
319    const KIND: Kind = Kind::U32;
320}
321
322impl Value for Version {
323    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Version));
324    postcard_field!();
325    type Native = NonZeroU32;
326    const KIND: Kind = Kind::U32;
327}
328
329macro_rules! varint {
330    ($adapter:ty, $native:ty, $kind:ident, $encoding:ident, $from:expr) => {
331        impl Value for $adapter {
332            const NAME: &'static str = concat!(module_path!(), "::", stringify!($adapter));
333            postcard_field!();
334            type Native = $native;
335            const KIND: Kind = Kind::$kind;
336        }
337    };
338}
339
340varint!(Flag, bool, Bool, bool, |value: u64| match value {
341    0 => Ok(false),
342    1 => Ok(true),
343    _ => Err(MessageError::borrowed("invalid storage boolean")),
344});
345varint!(Signed, i64, I64, int64, |value: u64| Ok(value as i64));
346
347impl Value for Float {
348    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Float));
349    postcard_field!();
350    type Native = f64;
351    const KIND: Kind = Kind::F64;
352}
353
354impl Value for Text {
355    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Text));
356    postcard_field!();
357    type Native = String;
358    const KIND: Kind = Kind::String;
359}
360
361impl<E: Coded> Value for Code<E> {
362    const NAME: &'static str = declaration::Name::new(concat!(module_path!(), "::", stringify!(Code)), &[E::NAME]).as_str();
363    type Native = E;
364    const KIND: Kind = Kind::U32;
365    fn postcard_write(value: &E, bytes: &mut Vec<u8>) {
366        PostcardValue::write(&value.code(), bytes);
367    }
368
369    fn postcard_size(value: &E) -> usize {
370        PostcardValue::size(&value.code())
371    }
372
373    fn postcard_memory(input: &mut PostcardReader<'_>) -> Result<usize> {
374        E::from_code(u64::from(input.value::<u32>()?))?;
375        Ok(0)
376    }
377
378    fn postcard_read(input: &mut PostcardReader<'_>) -> Result<E> {
379        E::from_code(u64::from(input.value::<u32>()?))
380    }
381}
382
383// Host Indices And Counts Travel As uint64; Decoding Never Truncates.
384fn host_width(value: u64) -> Result<usize> {
385    usize::try_from(value).map_err(|_| MessageError::borrowed("index exceeds host width"))
386}
387
388impl Value for Index {
389    const NAME: &'static str = concat!(module_path!(), "::", stringify!(Index));
390    type Native = usize;
391    const KIND: Kind = Kind::U64;
392    fn postcard_write(value: &usize, bytes: &mut Vec<u8>) {
393        PostcardValue::write(&(*value as u64), bytes);
394    }
395
396    fn postcard_size(value: &usize) -> usize {
397        PostcardValue::size(&(*value as u64))
398    }
399
400    fn postcard_memory(input: &mut PostcardReader<'_>) -> Result<usize> {
401        Self::postcard_read(input)?;
402        Ok(0)
403    }
404
405    fn postcard_read(input: &mut PostcardReader<'_>) -> Result<usize> {
406        host_width(input.value::<u64>()?)
407    }
408}
409
410// 128-Bit Values Travel As A Message Of Lossless High And Low Halves.
411macro_rules! wide {
412    ($adapter:ty, $native:ty, $high:ty, $high_codec:ty, $split:expr, $join:expr) => {
413        impl Described for $adapter {
414            const NAME: &'static str = <Self as Value>::NAME;
415            const FIELDS: &'static [Field] = &[
416                crate::schema::declaration::Field {
417                    name: Cow::Borrowed("high"),
418                    tag: 1,
419                    kind: <$high_codec as Value>::KIND,
420                    cardinality: Cardinality::Required,
421                },
422                crate::schema::declaration::Field {
423                    name: Cow::Borrowed("low"),
424                    tag: 2,
425                    kind: Kind::U64,
426                    cardinality: Cardinality::Required,
427                },
428            ];
429            const MARKER: &'static [u8] = &declaration::encode::<{ declaration::encoded_len(<Self as Described>::NAME, Self::FIELDS) }>(
430                <Self as Described>::NAME,
431                Self::FIELDS,
432            );
433        }
434        impl Value for $adapter {
435            const NAME: &'static str = concat!(module_path!(), "::", stringify!($adapter));
436            type Native = $native;
437            const KIND: Kind = Kind::Message { definition: <Self as Described>::DEFINITION };
438            fn postcard_write(value: &$native, bytes: &mut Vec<u8>) {
439                let (high, low): ($high, u64) = ($split)(*value);
440                PostcardValue::write(&high, bytes);
441                PostcardValue::write(&low, bytes);
442            }
443            fn postcard_size(value: &$native) -> usize {
444                let (high, low): ($high, u64) = ($split)(*value);
445                PostcardValue::size(&high).saturating_add(PostcardValue::size(&low))
446            }
447            fn postcard_memory(input: &mut PostcardReader<'_>) -> Result<usize> {
448                Self::postcard_read(input)?;
449                Ok(0)
450            }
451            fn postcard_read(input: &mut PostcardReader<'_>) -> Result<$native> {
452                let high = input.value::<$high>()?;
453                let low = input.value::<u64>()?;
454                ($join)(high, low)
455            }
456        }
457    };
458}
459
460wide!(Wide, u128, u64, Unsigned, |value: u128| ((value >> 64) as u64, value as u64), |high: u64, low: u64| Ok::<_, MessageError>(
461    (u128::from(high) << 64) | u128::from(low)
462));
463wide!(
464    WideNonZero,
465    std::num::NonZeroU128,
466    u64,
467    Unsigned,
468    |value: std::num::NonZeroU128| ((value.get() >> 64) as u64, value.get() as u64),
469    |high: u64, low: u64| std::num::NonZeroU128::new((u128::from(high) << 64) | u128::from(low))
470        .ok_or_else(|| MessageError::borrowed("wide value must be nonzero"))
471);
472wide!(WideSigned, i128, i64, Signed, |value: i128| ((value >> 64) as i64, value as u64), |high: i64, low: u64| Ok::<_, MessageError>(
473    (i128::from(high) << 64) | i128::from(low)
474));
475
476// One Message Holding A Single Field At Tag 1; Absence Reads As Empty.
477impl<A: Value> Described for Wrap<A> {
478    const NAME: &'static str = <Self as Value>::NAME;
479    const FIELDS: &'static [Field] =
480        &[crate::schema::declaration::Field { name: Cow::Borrowed("value"), tag: 1, kind: A::KIND, cardinality: A::CARDINALITY }];
481    const MARKER: &'static [u8] = declaration::encode_buffer::<2048>(<Self as Described>::NAME, Self::FIELDS)
482        .split_at(declaration::encoded_len(<Self as Described>::NAME, Self::FIELDS))
483        .0;
484}
485impl<A: Value> Value for Wrap<A> {
486    const NAME: &'static str = declaration::Name::new(concat!(module_path!(), "::", stringify!(Wrap)), &[A::NAME]).as_str();
487    type Native = A::Native;
488    const KIND: Kind = Kind::Message { definition: <Self as Described>::DEFINITION };
489    fn postcard_write(value: &A::Native, bytes: &mut Vec<u8>) {
490        A::postcard_write(value, bytes);
491    }
492
493    fn postcard_size(value: &A::Native) -> usize {
494        A::postcard_size(value)
495    }
496
497    fn postcard_memory(input: &mut PostcardReader<'_>) -> Result<usize> {
498        A::postcard_memory(input)
499    }
500
501    fn postcard_read(input: &mut PostcardReader<'_>) -> Result<A::Native> {
502        A::postcard_read(input)
503    }
504}
505
506// Repeated Messages, Each Holding One Element At Tag 1.
507impl<A: Value> Value for Many<A> {
508    const NAME: &'static str = declaration::Name::new(concat!(module_path!(), "::", stringify!(Many)), &[A::NAME]).as_str();
509    type Native = Vec<A::Native>;
510    const KIND: Kind = Wrap::<A>::KIND;
511    const CARDINALITY: Cardinality = Cardinality::Repeated;
512    fn postcard_write(values: &Vec<A::Native>, bytes: &mut Vec<u8>) {
513        PostcardValue::write(&(values.len() as u64), bytes);
514        for value in values {
515            A::postcard_write(value, bytes);
516        }
517    }
518
519    fn postcard_size(values: &Vec<A::Native>) -> usize {
520        values.iter().fold(PostcardValue::size(&(values.len() as u64)), |size, value| size.saturating_add(A::postcard_size(value)))
521    }
522
523    fn postcard_memory(input: &mut PostcardReader<'_>) -> Result<usize> {
524        let count = host_width(input.value::<u64>()?)?;
525        input.claim(count)?;
526        let mut memory = crate::__private::decoding_multiply(count, std::mem::size_of::<A::Native>())?;
527        for _ in 0..count {
528            memory = crate::__private::decoding_add(memory, A::postcard_memory(input)?)?;
529        }
530        Ok(memory)
531    }
532
533    fn postcard_read(input: &mut PostcardReader<'_>) -> Result<Vec<A::Native>> {
534        let count = host_width(input.value::<u64>()?)?;
535        input.claim(count)?;
536        let mut values = crate::__private::decoding_vector(count)?;
537        for _ in 0..count {
538            values.push(A::postcard_read(input)?);
539        }
540        Ok(values)
541    }
542}
543
544// One Message Holding A Pair At Tags 1 And 2.
545/* === Public Functions === */
546
547/* === Private Functions === */
548
549/* === Tests === */