distant_protocol/
msg.rs

1use derive_more::From;
2use serde::{Deserialize, Serialize};
3
4/// Represents a wrapper around a message, supporting single and batch payloads.
5#[derive(Clone, Debug, From, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(untagged)]
7pub enum Msg<T> {
8    Single(T),
9    Batch(Vec<T>),
10}
11
12impl<T> Msg<T> {
13    /// Creates a new msg with a singular payload.
14    #[inline]
15    pub fn single(payload: T) -> Self {
16        Self::Single(payload)
17    }
18
19    /// Creates a new msg with a batch payload.
20    pub fn batch<I>(payloads: I) -> Self
21    where
22        I: IntoIterator<Item = T>,
23    {
24        Self::Batch(payloads.into_iter().collect())
25    }
26
27    /// Returns true if msg has a single payload.
28    #[inline]
29    pub fn is_single(&self) -> bool {
30        matches!(self, Self::Single(_))
31    }
32
33    /// Returns reference to single value if msg is single variant.
34    #[inline]
35    pub fn as_single(&self) -> Option<&T> {
36        match self {
37            Self::Single(x) => Some(x),
38            _ => None,
39        }
40    }
41
42    /// Returns mutable reference to single value if msg is single variant.
43    #[inline]
44    pub fn as_mut_single(&mut self) -> Option<&T> {
45        match self {
46            Self::Single(x) => Some(x),
47            _ => None,
48        }
49    }
50
51    /// Returns the single value if msg is single variant.
52    #[inline]
53    pub fn into_single(self) -> Option<T> {
54        match self {
55            Self::Single(x) => Some(x),
56            _ => None,
57        }
58    }
59
60    /// Returns true if msg has a batch of payloads.
61    #[inline]
62    pub fn is_batch(&self) -> bool {
63        matches!(self, Self::Batch(_))
64    }
65
66    /// Returns reference to batch value if msg is batch variant.
67    #[inline]
68    pub fn as_batch(&self) -> Option<&[T]> {
69        match self {
70            Self::Batch(x) => Some(x),
71            _ => None,
72        }
73    }
74
75    /// Returns mutable reference to batch value if msg is batch variant.
76    #[inline]
77    pub fn as_mut_batch(&mut self) -> Option<&mut [T]> {
78        match self {
79            Self::Batch(x) => Some(x),
80            _ => None,
81        }
82    }
83
84    /// Returns the batch value if msg is batch variant.
85    #[inline]
86    pub fn into_batch(self) -> Option<Vec<T>> {
87        match self {
88            Self::Batch(x) => Some(x),
89            _ => None,
90        }
91    }
92
93    /// Convert into a collection of payload data.
94    #[inline]
95    pub fn into_vec(self) -> Vec<T> {
96        match self {
97            Self::Single(x) => vec![x],
98            Self::Batch(x) => x,
99        }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    mod single {
108        use super::*;
109
110        #[test]
111        fn should_be_able_to_serialize_to_json() {
112            let msg = Msg::single("hello world");
113
114            let value = serde_json::to_value(msg).unwrap();
115            assert_eq!(value, serde_json::json!("hello world"));
116        }
117
118        #[test]
119        fn should_be_able_to_deserialize_from_json() {
120            let value = serde_json::json!("hello world");
121
122            let msg: Msg<String> = serde_json::from_value(value).unwrap();
123            assert_eq!(msg, Msg::single(String::from("hello world")));
124        }
125
126        #[test]
127        fn should_be_able_to_serialize_to_msgpack() {
128            let msg = Msg::single("hello world");
129
130            // NOTE: We don't actually check the output here because it's an implementation detail
131            // and could change as we change how serialization is done. This is merely to verify
132            // that we can serialize since there are times when serde fails to serialize at
133            // runtime.
134            let _ = rmp_serde::encode::to_vec_named(&msg).unwrap();
135        }
136
137        #[test]
138        fn should_be_able_to_deserialize_from_msgpack() {
139            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
140            // verify that we are not corrupting or causing issues when serializing on a
141            // client/server and then trying to deserialize on the other side. This has happened
142            // enough times with minor changes that we need tests to verify.
143            let buf = rmp_serde::encode::to_vec_named(&Msg::single("hello world")).unwrap();
144
145            let msg: Msg<String> = rmp_serde::decode::from_slice(&buf).unwrap();
146            assert_eq!(msg, Msg::single(String::from("hello world")));
147        }
148    }
149
150    mod batch {
151        use super::*;
152
153        #[test]
154        fn should_be_able_to_serialize_to_json() {
155            let msg = Msg::batch(["hello world"]);
156
157            let value = serde_json::to_value(msg).unwrap();
158            assert_eq!(value, serde_json::json!(["hello world"]));
159        }
160
161        #[test]
162        fn should_be_able_to_deserialize_from_json() {
163            let value = serde_json::json!(["hello world"]);
164
165            let msg: Msg<String> = serde_json::from_value(value).unwrap();
166            assert_eq!(msg, Msg::batch([String::from("hello world")]));
167        }
168
169        #[test]
170        fn should_be_able_to_serialize_to_msgpack() {
171            let msg = Msg::batch(["hello world"]);
172
173            // NOTE: We don't actually check the output here because it's an implementation detail
174            // and could change as we change how serialization is done. This is merely to verify
175            // that we can serialize since there are times when serde fails to serialize at
176            // runtime.
177            let _ = rmp_serde::encode::to_vec_named(&msg).unwrap();
178        }
179
180        #[test]
181        fn should_be_able_to_deserialize_from_msgpack() {
182            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
183            // verify that we are not corrupting or causing issues when serializing on a
184            // client/server and then trying to deserialize on the other side. This has happened
185            // enough times with minor changes that we need tests to verify.
186            let buf = rmp_serde::encode::to_vec_named(&Msg::batch(["hello world"])).unwrap();
187
188            let msg: Msg<String> = rmp_serde::decode::from_slice(&buf).unwrap();
189            assert_eq!(msg, Msg::batch([String::from("hello world")]));
190        }
191    }
192}