Skip to main content

harmos_domain/message/
mod.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12pub(crate) mod allocation;
13pub mod postcard;
14
15/* === Re-Exports === */
16
17// Codec Internals For This Crate; Generated Code Reaches Them Through `__private`.
18pub(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
21/* === Imports === */
22
23// Standard Library Imports
24use std::borrow::Cow;
25use std::collections::BTreeMap;
26// Third Party Imports
27
28// Local Imports
29
30/* === Constants === */
31
32/* === Macros === */
33
34macro_rules! inline_memory {
35    ($($ty:ty),* $(,)?) => {$ (
36        impl MemorySize for $ty {
37            fn memory_size(&self) -> usize {
38                std::mem::size_of::<Self>()
39            }
40        }
41    )*};
42}
43
44inline_memory!((), bool, u8, u32, u64, i32, i64, f32, f64);
45
46#[macro_export]
47macro_rules! postcard_product {
48    ($ty:ty { $($field:ident: $field_ty:ty),* $(,)? } $(, validate = $validate:expr)?) => {
49        #[allow(unused_variables)]
50        impl $crate::__private::PostcardValue for $ty {
51            fn write(&self, bytes: &mut ::std::vec::Vec<u8>) {
52                $(<$field_ty as $crate::__private::PostcardValue>::write(&self.$field, bytes);)*
53            }
54            fn size(&self) -> usize {
55                0usize$(.saturating_add(<$field_ty as $crate::__private::PostcardValue>::size(&self.$field)))*
56            }
57            fn memory(input: &mut $crate::__private::PostcardReader<'_>) -> ::std::result::Result<usize, $crate::MessageError> {
58                input.nested(|input| {
59                    let memory = std::mem::size_of::<Self>();
60                    $(let memory = $crate::__private::decoding_add(memory,
61                        <$field_ty as $crate::__private::PostcardValue>::memory(input)?.saturating_sub(std::mem::size_of::<$field_ty>()))?;)*
62                    Ok(memory)
63                })
64            }
65            fn read(input: &mut $crate::__private::PostcardReader<'_>) -> ::std::result::Result<Self, $crate::MessageError> {
66                input.nested(|input| {
67                    let value = Self { $($field: <$field_ty as $crate::__private::PostcardValue>::read(input)?),* };
68                    $(($validate)(&value)?;)?
69                    Ok(value)
70                })
71            }
72        }
73    };
74}
75pub(crate) use postcard_product;
76
77/* === Type Aliases === */
78
79/* === Structs === */
80
81#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
82#[error("invalid message: {0}")]
83pub struct MessageError(Cow<'static, str>);
84
85/* === Enums === */
86
87/* === Traits === */
88
89pub trait Message: Sized + Send + Sync {
90    fn encode_to_vec(&self) -> Vec<u8>;
91    fn encode_into(&self, bytes: &mut Vec<u8>) {
92        bytes.extend_from_slice(&self.encode_to_vec());
93    }
94    fn encoded_len(&self) -> usize;
95    fn decode(bytes: &[u8]) -> Result<Self, MessageError>;
96    fn decoding_memory(_bytes: &[u8]) -> Result<usize, MessageError> {
97        Err(MessageError::borrowed("decoding memory bound is unsupported"))
98    }
99}
100
101pub trait MemorySize: Sized {
102    fn memory_size(&self) -> usize;
103}
104
105// A Value That Crosses A Process Boundary: Every Operation Request, Response
106// And Stream Item. Transport Codecs Derive From The Postcard Value And Its Shape.
107pub trait Portable: Message + MemorySize + crate::schema::Described + Send + Sync + 'static {}
108
109pub trait Storable: Message + MemorySize {
110    fn encoded_size(&self) -> usize {
111        self.encoded_len()
112    }
113}
114
115/* === Implementations === */
116
117impl<T> Portable for T where T: Message + MemorySize + crate::schema::Described + Send + Sync + 'static {}
118
119impl<T: PostcardValue> Message for T {
120    fn encode_to_vec(&self) -> Vec<u8> {
121        let mut bytes = Vec::with_capacity(self.size());
122        self.write(&mut bytes);
123        bytes
124    }
125    fn encode_into(&self, bytes: &mut Vec<u8>) {
126        self.write(bytes);
127    }
128    fn encoded_len(&self) -> usize {
129        self.size()
130    }
131    fn decoding_memory(bytes: &[u8]) -> Result<usize, MessageError> {
132        let mut input = PostcardReader::new(bytes);
133        let memory = Self::memory(&mut input)?;
134        input.finish()?;
135        Ok(memory)
136    }
137    fn decode(bytes: &[u8]) -> Result<Self, MessageError> {
138        <Self as Message>::decoding_memory(bytes)?;
139        let mut input = PostcardReader::new(bytes);
140        let value = Self::read(&mut input)?;
141        input.finish()?;
142        Ok(value)
143    }
144}
145
146impl<T: Message + MemorySize> Storable for T {}
147
148impl MemorySize for String {
149    fn memory_size(&self) -> usize {
150        std::mem::size_of::<Self>().saturating_add(self.capacity())
151    }
152}
153
154impl<T: MemorySize> MemorySize for Vec<T> {
155    fn memory_size(&self) -> usize {
156        let mut bytes = std::mem::size_of::<Self>().saturating_add(self.capacity().saturating_mul(std::mem::size_of::<T>()));
157
158        for value in self {
159            let owned = value.memory_size();
160            if owned == usize::MAX {
161                return usize::MAX;
162            }
163            bytes = bytes.saturating_add(owned.saturating_sub(std::mem::size_of::<T>()));
164        }
165        bytes
166    }
167}
168
169impl<T: MemorySize> MemorySize for Option<T> {
170    fn memory_size(&self) -> usize {
171        let Some(value) = self else {
172            return std::mem::size_of::<Self>();
173        };
174        let owned = value.memory_size();
175        if owned == usize::MAX {
176            return usize::MAX;
177        }
178
179        std::mem::size_of::<Self>().saturating_add(owned.saturating_sub(std::mem::size_of::<T>()))
180    }
181}
182
183// The Heap Pointee Owns Its Full Resident Size Beside The Inline Pointer
184impl<T: MemorySize> MemorySize for Box<T> {
185    fn memory_size(&self) -> usize {
186        let owned = (**self).memory_size();
187        if owned == usize::MAX {
188            return usize::MAX;
189        }
190
191        std::mem::size_of::<Self>().saturating_add(owned)
192    }
193}
194
195impl<K: MemorySize, V: MemorySize> MemorySize for BTreeMap<K, V> {
196    fn memory_size(&self) -> usize {
197        let mut bytes = btree_map_memory::<K, V>(self.len());
198        for (key, value) in self {
199            let key_bytes = key.memory_size();
200            let value_bytes = value.memory_size();
201            if key_bytes == usize::MAX || value_bytes == usize::MAX {
202                return usize::MAX;
203            }
204            bytes = bytes
205                .saturating_add(key_bytes.saturating_sub(std::mem::size_of::<K>()))
206                .saturating_add(value_bytes.saturating_sub(std::mem::size_of::<V>()));
207        }
208        bytes
209    }
210}
211
212impl MessageError {
213    pub fn new(reason: impl Into<String>) -> Self {
214        Self(Cow::Owned(reason.into()))
215    }
216
217    pub const fn borrowed(reason: &'static str) -> Self {
218        Self(Cow::Borrowed(reason))
219    }
220}
221
222/* === Public Functions === */
223
224pub fn btree_map_memory<K, V>(entries: usize) -> usize {
225    let alignment = std::mem::align_of::<K>().max(std::mem::align_of::<V>()).max(std::mem::align_of::<usize>());
226    let node = std::mem::size_of::<K>()
227        .saturating_add(std::mem::size_of::<V>())
228        .saturating_mul(11)
229        .saturating_add(13usize.saturating_mul(std::mem::size_of::<usize>()))
230        .saturating_add(2 * std::mem::size_of::<u16>())
231        .saturating_add(5usize.saturating_mul(alignment));
232    std::mem::size_of::<BTreeMap<K, V>>().saturating_add(entries.saturating_add(1).saturating_mul(node))
233}
234
235/* === Private Functions === */
236
237/* === Tests === */
238
239#[cfg(test)]
240mod tests {
241    use super::MemorySize;
242
243    #[test]
244    fn wrappers_saturate() {
245        struct Overflow;
246        impl MemorySize for Overflow {
247            fn memory_size(&self) -> usize {
248                usize::MAX
249            }
250        }
251
252        assert_eq!(Some(Overflow).memory_size(), usize::MAX);
253        assert_eq!(vec![Overflow].memory_size(), usize::MAX);
254        assert_eq!(Box::new(Overflow).memory_size(), usize::MAX);
255        assert_eq!(None::<Overflow>.memory_size(), std::mem::size_of::<Option<Overflow>>());
256    }
257}