1use crate::items::{encode_prefixed_item, fixed_items, prefixed_items};
4
5pub const UNKNOWN: u16 = 0xffff;
6pub const NAME_MAX_BYTES: usize = 64;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum Error {
10 Malformed,
11 BufferTooSmall,
12}
13
14pub fn readings(value: &[u8]) -> Result<impl ExactSizeIterator<Item = Option<u16>> + Clone, Error> {
16 Ok(fixed_items::<2>(value)
17 .map_err(|_| Error::Malformed)?
18 .map(|bytes| {
19 let value = u16::from_le_bytes(*bytes);
20 (value != UNKNOWN).then_some(value)
21 }))
22}
23
24pub fn encode_readings(values: &[u16], out: &mut [u8]) -> Result<usize, Error> {
26 let len = values.len().checked_mul(2).ok_or(Error::BufferTooSmall)?;
27 if out.len() < len {
28 return Err(Error::BufferTooSmall);
29 }
30 for (value, bytes) in values.iter().zip(out[..len].chunks_exact_mut(2)) {
31 bytes.copy_from_slice(&value.to_le_bytes());
32 }
33 Ok(len)
34}
35
36pub fn valid_name(name: &str) -> bool {
37 (1..=NAME_MAX_BYTES).contains(&name.len()) && !name.as_bytes().contains(&0)
38}
39
40pub fn names(value: &[u8]) -> Result<impl Iterator<Item = &str> + Clone, Error> {
42 for item in prefixed_items(value) {
43 let name = core::str::from_utf8(item.map_err(|_| Error::Malformed)?)
44 .map_err(|_| Error::Malformed)?;
45 if !valid_name(name) {
46 return Err(Error::Malformed);
47 }
48 }
49 Ok(prefixed_items(value).map(|item| {
50 core::str::from_utf8(item.expect("validated name prefix")).expect("validated UTF-8")
51 }))
52}
53
54pub fn encode_names(names: &[&str], out: &mut [u8]) -> Result<usize, Error> {
55 let mut len = 0usize;
56 for name in names {
57 if !valid_name(name) {
58 return Err(Error::Malformed);
59 }
60 len = len
62 .checked_add(1 + name.len())
63 .ok_or(Error::BufferTooSmall)?;
64 }
65 if len > out.len() {
66 return Err(Error::BufferTooSmall);
67 }
68 let mut offset = 0;
69 for name in names {
70 offset += encode_prefixed_item(name.as_bytes(), &mut out[offset..])
71 .map_err(|_| Error::BufferTooSmall)?;
72 }
73 Ok(offset)
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn temperature_readings_boundaries_and_order() {
82 let values = [2981, 0, 0xfffe, UNKNOWN];
83 let mut out = [0; 8];
84 assert_eq!(encode_readings(&values, &mut out), Ok(8));
85 assert_eq!(out, [0xa5, 0x0b, 0, 0, 0xfe, 0xff, 0xff, 0xff]);
86 assert_eq!(
87 readings(&out).unwrap().collect::<Vec<_>>(),
88 [Some(2981), Some(0), Some(65534), None]
89 );
90 assert_eq!(readings(&[]).unwrap().len(), 0);
91 assert!(readings(&[0]).is_err());
92 assert_eq!(
93 encode_readings(&values, &mut [0; 7]),
94 Err(Error::BufferTooSmall)
95 );
96 assert_eq!(encode_readings(&[], &mut []), Ok(0));
97 }
98
99 #[test]
100 fn temperature_names_validate_complete_array() {
101 let mut out = [0; 128];
102 let len = encode_names(&["Die", "電池", "Die"], &mut out).unwrap();
103 assert_eq!(
104 names(&out[..len]).unwrap().collect::<Vec<_>>(),
105 ["Die", "電池", "Die"]
106 );
107 assert_eq!(names(&[]).unwrap().count(), 0);
108 for bad in [
109 &[0][..],
110 &[1, 0],
111 &[1, 0xff],
112 &[2, b'a'],
113 &[0x80],
114 &[1, b'a', 0],
115 ] {
116 assert!(names(bad).is_err(), "{bad:?}");
117 }
118 assert_eq!(
119 encode_names(&["ab"], &mut [0; 2]),
120 Err(Error::BufferTooSmall)
121 );
122 for bad in ["", "a\0b", &"a".repeat(65)] {
123 assert_eq!(encode_names(&[bad], &mut out), Err(Error::Malformed));
124 }
125 assert!(encode_names(&[&"a".repeat(64)], &mut out).is_ok());
126 let too_long = [&[65][..], &[b'a'; 65]].concat();
127 assert!(names(&too_long).is_err());
128 assert_eq!(names(&b"\x01a".repeat(17)).unwrap().count(), 17);
130 }
131}