1use crate::Error;
2use core::convert::TryFrom;
3
4#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
6pub struct U7(pub(crate) u8);
7
8impl U7 {
9 pub const MIN: U7 = U7(0x00);
11 pub const MAX: U7 = U7(0x80 - 0x01);
13
14 #[inline(always)]
16 pub fn new(data: u8) -> Result<U7, Error> {
17 if data > u8::from(U7::MAX) {
18 Err(Error::DataByteOutOfRange)
19 } else {
20 Ok(U7(data))
21 }
22 }
23
24 #[inline(always)]
29 pub unsafe fn from_unchecked(data: u8) -> U7 {
30 U7(data)
31 }
32
33 #[inline(always)]
35 pub const fn from_u8_lossy(data: u8) -> U7 {
36 U7(data & 0x7F)
37 }
38
39 #[inline(always)]
42 pub fn try_from_bytes(bytes: &[u8]) -> Result<&[U7], Error> {
43 for b in bytes.iter() {
44 U7::try_from(*b)?;
45 }
46 unsafe { Ok(U7::from_bytes_unchecked(bytes)) }
47 }
48
49 #[inline(always)]
52 pub fn data_to_bytes(data: &[U7]) -> &[u8] {
53 unsafe { &*(data as *const [U7] as *const [u8]) }
54 }
55
56 #[inline(always)]
61 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &[U7] {
62 &*(bytes as *const [u8] as *const [U7])
63 }
64}
65
66impl From<U7> for u8 {
67 #[inline(always)]
68 fn from(data: U7) -> u8 {
69 data.0
70 }
71}
72
73impl TryFrom<u8> for U7 {
74 type Error = Error;
75
76 #[inline(always)]
77 fn try_from(data: u8) -> Result<U7, Error> {
78 U7::new(data)
79 }
80}
81
82#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
84pub struct U14(u16);
85
86impl U14 {
87 pub const MIN: U14 = U14(0);
89 pub const MAX: U14 = U14(0x4000 - 0x0001);
91
92 #[inline(always)]
97 pub unsafe fn from_unchecked(data: u16) -> U14 {
98 U14(data)
99 }
100
101 #[inline(always)]
104 pub fn try_from_slice(slice: &[u16]) -> Result<&[U14], Error> {
105 for d in slice.iter() {
106 U14::try_from(*d)?;
107 }
108 unsafe { Ok(U14::from_slice_unchecked(slice)) }
109 }
110
111 #[inline(always)]
114 pub fn data_to_slice(data: &[U14]) -> &[u16] {
115 unsafe { &*(data as *const [U14] as *const [u16]) }
116 }
117
118 #[inline(always)]
123 pub unsafe fn from_slice_unchecked(slice: &[u16]) -> &[U14] {
124 &*(slice as *const [u16] as *const [U14])
125 }
126}
127
128impl From<U14> for u16 {
129 #[inline(always)]
130 fn from(data: U14) -> u16 {
131 data.0
132 }
133}
134
135impl TryFrom<u16> for U14 {
136 type Error = Error;
137
138 #[inline(always)]
139 fn try_from(data: u16) -> Result<U14, Error> {
140 if data > u16::from(U14::MAX) {
141 Err(Error::U14OutOfRange)
142 } else {
143 Ok(U14(data))
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn try_from_passes() {
154 for n in 0x00..0x80 {
155 U7::try_from(n).unwrap();
156 }
157 }
158
159 #[test]
160 fn min_and_max_constant_are_valid() {
161 assert_eq!(U7::try_from(u8::from(U7::MIN)).unwrap(), U7::MIN);
162 assert_eq!(U7::try_from(u8::from(U7::MAX)).unwrap(), U7::MAX);
163 }
164
165 #[test]
166 fn try_from_out_of_range_fails() {
167 for n in 0x80..=u8::MAX {
168 assert_eq!(U7::try_from(n), Err(Error::DataByteOutOfRange));
169 }
170 }
171
172 #[test]
173 fn try_from_bytes_is_ok_on_valid_bytes() {
174 U7::try_from_bytes(&[]).unwrap();
175 U7::try_from_bytes(&[0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x7F]).unwrap();
176 }
177
178 #[test]
179 fn try_from_bytes_fails_on_out_of_range() {
180 assert_eq!(
181 U7::try_from_bytes(&[0x00, 0x80]),
182 Err(Error::DataByteOutOfRange)
183 );
184 }
185
186 #[test]
187 fn data_to_bytes_converts_exactly() {
188 assert_eq!(
189 &[0x00, 0x0F, 0x7F],
190 U7::data_to_bytes(&[
191 U7::try_from(0x00).unwrap(),
192 U7::try_from(0x0F).unwrap(),
193 U7::try_from(0x7F).unwrap()
194 ]),
195 );
196 }
197
198 #[test]
199 fn try_from_16_passes() {
200 for n in 0x0000..0x4000 {
201 U14::try_from(n).unwrap();
202 }
203 }
204
205 #[test]
206 fn min_and_max_14_constant_are_valid() {
207 assert_eq!(U14::try_from(u16::from(U14::MIN)).unwrap(), U14::MIN);
208 assert_eq!(U14::try_from(u16::from(U14::MAX)).unwrap(), U14::MAX);
209 }
210
211 #[test]
212 fn try_from_out_of_range_16_fails() {
213 for n in 0x4000..=u16::MAX {
214 assert_eq!(U14::try_from(n), Err(Error::U14OutOfRange));
215 }
216 }
217
218 #[test]
219 fn try_from_slice_is_ok_on_valid_range() {
220 U14::try_from_slice(&[]).unwrap();
221 U14::try_from_slice(&[0x0000, 0x0080, 0x0180, 0x01FF]).unwrap();
222 }
223
224 #[test]
225 fn try_from_slice_fails_on_out_of_range() {
226 assert_eq!(
227 U14::try_from_slice(&[0x0000, 0x5000]),
228 Err(Error::U14OutOfRange)
229 );
230 }
231
232 #[test]
233 fn data_to_slice_converts_exactly() {
234 assert_eq!(
235 &[0x0000, 0x010F, 0x017F],
236 U14::data_to_slice(&[
237 U14::try_from(0x0000).unwrap(),
238 U14::try_from(0x010F).unwrap(),
239 U14::try_from(0x017F).unwrap()
240 ]),
241 );
242 }
243
244 #[test]
245 fn test_from_u8_lossy() {
246 assert_eq!(U7::from_u8_lossy(0), U7::try_from(0).unwrap());
247 assert_eq!(U7::from_u8_lossy(64), U7::try_from(64).unwrap());
248 assert_eq!(U7::from_u8_lossy(127), U7::try_from(127).unwrap());
249 assert_eq!(U7::from_u8_lossy(128), U7::try_from(0).unwrap());
250 assert_eq!(U7::from_u8_lossy(200), U7::try_from(72).unwrap());
251 }
252}