harmos_domain/message/
mod.rs1pub(crate) mod allocation;
13pub mod postcard;
14
15pub(crate) use allocation::{add as decoding_add, multiply as decoding_multiply, vector as decoding_vector};
19pub(crate) use postcard::{Reader as PostcardReader, Value as PostcardValue};
20
21use std::borrow::Cow;
25use std::collections::BTreeMap;
26macro_rules! inline_memory {
35 ($($ty:ty),* $(,)?) => {$ (
36 impl MemorySize for $ty {
37 const INLINE_ONLY: bool = true;
38
39 fn memory_size(&self) -> usize {
40 std::mem::size_of::<Self>()
41 }
42 }
43 )*};
44}
45
46inline_memory!((), bool, u8, u32, u64, i32, i64, f32, f64);
47
48#[macro_export]
49macro_rules! postcard_product {
50 ($ty:ty { $($field:ident: $field_ty:ty),* $(,)? } $(, validate = $validate:expr)?) => {
51 #[allow(unused_variables)]
52 impl $crate::__private::PostcardValue for $ty {
53 fn write(&self, bytes: &mut ::std::vec::Vec<u8>) {
54 $(<$field_ty as $crate::__private::PostcardValue>::write(&self.$field, bytes);)*
55 }
56 fn size(&self) -> usize {
57 0usize$(.saturating_add(<$field_ty as $crate::__private::PostcardValue>::size(&self.$field)))*
58 }
59 fn memory(input: &mut $crate::__private::PostcardReader<'_>) -> ::std::result::Result<usize, $crate::MessageError> {
60 input.nested(|input| {
61 let memory = std::mem::size_of::<Self>();
62 $(let memory = $crate::__private::decoding_add(memory,
63 <$field_ty as $crate::__private::PostcardValue>::memory(input)?.saturating_sub(std::mem::size_of::<$field_ty>()))?;)*
64 Ok(memory)
65 })
66 }
67 fn read(input: &mut $crate::__private::PostcardReader<'_>) -> ::std::result::Result<Self, $crate::MessageError> {
68 input.nested(|input| {
69 let value = Self { $($field: <$field_ty as $crate::__private::PostcardValue>::read(input)?),* };
70 $(($validate)(&value)?;)?
71 Ok(value)
72 })
73 }
74 }
75 };
76}
77pub(crate) use postcard_product;
78
79#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
84#[error("invalid message: {0}")]
85pub struct MessageError(Cow<'static, str>);
86
87pub trait Message: Sized + Send + Sync {
92 fn encode_to_vec(&self) -> Vec<u8>;
93 fn encode_into(&self, bytes: &mut Vec<u8>) {
94 bytes.extend_from_slice(&self.encode_to_vec());
95 }
96 fn encoded_len(&self) -> usize;
97 fn decode(bytes: &[u8]) -> Result<Self, MessageError>;
98 fn decoding_memory(_bytes: &[u8]) -> Result<usize, MessageError> {
99 Err(MessageError::borrowed("decoding memory bound is unsupported"))
100 }
101}
102
103pub trait MemorySize: Sized {
104 const INLINE_ONLY: bool = false;
107
108 fn memory_size(&self) -> usize;
109}
110
111pub trait Portable: Message + MemorySize + crate::schema::Described + Send + Sync + 'static {}
114
115pub trait Storable: Message + MemorySize {
116 fn encoded_size(&self) -> usize {
117 self.encoded_len()
118 }
119}
120
121impl<T> Portable for T where T: Message + MemorySize + crate::schema::Described + Send + Sync + 'static {}
124
125impl<T: PostcardValue> Message for T {
126 fn encode_to_vec(&self) -> Vec<u8> {
127 let mut bytes = Vec::with_capacity(self.size());
128 self.write(&mut bytes);
129 bytes
130 }
131 fn encode_into(&self, bytes: &mut Vec<u8>) {
132 self.write(bytes);
133 }
134 fn encoded_len(&self) -> usize {
135 self.size()
136 }
137 fn decoding_memory(bytes: &[u8]) -> Result<usize, MessageError> {
138 let mut input = PostcardReader::new(bytes);
139 let memory = Self::memory(&mut input)?;
140 input.finish()?;
141 Ok(memory)
142 }
143 fn decode(bytes: &[u8]) -> Result<Self, MessageError> {
144 <Self as Message>::decoding_memory(bytes)?;
145 let mut input = PostcardReader::new(bytes);
146 let value = Self::read(&mut input)?;
147 input.finish()?;
148 Ok(value)
149 }
150}
151
152impl<T: Message + MemorySize> Storable for T {}
153
154impl MemorySize for String {
155 fn memory_size(&self) -> usize {
156 std::mem::size_of::<Self>().saturating_add(self.capacity())
157 }
158}
159
160impl<T: MemorySize> MemorySize for Vec<T> {
161 fn memory_size(&self) -> usize {
162 let mut bytes = std::mem::size_of::<Self>().saturating_add(self.capacity().saturating_mul(std::mem::size_of::<T>()));
163 if T::INLINE_ONLY {
164 return bytes;
165 }
166
167 for value in self {
168 let owned = value.memory_size();
169 if owned == usize::MAX {
170 return usize::MAX;
171 }
172 bytes = bytes.saturating_add(owned.saturating_sub(std::mem::size_of::<T>()));
173 }
174 bytes
175 }
176}
177
178impl<T: MemorySize> MemorySize for Option<T> {
179 const INLINE_ONLY: bool = T::INLINE_ONLY;
180
181 fn memory_size(&self) -> usize {
182 let Some(value) = self else {
183 return std::mem::size_of::<Self>();
184 };
185 let owned = value.memory_size();
186 if owned == usize::MAX {
187 return usize::MAX;
188 }
189
190 std::mem::size_of::<Self>().saturating_add(owned.saturating_sub(std::mem::size_of::<T>()))
191 }
192}
193
194impl<T: MemorySize> MemorySize for Box<T> {
196 fn memory_size(&self) -> usize {
197 let owned = (**self).memory_size();
198 if owned == usize::MAX {
199 return usize::MAX;
200 }
201
202 std::mem::size_of::<Self>().saturating_add(owned)
203 }
204}
205
206impl<K: MemorySize, V: MemorySize> MemorySize for BTreeMap<K, V> {
207 fn memory_size(&self) -> usize {
208 let mut bytes = btree_map_memory::<K, V>(self.len());
209 for (key, value) in self {
210 let key_bytes = key.memory_size();
211 let value_bytes = value.memory_size();
212 if key_bytes == usize::MAX || value_bytes == usize::MAX {
213 return usize::MAX;
214 }
215 bytes = bytes
216 .saturating_add(key_bytes.saturating_sub(std::mem::size_of::<K>()))
217 .saturating_add(value_bytes.saturating_sub(std::mem::size_of::<V>()));
218 }
219 bytes
220 }
221}
222
223impl MessageError {
224 pub fn new(reason: impl Into<String>) -> Self {
225 Self(Cow::Owned(reason.into()))
226 }
227
228 pub const fn borrowed(reason: &'static str) -> Self {
229 Self(Cow::Borrowed(reason))
230 }
231}
232
233pub fn btree_map_memory<K, V>(entries: usize) -> usize {
236 let alignment = std::mem::align_of::<K>().max(std::mem::align_of::<V>()).max(std::mem::align_of::<usize>());
237 let node = std::mem::size_of::<K>()
238 .saturating_add(std::mem::size_of::<V>())
239 .saturating_mul(11)
240 .saturating_add(13usize.saturating_mul(std::mem::size_of::<usize>()))
241 .saturating_add(2 * std::mem::size_of::<u16>())
242 .saturating_add(5usize.saturating_mul(alignment));
243 std::mem::size_of::<BTreeMap<K, V>>().saturating_add(entries.saturating_add(1).saturating_mul(node))
244}
245
246#[cfg(test)]
251mod tests {
252 use super::MemorySize;
253
254 #[test]
255 fn vector_allocations() {
256 use std::sync::atomic::{AtomicUsize, Ordering};
257
258 static VISITS: AtomicUsize = AtomicUsize::new(0);
259 struct Inline(u8);
260 impl MemorySize for Inline {
261 const INLINE_ONLY: bool = true;
262
263 fn memory_size(&self) -> usize {
264 VISITS.fetch_add(1, Ordering::Relaxed);
265 std::mem::size_of_val(&self.0)
266 }
267 }
268
269 let mut values = Vec::with_capacity(128);
270 values.push(Some(Inline(7)));
271 let allocation = values.capacity() * std::mem::size_of::<Option<Inline>>();
272 assert_eq!(values.memory_size(), std::mem::size_of_val(&values) + allocation);
273 assert_eq!(VISITS.load(Ordering::Relaxed), 0);
274
275 let mut text = String::with_capacity(256);
276 text.push_str("nested");
277 let text_allocation = text.capacity();
278 let mut nested = Vec::with_capacity(8);
279 nested.push(Some(text));
280 let allocation = nested.capacity() * std::mem::size_of::<Option<String>>();
281 let expected = std::mem::size_of_val(&nested) + allocation + text_allocation;
282 assert_eq!(nested.memory_size(), expected);
283 }
284
285 #[test]
286 fn wrappers_saturate() {
287 struct Overflow;
288 impl MemorySize for Overflow {
289 fn memory_size(&self) -> usize {
290 usize::MAX
291 }
292 }
293
294 assert_eq!(Some(Overflow).memory_size(), usize::MAX);
295 assert_eq!(vec![Overflow].memory_size(), usize::MAX);
296 assert_eq!(Box::new(Overflow).memory_size(), usize::MAX);
297 assert_eq!(None::<Overflow>.memory_size(), std::mem::size_of::<Option<Overflow>>());
298 }
299}