aldrin_core/message/
connect_reply.rs

1use super::message_ops::Sealed;
2use super::{Message, MessageKind, MessageOps};
3use crate::error::SerializeError;
4use crate::message_deserializer::{MessageDeserializeError, MessageWithValueDeserializer};
5use crate::message_serializer::{MessageSerializeError, MessageSerializer};
6use crate::serialized_value::{SerializedValue, SerializedValueSlice};
7use crate::value_serializer::Serialize;
8use bytes::BytesMut;
9use num_enum::{IntoPrimitive, TryFromPrimitive};
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
12#[repr(u8)]
13enum ConnectReplyKind {
14    Ok = 0,
15    IncompatibleVersion = 1,
16    Rejected = 2,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "fuzzing", derive(arbitrary::Arbitrary))]
21pub enum ConnectReply {
22    Ok(SerializedValue),
23    IncompatibleVersion(u32),
24    Rejected(SerializedValue),
25}
26
27impl ConnectReply {
28    pub fn ok_with_serialize_value<T: Serialize + ?Sized>(
29        value: &T,
30    ) -> Result<Self, SerializeError> {
31        let value = SerializedValue::serialize(value)?;
32        Ok(Self::Ok(value))
33    }
34
35    pub fn rejected_with_serialize_value<T: Serialize + ?Sized>(
36        value: &T,
37    ) -> Result<Self, SerializeError> {
38        let value = SerializedValue::serialize(value)?;
39        Ok(Self::Rejected(value))
40    }
41}
42
43impl MessageOps for ConnectReply {
44    fn kind(&self) -> MessageKind {
45        MessageKind::ConnectReply
46    }
47
48    fn serialize_message(self) -> Result<BytesMut, MessageSerializeError> {
49        match self {
50            Self::Ok(value) => {
51                let mut serializer =
52                    MessageSerializer::with_value(value, MessageKind::ConnectReply)?;
53                serializer.put_discriminant_u8(ConnectReplyKind::Ok);
54                serializer.finish()
55            }
56
57            Self::IncompatibleVersion(version) => {
58                let mut serializer = MessageSerializer::with_none_value(MessageKind::ConnectReply);
59                serializer.put_discriminant_u8(ConnectReplyKind::IncompatibleVersion);
60                serializer.put_varint_u32_le(version);
61                serializer.finish()
62            }
63
64            Self::Rejected(value) => {
65                let mut serializer =
66                    MessageSerializer::with_value(value, MessageKind::ConnectReply)?;
67                serializer.put_discriminant_u8(ConnectReplyKind::Rejected);
68                serializer.finish()
69            }
70        }
71    }
72
73    fn deserialize_message(buf: BytesMut) -> Result<Self, MessageDeserializeError> {
74        let mut deserializer = MessageWithValueDeserializer::new(buf, MessageKind::ConnectReply)?;
75
76        match deserializer.try_get_discriminant_u8()? {
77            ConnectReplyKind::Ok => deserializer.finish().map(Self::Ok),
78
79            ConnectReplyKind::IncompatibleVersion => {
80                let version = deserializer.try_get_varint_u32_le()?;
81                deserializer.finish_discard_value()?;
82                Ok(Self::IncompatibleVersion(version))
83            }
84
85            ConnectReplyKind::Rejected => deserializer.finish().map(Self::Rejected),
86        }
87    }
88
89    fn value(&self) -> Option<&SerializedValueSlice> {
90        match self {
91            Self::Ok(value) | Self::Rejected(value) => Some(value),
92            Self::IncompatibleVersion(_) => None,
93        }
94    }
95}
96
97impl Sealed for ConnectReply {}
98
99impl From<ConnectReply> for Message {
100    fn from(msg: ConnectReply) -> Self {
101        Self::ConnectReply(msg)
102    }
103}
104
105#[cfg(test)]
106mod test {
107    use super::super::test::{
108        assert_deserialize_eq, assert_deserialize_eq_with_value, assert_serialize_eq,
109    };
110    use super::super::Message;
111    use super::ConnectReply;
112
113    #[test]
114    fn ok() {
115        let serialized = [12, 0, 0, 0, 1, 2, 0, 0, 0, 3, 4, 0];
116        let value = 4u8;
117
118        let msg = ConnectReply::ok_with_serialize_value(&value).unwrap();
119        assert_serialize_eq(&msg, serialized);
120        assert_deserialize_eq_with_value(&msg, serialized, &value);
121
122        let msg = Message::ConnectReply(msg);
123        assert_serialize_eq(&msg, serialized);
124        assert_deserialize_eq_with_value(&msg, serialized, &value);
125    }
126
127    #[test]
128    fn version_mismatch() {
129        let serialized = [12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 2];
130
131        let msg = ConnectReply::IncompatibleVersion(2);
132        assert_serialize_eq(&msg, serialized);
133        assert_deserialize_eq(&msg, serialized);
134
135        let msg = Message::ConnectReply(msg);
136        assert_serialize_eq(&msg, serialized);
137        assert_deserialize_eq(&msg, serialized);
138    }
139
140    #[test]
141    fn rejected() {
142        let serialized = [12, 0, 0, 0, 1, 2, 0, 0, 0, 3, 4, 2];
143        let value = 4u8;
144
145        let msg = ConnectReply::rejected_with_serialize_value(&value).unwrap();
146        assert_serialize_eq(&msg, serialized);
147        assert_deserialize_eq_with_value(&msg, serialized, &value);
148
149        let msg = Message::ConnectReply(msg);
150        assert_serialize_eq(&msg, serialized);
151        assert_deserialize_eq_with_value(&msg, serialized, &value);
152    }
153}