Skip to main content

codeq/codec/impls/
string_impl.rs

1use std::io;
2
3use byteorder::BigEndian;
4use byteorder::ReadBytesExt;
5use byteorder::WriteBytesExt;
6
7use crate::Decode;
8use crate::Encode;
9
10impl Encode for &str {
11    fn encode<W: io::Write>(&self, mut w: W) -> Result<usize, io::Error> {
12        let bytes = self.as_bytes();
13        w.write_u32::<BigEndian>(bytes.len() as u32)?;
14        w.write_all(bytes)?;
15        Ok(bytes.len() + 4)
16    }
17}
18
19impl Encode for String {
20    fn encode<W: io::Write>(&self, w: W) -> Result<usize, io::Error> {
21        self.as_str().encode(w)
22    }
23}
24
25impl Decode for String {
26    fn decode<R: io::Read>(mut r: R) -> Result<Self, io::Error> {
27        let len = r.read_u32::<BigEndian>()? as usize;
28        let mut buf = vec![0; len];
29        r.read_exact(&mut buf)?;
30        String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
31    }
32}
33
34#[cfg(test)]
35mod tests {
36
37    use std::io;
38
39    use crate::Decode;
40    use crate::Encode;
41
42    #[test]
43    fn test_string_codec() -> Result<(), io::Error> {
44        let s = "hello".to_string();
45        let mut buf = Vec::new();
46        let n = s.encode(&mut buf)?;
47        assert_eq!(n, buf.len());
48        assert_eq!(buf.len(), 4 + s.len());
49
50        let b = String::decode(&mut buf.as_slice())?;
51        assert_eq!(s, b);
52
53        Ok(())
54    }
55
56    #[test]
57    fn test_str_encode() -> Result<(), io::Error> {
58        check_str_encode("hello", b"\x00\x00\x00\x05hello")
59    }
60
61    #[test]
62    fn test_str_encode_empty() -> Result<(), io::Error> {
63        check_str_encode("", b"\x00\x00\x00\x00")
64    }
65
66    #[test]
67    fn test_str_encode_multibyte() -> Result<(), io::Error> {
68        let s = "你好";
69        assert_eq!(s.chars().count(), 2, "2 characters");
70        assert_eq!(s.len(), 6, "but 6 UTF-8 bytes");
71
72        let mut buf = Vec::new();
73        s.encode(&mut buf)?;
74
75        // Length prefix counts bytes (6), not characters (2).
76        assert_eq!(&buf[..4], &[0u8, 0, 0, 6]);
77        assert_eq!(&buf[4..], s.as_bytes());
78        assert_eq!(String::decode(&mut buf.as_slice())?, s);
79
80        Ok(())
81    }
82
83    #[test]
84    fn test_str_matches_string_encode() -> Result<(), io::Error> {
85        for s in ["", "hello", "你好"] {
86            let mut from_str = Vec::new();
87            s.encode(&mut from_str)?;
88
89            let mut from_string = Vec::new();
90            s.to_string().encode(&mut from_string)?;
91
92            assert_eq!(
93                from_str, from_string,
94                "&str and String must encode identically: {s:?}"
95            );
96        }
97        Ok(())
98    }
99
100    /// Encodes `s`, asserting the exact wire bytes, the returned length, and a
101    /// clean round-trip back through `String::decode`.
102    fn check_str_encode(s: &str, expect: &[u8]) -> Result<(), io::Error> {
103        let mut buf = Vec::new();
104        let n = s.encode(&mut buf)?;
105
106        assert_eq!(buf, expect, "exact wire bytes for {s:?}");
107        assert_eq!(n, buf.len(), "returned count equals bytes written");
108        assert_eq!(buf.len(), 4 + s.len(), "4-byte prefix + UTF-8 byte length");
109
110        let decoded = String::decode(&mut buf.as_slice())?;
111        assert_eq!(decoded, s, "round-trips through String::decode");
112
113        Ok(())
114    }
115}