embedded_mqtt/codec/
string.rs1use core::{
2 result::Result,
3 str,
4 cmp::min,
5 convert::TryFrom,
6};
7
8use crate::{
9 status::Status,
10 error::{DecodeError, EncodeError},
11};
12
13use super::{
14 values,
15 Decodable,
16 Encodable,
17};
18
19impl<'buf> Decodable<'buf> for &'buf str {
20 fn decode(bytes: &'buf [u8]) -> Result<Status<(usize, &'buf str)>, DecodeError> {
21 parse_string(bytes)
22 }
23}
24
25impl Encodable for str {
26 fn encoded_len(&self) -> usize {
27 2 + self.len()
28 }
29
30 fn encode(&self, bytes: &mut [u8]) -> Result<usize, EncodeError> {
31 encode_string(self, bytes)
32 }
33}
34
35pub fn parse_string(bytes: &[u8]) -> Result<Status<(usize, &str)>, DecodeError> {
36 let offset = 0;
37
38 let (offset, string_len) = read!(values::parse_u16, bytes, offset);
39
40 let available = bytes.len() - offset;
41
42 let needed = string_len as usize - min(available, string_len as usize);
43 if needed > 0 {
44 return Ok(Status::Partial(needed));
45 }
46
47 let val = if string_len > 0 {
48 str::from_utf8(&bytes[2..(2 + string_len) as usize])?
55 } else {
56 ""
57 };
58
59 if val.chars().any(|ch| ch == '\u{0000}') {
62 return Err(DecodeError::Utf8)
63 }
64
65 Ok(Status::Complete(((2 + string_len) as usize, val)))
66}
67
68pub fn encode_string(string: &str, bytes: &mut [u8]) -> Result<usize, EncodeError> {
69 let size = match u16::try_from(string.len()) {
70 Err(_) => return Err(EncodeError::ValueTooBig),
71 Ok(s) => s,
72 };
73
74 if bytes.len() < (2 + size) as usize {
75 return Err(EncodeError::OutOfSpace)
76 }
77
78 values::encode_u16(size, &mut bytes[0..2])?;
79 (&mut bytes[2..2 + size as usize]).copy_from_slice(string.as_bytes());
80
81 Ok(2 + size as usize)
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use std::{
88 io::{Cursor, Write},
89 vec::Vec,
90 format,
91 };
92
93 use byteorder::{
94 BigEndian,
95 ByteOrder,
96 };
97
98 use byteorder::WriteBytesExt;
99
100 #[test]
101 fn small_buffer() {
102 assert_eq!(Ok(Status::Partial(2)), parse_string(&[]));
103 assert_eq!(Ok(Status::Partial(1)), parse_string(&[0]));
104
105 let mut buf = [0u8; 2];
106 BigEndian::write_u16(&mut buf, 16);
107 assert_eq!(Ok(Status::Partial(16)), parse_string(&buf));
108 }
109
110 #[test]
111 fn empty_str() {
112 let mut buf = [0u8; 2];
113 BigEndian::write_u16(&mut buf, 0);
114 assert_eq!(Ok(Status::Complete((2, ""))), parse_string(&buf));
115 }
116
117 #[test]
118 fn parse_str() {
119 let inp = "don't panic!";
120 let mut buf = Cursor::new(Vec::new());
121 buf.write_u16::<BigEndian>(inp.len() as u16).unwrap();
122 buf.write(inp.as_bytes()).unwrap();
123 assert_eq!(
124 Status::Complete((14, inp)),
125 parse_string(buf.get_ref().as_ref()).unwrap()
126 );
127 }
128
129 #[test]
130 fn invalid_utf8() {
131 let inp = [0, 159, 146, 150];
132 let mut buf = Cursor::new(Vec::new());
133 buf.write_u16::<BigEndian>(inp.len() as u16).unwrap();
134 buf.write(&inp).unwrap();
135 assert_eq!(Err(DecodeError::Utf8), parse_string(buf.get_ref().as_ref()));
136 }
137
138 #[test]
139 fn null_utf8() {
140 let inp = format!("don't {} panic!", '\u{0000}');
141 let mut buf = Cursor::new(Vec::new());
142 buf.write_u16::<BigEndian>(inp.len() as u16).unwrap();
143 buf.write(inp.as_bytes()).unwrap();
144 assert_eq!(Err(DecodeError::Utf8), parse_string(buf.get_ref().as_ref()));
145 }
146
147 #[test]
148 fn encode() {
149 let mut buf = [0u8; 3];
150 let result = encode_string("a", &mut buf[0..3]);
151 assert_eq!(result, Ok(3));
152 assert_eq!(buf, [0b00000000, 0b00000001, 0x61]);
153 }
154}