Skip to main content

harmos_domain/model/storage/position/
codec.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12/* === Re-Exports === */
13
14/* === Imports === */
15
16// Standard Library Imports
17use std::borrow::Cow;
18use std::num::NonZeroUsize;
19// Third Party Imports
20
21// Local Imports
22use super::{StorageCursor, StoreHistory};
23use crate::schema::declaration::{Field, Kind};
24use crate::schema::{Cardinality, Described};
25use crate::{Error, Identifier, MemorySize, Message, Result};
26
27/* === Constants === */
28
29/* === Macros === */
30
31/* === Type Aliases === */
32
33/* === Structs === */
34
35/* === Enums === */
36
37/* === Traits === */
38
39/* === Implementations === */
40
41impl StoreHistory {
42    pub fn encode_bounded(&self, max_bytes: NonZeroUsize) -> Result<Vec<u8>> {
43        encode_bounded(self, max_bytes)
44    }
45
46    pub fn decode_bounded(bytes: &[u8], max_bytes: NonZeroUsize) -> Result<Self> {
47        decode_bounded(bytes, max_bytes)
48    }
49}
50
51impl StorageCursor {
52    pub fn encode_bounded(&self, max_bytes: NonZeroUsize) -> Result<Vec<u8>> {
53        encode_bounded(self, max_bytes)
54    }
55
56    pub fn decode_bounded(bytes: &[u8], max_bytes: NonZeroUsize) -> Result<Self> {
57        decode_bounded(bytes, max_bytes)
58    }
59}
60
61crate::postcard_product!(StoreHistory { store: Identifier, epoch: Identifier });
62crate::postcard_product!(StorageCursor { history: StoreHistory, sequence: u64 });
63
64impl Described for StoreHistory {
65    const NAME: &'static str = concat!(module_path!(), "::", stringify!(StoreHistory));
66    const FIELDS: &'static [Field] = &[
67        Field { name: Cow::Borrowed("store"), tag: 1, kind: Kind::String, cardinality: Cardinality::Required },
68        Field { name: Cow::Borrowed("epoch"), tag: 2, kind: Kind::String, cardinality: Cardinality::Required },
69    ];
70
71    const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
72        { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
73    >(Self::NAME, Self::FIELDS);
74}
75
76impl Described for StorageCursor {
77    const NAME: &'static str = concat!(module_path!(), "::", stringify!(StorageCursor));
78    const FIELDS: &'static [Field] = &[
79        Field {
80            name: Cow::Borrowed("history"),
81            tag: 1,
82            kind: Kind::Message { definition: StoreHistory::DEFINITION },
83            cardinality: Cardinality::Required,
84        },
85        Field { name: Cow::Borrowed("sequence"), tag: 2, kind: Kind::U64, cardinality: Cardinality::Required },
86    ];
87
88    const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
89        { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
90    >(Self::NAME, Self::FIELDS);
91}
92
93/* === Public Functions === */
94
95pub fn encode_bounded<T: Message>(value: &T, max_bytes: NonZeroUsize) -> Result<Vec<u8>> {
96    if value.encoded_len() > max_bytes.get() {
97        return Err(bound_error());
98    }
99    Ok(value.encode_to_vec())
100}
101
102pub fn decode_bounded<T: Message + MemorySize>(bytes: &[u8], max_bytes: NonZeroUsize) -> Result<T> {
103    let required =
104        T::decoding_memory(bytes).map_err(|_| Error::InvalidInput { field: "storage native codec", reason: "invalid encoding" })?;
105    if required > max_bytes.get() {
106        return Err(bound_error());
107    }
108    let value = T::decode(bytes).map_err(|_| Error::InvalidInput { field: "storage native codec", reason: "invalid encoding" })?;
109    if value.memory_size() > max_bytes.get() {
110        return Err(bound_error());
111    }
112    Ok(value)
113}
114
115/* === Private Functions === */
116
117fn bound_error() -> Error {
118    Error::InvalidInput { field: "storage native codec", reason: "value exceeds allowance" }
119}
120
121/* === Tests === */