rabbitmq_stream_protocol/commands/
open.rs

1use std::{collections::HashMap, io::Write};
2
3use crate::{
4    codec::{Decoder, Encoder},
5    error::{DecodeError, EncodeError},
6    protocol::commands::COMMAND_OPEN,
7    response::ResponseCode,
8    FromResponse,
9};
10
11use super::Command;
12
13#[cfg(test)]
14use fake::Fake;
15
16#[cfg_attr(test, derive(fake::Dummy))]
17#[derive(PartialEq, Eq, Debug)]
18pub struct OpenCommand {
19    correlation_id: u32,
20    virtual_host: String,
21}
22
23impl OpenCommand {
24    pub fn new(correlation_id: u32, virtual_host: String) -> Self {
25        Self {
26            correlation_id,
27            virtual_host,
28        }
29    }
30}
31
32impl Encoder for OpenCommand {
33    fn encode(&self, writer: &mut impl Write) -> Result<(), EncodeError> {
34        self.correlation_id.encode(writer)?;
35        self.virtual_host.as_str().encode(writer)?;
36        Ok(())
37    }
38
39    fn encoded_size(&self) -> u32 {
40        self.correlation_id.encoded_size() + self.virtual_host.as_str().encoded_size()
41    }
42}
43
44impl Command for OpenCommand {
45    fn key(&self) -> u16 {
46        COMMAND_OPEN
47    }
48}
49
50#[cfg_attr(test, derive(fake::Dummy))]
51#[derive(Debug, PartialEq, Eq)]
52pub struct OpenResponse {
53    pub(crate) correlation_id: u32,
54    pub(crate) code: ResponseCode,
55    pub connection_properties: HashMap<String, String>,
56}
57
58impl OpenResponse {
59    /// Get a reference to the generic response's code.
60    pub fn code(&self) -> &ResponseCode {
61        &self.code
62    }
63
64    pub fn is_ok(&self) -> bool {
65        self.code == ResponseCode::Ok
66    }
67}
68
69impl OpenResponse {
70    /// Get a reference to the open response's connection properties.
71    pub fn connection_properties(&self) -> &HashMap<String, String> {
72        &self.connection_properties
73    }
74}
75
76impl FromResponse for OpenResponse {
77    fn from_response(response: crate::Response) -> Option<Self> {
78        match response.kind {
79            crate::ResponseKind::Open(open) => Some(open),
80            _ => None,
81        }
82    }
83}
84
85impl Decoder for OpenResponse {
86    fn decode(input: &[u8]) -> Result<(&[u8], Self), DecodeError> {
87        let (input, correlation_id) = u32::decode(input)?;
88        let (input, response_code) = ResponseCode::decode(input)?;
89
90        let (input, connection_properties) = if response_code == ResponseCode::Ok {
91            HashMap::decode(input)?
92        } else {
93            (input, HashMap::new())
94        };
95
96        Ok((
97            input,
98            OpenResponse {
99                correlation_id,
100                code: response_code,
101                connection_properties,
102            },
103        ))
104    }
105}
106
107impl Decoder for OpenCommand {
108    fn decode(input: &[u8]) -> Result<(&[u8], Self), DecodeError> {
109        let (input, correlation_id) = u32::decode(input)?;
110        let (input, virtual_host) = Option::decode(input)?;
111
112        Ok((
113            input,
114            OpenCommand {
115                correlation_id,
116                virtual_host: virtual_host.unwrap(),
117            },
118        ))
119    }
120}
121
122#[cfg(test)]
123mod tests {
124
125    use fake::{Fake, Faker};
126
127    use super::OpenCommand;
128    use crate::{
129        codec::Encoder,
130        commands::{
131            open::OpenResponse,
132            tests::{command_encode_decode_test, specific_command_encode_decode_test},
133        },
134        ResponseCode,
135    };
136
137    #[test]
138    fn open_command_test() {
139        command_encode_decode_test::<OpenCommand>()
140    }
141
142    impl Encoder for OpenResponse {
143        fn encode(
144            &self,
145            writer: &mut impl std::io::Write,
146        ) -> Result<(), crate::error::EncodeError> {
147            self.correlation_id.encode(writer)?;
148            self.code.encode(writer)?;
149            self.connection_properties.encode(writer)?;
150            Ok(())
151        }
152
153        fn encoded_size(&self) -> u32 {
154            0
155        }
156    }
157
158    #[test]
159    fn open_response_test() {
160        let mut response: OpenResponse = Faker.fake();
161        response.code = ResponseCode::Ok;
162        specific_command_encode_decode_test(response);
163    }
164}