cassandra_protocol/frame/
message_startup.rs

1use crate::error;
2use crate::frame::{Direction, Envelope, Flags, FromCursor, Opcode, Serialize, Version};
3use crate::types::{from_cursor_str, serialize_str, CIntShort};
4use std::collections::HashMap;
5use std::io::Cursor;
6
7const CQL_VERSION: &str = "CQL_VERSION";
8const CQL_VERSION_VAL: &str = "3.0.0";
9const COMPRESSION: &str = "COMPRESSION";
10const DRIVER_NAME: &str = "DRIVER_NAME";
11const DRIVER_VERSION: &str = "DRIVER_VERSION";
12
13#[derive(Debug, PartialEq, Eq, Default, Clone)]
14pub struct BodyReqStartup {
15    pub map: HashMap<String, String>,
16}
17
18impl BodyReqStartup {
19    pub fn new(compression: Option<String>, version: Version) -> BodyReqStartup {
20        let mut map = HashMap::new();
21        map.insert(CQL_VERSION.into(), CQL_VERSION_VAL.into());
22        if let Some(c) = compression {
23            map.insert(COMPRESSION.into(), c);
24        }
25
26        if version >= Version::V5 {
27            map.insert(DRIVER_NAME.into(), "cdrs-tokio".into());
28            if let Some(version) = option_env!("CARGO_PKG_VERSION") {
29                map.insert(DRIVER_VERSION.into(), version.into());
30            }
31        }
32
33        BodyReqStartup { map }
34    }
35}
36
37impl Serialize for BodyReqStartup {
38    fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
39        let num = self.map.len() as CIntShort;
40        num.serialize(cursor, version);
41
42        for (key, val) in &self.map {
43            serialize_str(cursor, key, version);
44            serialize_str(cursor, val, version);
45        }
46    }
47}
48
49impl FromCursor for BodyReqStartup {
50    fn from_cursor(cursor: &mut Cursor<&[u8]>, version: Version) -> error::Result<Self> {
51        let num = CIntShort::from_cursor(cursor, version)?;
52
53        let mut map = HashMap::with_capacity(num as usize);
54        for _ in 0..num {
55            map.insert(
56                from_cursor_str(cursor)?.to_string(),
57                from_cursor_str(cursor)?.to_string(),
58            );
59        }
60
61        Ok(BodyReqStartup { map })
62    }
63}
64
65impl Envelope {
66    /// Creates new envelope of type `startup`.
67    pub fn new_req_startup(compression: Option<String>, version: Version) -> Envelope {
68        let direction = Direction::Request;
69        let opcode = Opcode::Startup;
70        let body = BodyReqStartup::new(compression, version);
71
72        Envelope::new(
73            version,
74            direction,
75            Flags::empty(),
76            opcode,
77            0,
78            body.serialize_to_vec(version),
79            None,
80            vec![],
81        )
82    }
83}
84
85#[cfg(test)]
86mod test {
87    use super::*;
88    use crate::frame::{Envelope, Flags, Opcode, Version};
89
90    #[test]
91    fn new_body_req_startup_some_compression() {
92        let compression = "test_compression";
93        let body = BodyReqStartup::new(Some(compression.into()), Version::V4);
94        assert_eq!(
95            body.map.get("CQL_VERSION"),
96            Some("3.0.0".to_string()).as_ref()
97        );
98        assert_eq!(
99            body.map.get("COMPRESSION"),
100            Some(compression.to_string()).as_ref()
101        );
102        assert_eq!(body.map.len(), 2);
103    }
104
105    #[test]
106    fn new_body_req_startup_none_compression() {
107        let body = BodyReqStartup::new(None, Version::V4);
108        assert_eq!(
109            body.map.get("CQL_VERSION"),
110            Some("3.0.0".to_string()).as_ref()
111        );
112        assert_eq!(body.map.len(), 1);
113    }
114
115    #[test]
116    fn new_req_startup() {
117        let compression = Some("test_compression".to_string());
118        let frame = Envelope::new_req_startup(compression, Version::V4);
119        assert_eq!(frame.version, Version::V4);
120        assert_eq!(frame.flags, Flags::empty());
121        assert_eq!(frame.opcode, Opcode::Startup);
122        assert_eq!(frame.tracing_id, None);
123        assert!(frame.warnings.is_empty());
124    }
125
126    #[test]
127    fn body_req_startup_from_cursor() {
128        let bytes = vec![
129            0, 3, 0, 11, 68, 82, 73, 86, 69, 82, 95, 78, 65, 77, 69, 0, 22, 68, 97, 116, 97, 83,
130            116, 97, 120, 32, 80, 121, 116, 104, 111, 110, 32, 68, 114, 105, 118, 101, 114, 0, 14,
131            68, 82, 73, 86, 69, 82, 95, 86, 69, 82, 83, 73, 79, 78, 0, 6, 51, 46, 50, 53, 46, 48,
132            0, 11, 67, 81, 76, 95, 86, 69, 82, 83, 73, 79, 78, 0, 5, 51, 46, 52, 46, 53,
133        ];
134
135        let mut cursor = Cursor::new(bytes.as_slice());
136        BodyReqStartup::from_cursor(&mut cursor, Version::V4).unwrap();
137    }
138}