Skip to main content

aven_protocol/wire/tail/
batch.rs

1//! Compact framing belongs only to the batch transport; record bytes are unchanged.
2use super::*;
3
4pub mod fixed {
5    use serde::{Deserializer, Serializer, de::Error};
6    pub fn serialize<S: Serializer>(
7        value: &[u8; 32],
8        serializer: S,
9    ) -> std::result::Result<S::Ok, S::Error> {
10        crate::base64_bytes::serialize(value, serializer)
11    }
12    pub fn deserialize<'de, D: Deserializer<'de>>(
13        deserializer: D,
14    ) -> std::result::Result<[u8; 32], D::Error> {
15        crate::base64_bytes::bounded::<D, 32>(deserializer)?
16            .try_into()
17            .map_err(|_| D::Error::custom("expected 32 bytes"))
18    }
19}
20
21#[derive(Serialize, Deserialize)]
22#[serde(remote = "Context", deny_unknown_fields)]
23struct CompactContext {
24    #[serde(with = "fixed")]
25    vault: [u8; 32],
26    #[serde(with = "fixed")]
27    genesis: [u8; 32],
28    #[serde(with = "fixed")]
29    device: [u8; 32],
30    #[serde(with = "fixed")]
31    head: [u8; 32],
32    #[serde(with = "fixed")]
33    stream: [u8; 32],
34    #[serde(with = "fixed")]
35    descriptor: [u8; 32],
36}
37
38#[derive(Serialize, Deserialize)]
39#[serde(deny_unknown_fields)]
40pub struct Envelope<T> {
41    #[serde(with = "CompactContext")]
42    pub context: Context,
43    #[serde(with = "fixed")]
44    pub correlation: [u8; 32],
45    pub operation: T,
46}
47
48#[derive(Clone, Serialize, Deserialize)]
49#[serde(deny_unknown_fields)]
50pub struct CompactMapping {
51    pub operation_id: String,
52    pub sequence: i64,
53    #[serde(with = "fixed")]
54    pub commitment: [u8; 32],
55}
56impl From<Mapping> for CompactMapping {
57    fn from(value: Mapping) -> Self {
58        Self {
59            operation_id: value.operation_id,
60            sequence: value.sequence,
61            commitment: value.commitment,
62        }
63    }
64}
65impl From<CompactMapping> for Mapping {
66    fn from(value: CompactMapping) -> Self {
67        Self {
68            operation_id: value.operation_id,
69            sequence: value.sequence,
70            commitment: value.commitment,
71        }
72    }
73}
74
75const _: () = assert!(BATCH_APPEND_LIMIT <= super::super::images::HTTP_LIMIT);
76
77/// Bounds collection allocation even when an input contains many tiny elements.
78pub fn bounded_items<'de, D, T>(deserializer: D) -> std::result::Result<Vec<T>, D::Error>
79where
80    D: serde::Deserializer<'de>,
81    T: serde::Deserialize<'de>,
82{
83    struct Items<T>(std::marker::PhantomData<T>);
84    impl<'de, T: serde::Deserialize<'de>> serde::de::Visitor<'de> for Items<T> {
85        type Value = Vec<T>;
86        fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
87            f.write_str("at most 128 batch items")
88        }
89        fn visit_seq<A: serde::de::SeqAccess<'de>>(
90            self,
91            mut seq: A,
92        ) -> std::result::Result<Self::Value, A::Error> {
93            use serde::de::Error;
94            let mut items = Vec::new();
95            while let Some(item) = seq.next_element()? {
96                if items.len() == BATCH_COUNT {
97                    return Err(A::Error::custom("batch count limit"));
98                }
99                items.push(item);
100            }
101            Ok(items)
102        }
103    }
104    deserializer.deserialize_seq(Items(std::marker::PhantomData))
105}