display_types/
manufacture.rs1#[non_exhaustive]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ManufactureDate {
14 Manufactured {
17 week: Option<u8>,
19 year: u16,
21 },
22 ModelYear(u16),
24}
25
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct ManufacturerId(pub [u8; 3]);
46
47impl ManufacturerId {
48 pub fn from_ascii(bytes: [u8; 3]) -> Option<Self> {
51 if bytes.iter().all(|&b| b.is_ascii_uppercase()) {
52 Some(Self(bytes))
53 } else {
54 None
55 }
56 }
57
58 pub fn as_str(&self) -> &str {
63 debug_assert!(
64 self.0.iter().all(|&b| b.is_ascii_uppercase()),
65 "ManufacturerId invariant violated: bytes must be ASCII uppercase A-Z, got {:?}",
66 self.0
67 );
68 core::str::from_utf8(&self.0).expect("ManufacturerId bytes must be ASCII uppercase A-Z")
70 }
71}
72
73impl core::fmt::Display for ManufacturerId {
74 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
75 f.write_str(self.as_str())
76 }
77}
78
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub struct MonitorString(pub [u8; 13]);
91
92impl MonitorString {
93 pub fn as_str(&self) -> &str {
97 let bytes = &self.0;
98 let end = bytes.iter().position(|&b| b == 0x0A).unwrap_or(bytes.len());
99 let trimmed = match bytes[..end].iter().rposition(|&b| b != b' ') {
100 Some(i) => &bytes[..=i],
101 None => &[][..],
102 };
103 core::str::from_utf8(trimmed).unwrap_or("")
104 }
105}
106
107impl core::fmt::Display for MonitorString {
108 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109 f.write_str(self.as_str())
110 }
111}
112
113impl core::ops::Deref for MonitorString {
114 type Target = str;
115 fn deref(&self) -> &str {
116 self.as_str()
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 #[cfg(any(feature = "alloc", feature = "std"))]
124 use crate::alloc::string::ToString;
125
126 #[test]
129 fn manufacturer_id_valid_ascii_uppercase() {
130 let id = ManufacturerId::from_ascii(*b"DEL").unwrap();
131 assert_eq!(id.as_str(), "DEL");
132 }
133
134 #[test]
135 fn manufacturer_id_rejects_lowercase() {
136 assert!(ManufacturerId::from_ascii(*b"del").is_none());
137 }
138
139 #[test]
140 fn manufacturer_id_rejects_digit() {
141 assert!(ManufacturerId::from_ascii(*b"D3L").is_none());
142 }
143
144 #[test]
145 #[cfg(any(feature = "alloc", feature = "std"))]
146 fn manufacturer_id_display() {
147 let id = ManufacturerId::from_ascii(*b"SAM").unwrap();
148 assert_eq!(id.to_string(), "SAM");
149 }
150
151 #[test]
154 fn monitor_string_strips_terminator_and_spaces() {
155 let mut buf = [b' '; 13];
156 let name = b"DELL U2722D";
157 buf[..name.len()].copy_from_slice(name);
158 buf[name.len()] = 0x0A;
159 assert_eq!(MonitorString(buf).as_str(), "DELL U2722D");
160 }
161
162 #[test]
163 fn monitor_string_no_terminator_strips_trailing_spaces() {
164 let mut buf = [b' '; 13];
165 buf[..3].copy_from_slice(b"ABC");
166 assert_eq!(MonitorString(buf).as_str(), "ABC");
167 }
168
169 #[test]
170 fn monitor_string_all_padding_gives_empty() {
171 assert_eq!(MonitorString([b' '; 13]).as_str(), "");
172 }
173
174 #[test]
175 fn monitor_string_deref() {
176 let mut buf = [b' '; 13];
177 buf[..3].copy_from_slice(b"LEN");
178 buf[3] = 0x0A;
179 let ms = MonitorString(buf);
180 let s: &str = &ms;
181 assert_eq!(s, "LEN");
182 }
183
184 #[test]
185 #[cfg(any(feature = "alloc", feature = "std"))]
186 fn monitor_string_display() {
187 let mut buf = [b' '; 13];
188 buf[..3].copy_from_slice(b"GSM");
189 buf[3] = 0x0A;
190 assert_eq!(MonitorString(buf).to_string(), "GSM");
191 }
192}