rosrust/tcpros/
header.rs

1use crate::rosmsg::RosMsg;
2use error_chain::bail;
3use std::collections::HashMap;
4use std::io::Error;
5
6pub fn decode<R: std::io::Read>(data: &mut R) -> Result<HashMap<String, String>, Error> {
7    RosMsg::decode(data)
8}
9
10pub fn encode<W: std::io::Write>(
11    writer: &mut W,
12    data: &HashMap<String, String>,
13) -> Result<(), Error> {
14    data.encode(writer)
15}
16
17pub fn match_field(
18    fields: &HashMap<String, String>,
19    field: &str,
20    expected: &str,
21) -> Result<(), super::error::Error> {
22    use super::error::ErrorKind;
23    let actual = match fields.get(field) {
24        Some(actual) => actual,
25        None => bail!(ErrorKind::HeaderMissingField(field.into())),
26    };
27    if actual != expected {
28        bail!(ErrorKind::HeaderMismatch(
29            field.into(),
30            expected.into(),
31            actual.clone(),
32        ));
33    }
34    Ok(())
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use std::collections::HashMap;
41
42    static FAILED_TO_ENCODE: &str = "Failed to encode";
43    static FAILED_TO_DECODE: &str = "Failed to decode";
44
45    #[test]
46    fn writes_empty_map() {
47        let mut cursor = std::io::Cursor::new(Vec::new());
48        let data = HashMap::<String, String>::new();
49        encode(&mut cursor, &data).expect(FAILED_TO_ENCODE);
50
51        assert_eq!(vec![0, 0, 0, 0], cursor.into_inner());
52    }
53
54    #[test]
55    fn writes_single_item() {
56        let mut cursor = std::io::Cursor::new(Vec::new());
57        let mut data = HashMap::<String, String>::new();
58        data.insert(String::from("abc"), String::from("123"));
59        encode(&mut cursor, &data).expect(FAILED_TO_ENCODE);
60        assert_eq!(
61            vec![11, 0, 0, 0, 7, 0, 0, 0, 97, 98, 99, 61, 49, 50, 51],
62            cursor.into_inner()
63        );
64    }
65
66    #[test]
67    fn writes_multiple_items() {
68        let mut cursor = std::io::Cursor::new(Vec::new());
69        let mut data = HashMap::<String, String>::new();
70        data.insert(String::from("abc"), String::from("123"));
71        data.insert(String::from("AAA"), String::from("B0"));
72        encode(&mut cursor, &data).expect(FAILED_TO_ENCODE);
73        let data = cursor.into_inner();
74        assert!(
75            vec![
76                21, 0, 0, 0, 7, 0, 0, 0, 97, 98, 99, 61, 49, 50, 51, 6, 0, 0, 0, 65, 65, 65, 61,
77                66, 48,
78            ] == data
79                || vec![
80                    21, 0, 0, 0, 6, 0, 0, 0, 65, 65, 65, 61, 66, 48, 7, 0, 0, 0, 97, 98, 99, 61,
81                    49, 50, 51,
82                ] == data
83        );
84    }
85
86    #[test]
87    fn reads_empty_map() {
88        let input = vec![0, 0, 0, 0];
89        let data = decode(&mut std::io::Cursor::new(input)).expect(FAILED_TO_DECODE);
90        assert_eq!(0, data.len());
91    }
92
93    #[test]
94    fn reads_single_element() {
95        let input = vec![11, 0, 0, 0, 7, 0, 0, 0, 97, 98, 99, 61, 49, 50, 51];
96        let data = decode(&mut std::io::Cursor::new(input)).expect(FAILED_TO_DECODE);
97        assert_eq!(1, data.len());
98        assert_eq!(Some(&String::from("123")), data.get("abc"));
99    }
100
101    #[test]
102    fn reads_typical_header() {
103        let input = vec![
104            0xb0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
105            0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x73,
106            0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x25, 0x00,
107            0x00, 0x00, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x69, 0x64, 0x3d, 0x2f, 0x72, 0x6f,
108            0x73, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f, 0x34, 0x37, 0x36, 0x37, 0x5f, 0x31, 0x33,
109            0x31, 0x36, 0x39, 0x31, 0x32, 0x37, 0x34, 0x31, 0x35, 0x35, 0x37, 0x0a, 0x00, 0x00,
110            0x00, 0x6c, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x3d, 0x31, 0x27, 0x00, 0x00,
111            0x00, 0x6d, 0x64, 0x35, 0x73, 0x75, 0x6d, 0x3d, 0x39, 0x39, 0x32, 0x63, 0x65, 0x38,
112            0x61, 0x31, 0x36, 0x38, 0x37, 0x63, 0x65, 0x63, 0x38, 0x63, 0x38, 0x62, 0x64, 0x38,
113            0x38, 0x33, 0x65, 0x63, 0x37, 0x33, 0x63, 0x61, 0x34, 0x31, 0x64, 0x31, 0x0e, 0x00,
114            0x00, 0x00, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x3d, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x74,
115            0x65, 0x72, 0x14, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x73, 0x74, 0x64,
116            0x5f, 0x6d, 0x73, 0x67, 0x73, 0x2f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,
117        ];
118        let data = decode(&mut std::io::Cursor::new(input)).expect(FAILED_TO_DECODE);
119        assert_eq!(6, data.len());
120        assert_eq!(
121            Some(&String::from("string data\n\n")),
122            data.get("message_definition")
123        );
124        assert_eq!(
125            Some(&String::from("/rostopic_4767_1316912741557")),
126            data.get("callerid")
127        );
128        assert_eq!(Some(&String::from("1")), data.get("latching"));
129        assert_eq!(
130            Some(&String::from("992ce8a1687cec8c8bd883ec73ca41d1")),
131            data.get("md5sum")
132        );
133        assert_eq!(Some(&String::from("/chatter")), data.get("topic"));
134        assert_eq!(Some(&String::from("std_msgs/String")), data.get("type"));
135    }
136}