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}