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 {
68            name: Cow::Borrowed("store"),
69            tag: 1,
70            kind: Kind::String,
71            cardinality: Cardinality::Required,
72        },
73        Field {
74            name: Cow::Borrowed("epoch"),
75            tag: 2,
76            kind: Kind::String,
77            cardinality: Cardinality::Required,
78        },
79    ];
80
81    const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
82        { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
83    >(Self::NAME, Self::FIELDS);
84}
85
86impl Described for StorageCursor {
87    const NAME: &'static str = concat!(module_path!(), "::", stringify!(StorageCursor));
88    const FIELDS: &'static [Field] = &[
89        Field {
90            name: Cow::Borrowed("history"),
91            tag: 1,
92            kind: Kind::Message { definition: StoreHistory::DEFINITION },
93            cardinality: Cardinality::Required,
94        },
95        Field {
96            name: Cow::Borrowed("sequence"),
97            tag: 2,
98            kind: Kind::U64,
99            cardinality: Cardinality::Required,
100        },
101    ];
102
103    const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
104        { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
105    >(Self::NAME, Self::FIELDS);
106}
107
108/* === Public Functions === */
109
110pub fn encode_bounded<T: Message>(value: &T, max_bytes: NonZeroUsize) -> Result<Vec<u8>> {
111    if value.encoded_size() > max_bytes.get() {
112        return Err(bound_error());
113    }
114    Ok(value.encode())
115}
116
117pub fn decode_bounded<T: Message + MemorySize>(bytes: &[u8], max_bytes: NonZeroUsize) -> Result<T> {
118    let required = T::decoding_memory(bytes).map_err(|_| Error::InvalidInput {
119        field: "storage native codec",
120        reason: "invalid encoding",
121    })?;
122    if required > max_bytes.get() {
123        return Err(bound_error());
124    }
125    let value = T::decode(bytes).map_err(|_| Error::InvalidInput {
126        field: "storage native codec",
127        reason: "invalid encoding",
128    })?;
129    if value.memory_size() > max_bytes.get() {
130        return Err(bound_error());
131    }
132    Ok(value)
133}
134
135/* === Private Functions === */
136
137fn bound_error() -> Error {
138    Error::InvalidInput {
139        field: "storage native codec",
140        reason: "value exceeds allowance",
141    }
142}
143
144/* === Tests === */