harmos_domain/model/storage/
objects.rs1pub mod codec;
13
14pub use codec::Key;
17
18use std::borrow::Cow;
22use std::num::{NonZeroU64, NonZeroUsize};
23
24use serde::{Deserialize, Serialize};
26
27use crate::Identifier;
29use crate::model::storage::keys::invalid;
30use crate::model::storage::{ObjectKey, ObjectValue, StorageCursor, StoreHistory};
31use crate::schema::declaration::{Field, Kind};
32use crate::schema::{Cardinality, Described};
33use crate::{MemorySize, Message, Result};
34
35#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(deny_unknown_fields)]
45pub struct ObjectEntry {
46 pub position: StorageCursor,
47 pub version: ObjectVersionToken,
48 pub value: ObjectValue,
49}
50
51#[derive(Clone, Debug)]
52pub struct ObjectRevision<T> {
53 pub position: StorageCursor,
54 pub version: ObjectVersionToken,
55 pub value: T,
56}
57
58#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(deny_unknown_fields)]
60pub struct ObjectPoint {
61 pub schema: Identifier,
62 pub item: ObjectKey,
63 pub version: ObjectVersion,
64}
65
66#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
67#[serde(deny_unknown_fields)]
68pub struct ObjectVersionToken {
69 pub(crate) history: StoreHistory,
70 pub(crate) revision: NonZeroU64,
71}
72
73#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
74pub struct ObjectReceipt {
75 pub position: StorageCursor,
76 pub version: ObjectVersionToken,
77}
78
79#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
82pub enum ObjectVersion {
83 Latest,
84 Exact(ObjectVersionToken),
85}
86
87impl MemorySize for ObjectPoint {
92 fn memory_size(&self) -> usize {
93 std::mem::size_of::<Self>()
94 .saturating_add(self.schema.memory_size().saturating_sub(std::mem::size_of::<Identifier>()))
95 .saturating_add(self.item.memory_size().saturating_sub(std::mem::size_of::<ObjectKey>()))
96 .saturating_add(match &self.version {
97 ObjectVersion::Latest => 0,
98 ObjectVersion::Exact(token) => token.memory_size().saturating_sub(std::mem::size_of::<ObjectVersionToken>()),
99 })
100 }
101}
102
103impl MemorySize for ObjectEntry {
104 fn memory_size(&self) -> usize {
105 std::mem::size_of::<Self>()
106 .saturating_add(self.position.memory_size().saturating_sub(std::mem::size_of::<StorageCursor>()))
107 .saturating_add(self.version.memory_size().saturating_sub(std::mem::size_of::<ObjectVersionToken>()))
108 .saturating_add(self.value.memory_size().saturating_sub(std::mem::size_of::<ObjectValue>()))
109 }
110}
111
112impl<T: MemorySize> MemorySize for ObjectRevision<T> {
113 fn memory_size(&self) -> usize {
114 std::mem::size_of::<Self>()
115 .saturating_add(self.position.memory_size().saturating_sub(std::mem::size_of::<StorageCursor>()))
116 .saturating_add(self.version.memory_size().saturating_sub(std::mem::size_of::<ObjectVersionToken>()))
117 .saturating_add(self.value.memory_size().saturating_sub(std::mem::size_of::<T>()))
118 }
119}
120
121impl MemorySize for ObjectReceipt {
122 fn memory_size(&self) -> usize {
123 std::mem::size_of::<Self>() + self.position.memory_size() - std::mem::size_of::<StorageCursor>() + self.version.memory_size()
124 - std::mem::size_of::<ObjectVersionToken>()
125 }
126}
127
128impl MemorySize for ObjectVersionToken {
129 fn memory_size(&self) -> usize {
130 std::mem::size_of::<Self>().saturating_add(self.history.memory_size().saturating_sub(std::mem::size_of::<StoreHistory>()))
131 }
132}
133
134impl ObjectVersionToken {
135 pub fn history(&self) -> &StoreHistory {
136 &self.history
137 }
138
139 pub fn revision(&self) -> NonZeroU64 {
140 self.revision
141 }
142
143 pub fn encode_bounded(&self, max_bytes: NonZeroUsize) -> Result<Vec<u8>> {
144 if self.encoded_len() > max_bytes.get() {
145 return Err(invalid("object version encoding exceeds allowance"));
146 }
147 Ok(self.encode_to_vec())
148 }
149
150 pub fn decode_bounded(bytes: &[u8], max_bytes: NonZeroUsize) -> Result<Self> {
151 let required = Self::decoding_memory(bytes).map_err(|_| invalid("invalid object version encoding"))?;
152 if required > max_bytes.get() {
153 return Err(invalid("object version decoding exceeds allowance"));
154 }
155 let token = Self::decode(bytes).map_err(|_| invalid("invalid object version encoding"))?;
156 if token.memory_size() > max_bytes.get() {
157 return Err(invalid("object version decoding exceeds allowance"));
158 }
159 Ok(token)
160 }
161
162 pub fn new(position: StorageCursor) -> Self {
163 Self { history: position.history, revision: NonZeroU64::new(position.sequence).expect("admission positions are nonzero") }
164 }
165
166 pub fn check_position(&self, position: &StorageCursor) -> Result<()> {
167 self.history.check(&position.history)?;
168 if self.revision.get() != position.sequence {
169 return Err(invalid("object version does not match its admission identity"));
170 }
171 Ok(())
172 }
173}
174
175crate::postcard_product!(ObjectVersionToken { history: StoreHistory, revision: NonZeroU64 });
176
177impl Described for ObjectVersionToken {
178 const NAME: &'static str = concat!(module_path!(), "::", stringify!(ObjectVersionToken));
179 const FIELDS: &'static [Field] = &[
180 Field { name: Cow::Borrowed("store"), tag: 1, kind: Kind::String, cardinality: Cardinality::Required },
181 Field { name: Cow::Borrowed("epoch"), tag: 2, kind: Kind::String, cardinality: Cardinality::Required },
182 Field { name: Cow::Borrowed("revision"), tag: 3, kind: Kind::U64, cardinality: Cardinality::Required },
183 ];
184
185 const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
186 { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
187 >(Self::NAME, Self::FIELDS);
188}
189
190