manul/protocol/
message.rs1use alloc::string::{String, ToString};
2
3use digest::Digest;
4use serde::{Deserialize, Serialize};
5
6use super::{
7 errors::{DirectMessageError, EchoBroadcastError, LocalError, MessageValidationError, NormalBroadcastError},
8 BoxedFormat,
9};
10
11mod private {
12 use alloc::boxed::Box;
13 use serde::{Deserialize, Serialize};
14 use serde_encoded_bytes::{Base64, SliceLike};
15
16 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17 pub struct MessagePayload(#[serde(with = "SliceLike::<Base64>")] pub Box<[u8]>);
18
19 impl AsRef<[u8]> for MessagePayload {
20 fn as_ref(&self) -> &[u8] {
21 &self.0
22 }
23 }
24
25 pub trait ProtocolMessageWrapper: Sized {
26 fn new_inner(maybe_message: Option<MessagePayload>) -> Self;
27 fn maybe_message(&self) -> &Option<MessagePayload>;
28 }
29}
30
31use private::{MessagePayload, ProtocolMessageWrapper};
32
33pub trait ProtocolMessagePart: ProtocolMessageWrapper {
38 type Error: From<String>;
44
45 fn none() -> Self {
49 Self::new_inner(None)
50 }
51
52 fn new<T>(format: &BoxedFormat, message: T) -> Result<Self, LocalError>
54 where
55 T: 'static + Serialize,
56 {
57 let payload = MessagePayload(format.serialize(message)?);
58 Ok(Self::new_inner(Some(payload)))
59 }
60
61 fn is_none(&self) -> bool {
63 self.maybe_message().is_none()
64 }
65
66 fn assert_is_none(&self) -> Result<(), Self::Error> {
68 if self.is_none() {
69 Ok(())
70 } else {
71 Err("The payload was expected to be `None`, but contains a message"
72 .to_string()
73 .into())
74 }
75 }
76
77 fn verify_is_not<'de, T: Deserialize<'de>>(&'de self, format: &BoxedFormat) -> Result<(), MessageValidationError> {
83 if self.deserialize::<T>(format).is_err() {
84 Ok(())
85 } else {
86 Err(MessageValidationError::InvalidEvidence(
87 "Message deserialized successfully, as expected by the protocol".into(),
88 ))
89 }
90 }
91
92 fn verify_is_some(&self) -> Result<(), MessageValidationError> {
98 if self.maybe_message().is_some() {
99 Ok(())
100 } else {
101 Err(MessageValidationError::InvalidEvidence(
102 "The payload is `None`, as expected by the protocol".into(),
103 ))
104 }
105 }
106
107 fn deserialize<'de, T>(&'de self, format: &BoxedFormat) -> Result<T, Self::Error>
109 where
110 T: Deserialize<'de>,
111 {
112 let payload = self
113 .maybe_message()
114 .as_ref()
115 .ok_or_else(|| "The payload is `None` and cannot be deserialized".into())?;
116 format.deserialize(&payload.0).map_err(|err| err.to_string().into())
117 }
118}
119
120#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
121pub(crate) enum PartKind {
122 EchoBroadcast,
123 NormalBroadcast,
124 DirectMessage,
125}
126
127pub(crate) trait HasPartKind {
128 const KIND: PartKind;
129}
130
131pub(crate) trait ProtocolMessagePartHashable: ProtocolMessagePart + HasPartKind {
133 fn hash<D: Digest>(&self) -> digest::Output<D> {
134 let mut digest = D::new_with_prefix(b"ProtocolMessagePart");
135 match Self::KIND {
136 PartKind::EchoBroadcast => digest.update([0u8]),
137 PartKind::NormalBroadcast => digest.update([1u8]),
138 PartKind::DirectMessage => digest.update([2u8]),
139 }
140 match self.maybe_message().as_ref() {
141 None => digest.update([0u8]),
142 Some(payload) => {
143 let payload_len =
144 u64::try_from(payload.as_ref().len()).expect("payload length does not exceed 18 exabytes");
145 digest.update([1u8]);
146 digest.update(payload_len.to_be_bytes());
147 digest.update(payload);
148 }
149 };
150 digest.finalize()
151 }
152}
153
154impl<T: ProtocolMessagePart + HasPartKind> ProtocolMessagePartHashable for T {}
155
156#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
158pub struct DirectMessage(Option<MessagePayload>);
159
160impl ProtocolMessageWrapper for DirectMessage {
161 fn new_inner(maybe_message: Option<MessagePayload>) -> Self {
162 Self(maybe_message)
163 }
164
165 fn maybe_message(&self) -> &Option<MessagePayload> {
166 &self.0
167 }
168}
169
170impl HasPartKind for DirectMessage {
171 const KIND: PartKind = PartKind::DirectMessage;
172}
173
174impl ProtocolMessagePart for DirectMessage {
175 type Error = DirectMessageError;
176}
177
178#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
180pub struct EchoBroadcast(Option<MessagePayload>);
181
182impl ProtocolMessageWrapper for EchoBroadcast {
183 fn new_inner(maybe_message: Option<MessagePayload>) -> Self {
184 Self(maybe_message)
185 }
186
187 fn maybe_message(&self) -> &Option<MessagePayload> {
188 &self.0
189 }
190}
191
192impl HasPartKind for EchoBroadcast {
193 const KIND: PartKind = PartKind::EchoBroadcast;
194}
195
196impl ProtocolMessagePart for EchoBroadcast {
197 type Error = EchoBroadcastError;
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
202pub struct NormalBroadcast(Option<MessagePayload>);
203
204impl ProtocolMessageWrapper for NormalBroadcast {
205 fn new_inner(maybe_message: Option<MessagePayload>) -> Self {
206 Self(maybe_message)
207 }
208
209 fn maybe_message(&self) -> &Option<MessagePayload> {
210 &self.0
211 }
212}
213
214impl HasPartKind for NormalBroadcast {
215 const KIND: PartKind = PartKind::NormalBroadcast;
216}
217
218impl ProtocolMessagePart for NormalBroadcast {
219 type Error = NormalBroadcastError;
220}
221
222#[derive(Debug, Clone, PartialEq, Eq)]
224pub struct ProtocolMessage {
225 pub echo_broadcast: EchoBroadcast,
227 pub normal_broadcast: NormalBroadcast,
229 pub direct_message: DirectMessage,
231}