aldrin_core/message/
connect_reply2.rs

1use super::message_ops::Sealed;
2use super::{Message, MessageKind, MessageOps};
3use crate::error::{DeserializeError, SerializeError};
4use crate::message_deserializer::{MessageDeserializeError, MessageWithValueDeserializer};
5use crate::message_serializer::{MessageSerializeError, MessageSerializer};
6use crate::serialized_value::{SerializedValue, SerializedValueSlice};
7use crate::value_deserializer::{Deserialize, Deserializer};
8use crate::value_serializer::{AsSerializeArg, Serialize, Serializer};
9use bytes::BytesMut;
10use num_enum::{IntoPrimitive, TryFromPrimitive};
11
12#[derive(Debug, Clone, PartialEq, Eq, Default)]
13#[cfg_attr(feature = "fuzzing", derive(arbitrary::Arbitrary))]
14pub struct ConnectReplyData {
15    pub user: Option<SerializedValue>,
16}
17
18impl ConnectReplyData {
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    pub fn serialize_user<T: Serialize + ?Sized>(
24        &mut self,
25        user: &T,
26    ) -> Result<&mut Self, SerializeError> {
27        self.user = SerializedValue::serialize(user).map(Some)?;
28        Ok(self)
29    }
30
31    pub fn deserialize_user<T: Deserialize>(&self) -> Option<Result<T, DeserializeError>> {
32        self.user.as_deref().map(SerializedValueSlice::deserialize)
33    }
34}
35
36#[derive(IntoPrimitive, TryFromPrimitive)]
37#[repr(u32)]
38enum ConnectReplyDataField {
39    User = 0,
40}
41
42impl Serialize for ConnectReplyData {
43    fn serialize(&self, serializer: Serializer) -> Result<(), SerializeError> {
44        let mut serializer = serializer.serialize_struct(1)?;
45        serializer.serialize_field(ConnectReplyDataField::User, &self.user)?;
46        serializer.finish()
47    }
48}
49
50impl Deserialize for ConnectReplyData {
51    fn deserialize(deserializer: Deserializer) -> Result<Self, DeserializeError> {
52        let mut deserializer = deserializer.deserialize_struct()?;
53
54        let mut user = None;
55
56        while deserializer.has_more_fields() {
57            let deserializer = deserializer.deserialize_field()?;
58
59            let Ok(field) = deserializer.try_id() else {
60                deserializer.skip()?;
61                continue;
62            };
63
64            match field {
65                ConnectReplyDataField::User => user = deserializer.deserialize()?,
66            }
67        }
68
69        deserializer.finish(Self { user })
70    }
71}
72
73impl AsSerializeArg for ConnectReplyData {
74    type SerializeArg<'a> = &'a Self;
75
76    fn as_serialize_arg<'a>(&'a self) -> Self::SerializeArg<'a>
77    where
78        Self: 'a,
79    {
80        self
81    }
82}
83
84#[derive(Debug, Copy, Clone, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
85#[repr(u8)]
86enum ConnectReplyKind {
87    Ok = 0,
88    Rejected = 1,
89    IncompatibleVersion = 2,
90}
91
92#[derive(Debug, Copy, Clone, PartialEq, Eq)]
93#[cfg_attr(feature = "fuzzing", derive(arbitrary::Arbitrary))]
94pub enum ConnectResult {
95    Ok(u32),
96    Rejected,
97    IncompatibleVersion,
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
101#[cfg_attr(feature = "fuzzing", derive(arbitrary::Arbitrary))]
102pub struct ConnectReply2 {
103    pub result: ConnectResult,
104    pub value: SerializedValue,
105}
106
107impl ConnectReply2 {
108    pub fn ok_with_serialize_data(
109        version: u32,
110        data: &ConnectReplyData,
111    ) -> Result<Self, SerializeError> {
112        let value = SerializedValue::serialize(data)?;
113
114        Ok(Self {
115            result: ConnectResult::Ok(version),
116            value,
117        })
118    }
119
120    pub fn rejected_with_serialize_data(data: &ConnectReplyData) -> Result<Self, SerializeError> {
121        let value = SerializedValue::serialize(data)?;
122
123        Ok(Self {
124            result: ConnectResult::Rejected,
125            value,
126        })
127    }
128
129    pub fn incompatible_version_with_serialize_data(
130        data: &ConnectReplyData,
131    ) -> Result<Self, SerializeError> {
132        let value = SerializedValue::serialize(data)?;
133
134        Ok(Self {
135            result: ConnectResult::IncompatibleVersion,
136            value,
137        })
138    }
139
140    pub fn deserialize_connect_data(&self) -> Result<ConnectReplyData, DeserializeError> {
141        self.value.deserialize()
142    }
143}
144
145impl MessageOps for ConnectReply2 {
146    fn kind(&self) -> MessageKind {
147        MessageKind::ConnectReply2
148    }
149
150    fn serialize_message(self) -> Result<BytesMut, MessageSerializeError> {
151        let mut serializer = MessageSerializer::with_value(self.value, MessageKind::ConnectReply2)?;
152
153        match self.result {
154            ConnectResult::Ok(version) => {
155                serializer.put_discriminant_u8(ConnectReplyKind::Ok);
156                serializer.put_varint_u32_le(version);
157                serializer.finish()
158            }
159
160            ConnectResult::Rejected => {
161                serializer.put_discriminant_u8(ConnectReplyKind::Rejected);
162                serializer.finish()
163            }
164
165            ConnectResult::IncompatibleVersion => {
166                serializer.put_discriminant_u8(ConnectReplyKind::IncompatibleVersion);
167                serializer.finish()
168            }
169        }
170    }
171
172    fn deserialize_message(buf: BytesMut) -> Result<Self, MessageDeserializeError> {
173        let mut deserializer = MessageWithValueDeserializer::new(buf, MessageKind::ConnectReply2)?;
174
175        match deserializer.try_get_discriminant_u8()? {
176            ConnectReplyKind::Ok => {
177                let version = deserializer.try_get_varint_u32_le()?;
178                let value = deserializer.finish()?;
179
180                Ok(Self {
181                    result: ConnectResult::Ok(version),
182                    value,
183                })
184            }
185
186            ConnectReplyKind::Rejected => {
187                let value = deserializer.finish()?;
188
189                Ok(Self {
190                    result: ConnectResult::Rejected,
191                    value,
192                })
193            }
194
195            ConnectReplyKind::IncompatibleVersion => {
196                let value = deserializer.finish()?;
197
198                Ok(Self {
199                    result: ConnectResult::IncompatibleVersion,
200                    value,
201                })
202            }
203        }
204    }
205
206    fn value(&self) -> Option<&SerializedValueSlice> {
207        Some(&self.value)
208    }
209}
210
211impl Sealed for ConnectReply2 {}
212
213impl From<ConnectReply2> for Message {
214    fn from(msg: ConnectReply2) -> Self {
215        Self::ConnectReply2(msg)
216    }
217}
218
219#[cfg(test)]
220mod test {
221    use super::super::test::{assert_deserialize_eq_with_value, assert_serialize_eq};
222    use super::super::Message;
223    use super::{ConnectReply2, ConnectReplyData};
224
225    #[test]
226    fn ok() {
227        let serialized = [15, 0, 0, 0, 47, 4, 0, 0, 0, 39, 1, 0, 0, 0, 1];
228        let value = ConnectReplyData::new();
229
230        let msg = ConnectReply2::ok_with_serialize_data(1, &value).unwrap();
231        assert_serialize_eq(&msg, serialized);
232        assert_deserialize_eq_with_value(&msg, serialized, &value);
233
234        let msg = Message::ConnectReply2(msg);
235        assert_serialize_eq(&msg, serialized);
236        assert_deserialize_eq_with_value(&msg, serialized, &value);
237    }
238
239    #[test]
240    fn rejected() {
241        let serialized = [14, 0, 0, 0, 47, 4, 0, 0, 0, 39, 1, 0, 0, 1];
242        let value = ConnectReplyData::new();
243
244        let msg = ConnectReply2::rejected_with_serialize_data(&value).unwrap();
245        assert_serialize_eq(&msg, serialized);
246        assert_deserialize_eq_with_value(&msg, serialized, &value);
247
248        let msg = Message::ConnectReply2(msg);
249        assert_serialize_eq(&msg, serialized);
250        assert_deserialize_eq_with_value(&msg, serialized, &value);
251    }
252
253    #[test]
254    fn incompatible_version() {
255        let serialized = [14, 0, 0, 0, 47, 4, 0, 0, 0, 39, 1, 0, 0, 2];
256        let value = ConnectReplyData::new();
257
258        let msg = ConnectReply2::incompatible_version_with_serialize_data(&value).unwrap();
259        assert_serialize_eq(&msg, serialized);
260        assert_deserialize_eq_with_value(&msg, serialized, &value);
261
262        let msg = Message::ConnectReply2(msg);
263        assert_serialize_eq(&msg, serialized);
264        assert_deserialize_eq_with_value(&msg, serialized, &value);
265    }
266}