bcd_numbers/
bcd.rs

1use crate::BCDConversionError;
2use std::fmt::{Debug, Display};
3
4#[derive(Clone, Copy)]
5pub struct BCD<const BYTES: usize> {
6    data: [u8;BYTES]
7}
8
9#[derive(Clone)]
10pub struct DynBCD {
11    data: Vec<u8>
12}
13
14pub trait Convertible<T> {
15    fn convert(&self) -> T;
16}
17
18fn check_invalid_byte(val: u8) -> bool {
19    let high = (val & 0xf0) >> 0x04;
20    let low = val & 0x0f;
21    low > 9 || high > 9
22}
23
24fn check_invalid_bytes<'a>(it: impl Iterator<Item = &'a u8>) -> bool {
25    let mut it = it;
26    it.any(|val| check_invalid_byte(val.to_owned()))
27}
28
29impl<const BYTES_OG: usize, const BYTES_DST: usize> Convertible<BCD<BYTES_DST>> for BCD<BYTES_OG> {
30    fn convert(&self) -> BCD<BYTES_DST> {
31        if BYTES_OG >= BYTES_DST {
32            BCD {
33                data: self.data.into_iter().rev().take(BYTES_DST).rev().collect::<Vec<u8>>().try_into().unwrap()
34            }
35        }
36        else {
37            let mut new_data = vec![0;BYTES_DST-BYTES_OG];
38            new_data.append(&mut Vec::from(self.data));
39            BCD {
40                data: new_data.try_into().unwrap()
41            }
42        }
43    }
44}
45
46impl<const BYTES: usize> Debug for BCD<BYTES> {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        f.debug_struct("BCD")
49            .field("data", &self.data)
50            .field("computed_value", &Into::<u128>::into((*self).convert()))
51            .finish()
52    }
53}
54
55impl<const BYTES: usize> Display for BCD<BYTES> {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        write!(f, "BCD<{}> {{ \"computed_value\": {} }}", BYTES, Into::<u128>::into((*self).convert()))
58    }
59}
60
61impl Debug for DynBCD {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        f.debug_struct("DynBCD")
64            .field("data", &self.data)
65            .field("computed_value", &Into::<u128>::into(self.clone()))
66            .finish()
67    }
68}
69
70impl Display for DynBCD {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        write!(f, "DynBCD {{ \"computed_value\": {} }}", Into::<u128>::into(self.clone()))
73    }
74}
75
76impl<const BYTES: usize> IntoIterator for BCD<BYTES> {
77    type Item = u8;
78
79    type IntoIter = std::array::IntoIter<Self::Item,BYTES>;
80
81    fn into_iter(self) -> Self::IntoIter {
82        self.data.into_iter()
83    }
84}
85
86impl IntoIterator for DynBCD {
87    type Item = u8;
88
89    type IntoIter = std::vec::IntoIter<Self::Item>;
90
91    fn into_iter(self) -> Self::IntoIter {
92        self.data.into_iter()
93    }
94}
95
96impl<const BYTES: usize> From<BCD<BYTES>> for Vec<u8> {
97    fn from(data: BCD<BYTES>) -> Self {
98        Vec::from(data.data)
99    }
100}
101
102impl From<DynBCD> for Vec<u8> {
103    fn from(data: DynBCD) -> Self {
104        data.data
105    }
106}
107
108impl<const BYTES: usize> From<DynBCD> for BCD<BYTES> {
109    fn from(value: DynBCD) -> Self {
110        let mut new_data: Vec<u8> = value.data.into_iter().rev().take(BYTES).collect();
111        while new_data.len() < BYTES {
112            new_data.push(0);
113        }
114        let new_data: Vec<u8> = new_data.into_iter().rev().collect();
115        Self {
116            data: new_data.try_into().unwrap()
117        }
118    }
119}
120
121impl<const BYTES: usize> From<BCD<BYTES>> for DynBCD {
122    fn from(value: BCD<BYTES>) -> Self {
123        Self {
124            data: Vec::from(value.data)
125        }
126    }
127}
128
129impl TryFrom<&[u8]> for DynBCD {
130    type Error = BCDConversionError;
131
132    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
133        if check_invalid_bytes(value.iter()) {
134            return Err(BCDConversionError::new("Invalid format, found A-F"));
135        }
136        Ok(Self {
137            data: Vec::from(value)
138        })
139    }
140}
141
142impl<const BYTES: usize> TryFrom<&[u8]> for BCD<BYTES> {
143    type Error = BCDConversionError;
144
145    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
146        if check_invalid_bytes(value.iter()) {
147            return Err(BCDConversionError::new("Invalid format, found A-F"));
148        }
149        if value.len() >= BYTES {
150            let buffer: Vec<u8> = value.iter()
151                .rev().take(BYTES).rev()
152                .copied()
153                .collect();
154            Ok(Self {
155                data: buffer.try_into().unwrap()
156            })
157        }
158        else {
159            let mut buffer = vec![0;BYTES - value.len()];
160            buffer.extend(value.iter().copied());
161            Ok(Self {
162                data: buffer.try_into().unwrap()
163            })
164        }
165    }
166}
167
168impl<const BYTES_OG: usize, const BYTES_DST: usize> TryFrom<[u8;BYTES_OG]> for BCD<BYTES_DST> {
169    type Error = BCDConversionError;
170
171    fn try_from(value: [u8;BYTES_OG]) -> Result<Self, Self::Error> {
172        if check_invalid_bytes(value.iter()) {
173            return Err(BCDConversionError::new("Invalid format. Found A-F"));
174        }
175        if BYTES_OG >= BYTES_DST {
176            Ok(Self {
177                data: value[BYTES_OG-BYTES_DST..].try_into().unwrap()
178            })
179        }
180        else {
181            let mut new_data = vec![0;BYTES_DST-BYTES_OG];
182            new_data.append(&mut Vec::from(value));
183            Ok(Self {
184                data: new_data.try_into().unwrap()
185            })
186        }
187    }
188}
189
190impl<const BYTES_OG: usize, const BYTES_DST: usize> From<BCD<BYTES_OG>> for [u8;BYTES_DST] {
191    fn from(data: BCD<BYTES_OG>) -> Self {
192        if BYTES_OG >= BYTES_DST {
193            data.data.into_iter().rev().take(BYTES_DST).rev().collect::<Vec<u8>>().try_into().unwrap()
194        }
195        else {
196            let mut new_data = vec![0;BYTES_DST-BYTES_OG];
197            new_data.append(&mut Vec::from(data.data));
198            new_data.try_into().unwrap()
199        }
200    }
201}
202
203impl TryFrom<u8> for BCD<1> {
204    type Error = BCDConversionError;
205
206    fn try_from(value: u8) -> Result<Self, Self::Error> {
207        let n_bytes = value.to_ne_bytes().into_iter().count();
208        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
209        if value > max_val { return Err(Self::Error::new_with_template_description("u8", value, max_val)); }
210        let high = value/10;
211        let low = value%10;
212        Ok(Self{data: [high<<4|low]})
213    }
214}
215
216impl From<BCD<1>> for u8 {
217    fn from(val: BCD<1>) -> Self {
218        let high = (val.data[0] & 0xf0) >> 4;
219        let low  = val.data[0] & 0x0f;
220        high*10+low
221    }
222}
223
224impl TryFrom<u16> for BCD<2> {
225    type Error = BCDConversionError;
226
227    fn try_from(value: u16) -> Result<Self, Self::Error> {
228        let n_bytes = value.to_ne_bytes().into_iter().count();
229        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
230        if value > max_val { return Err(Self::Error::new_with_template_description("u16", value, max_val)); }
231        let mut value = value;
232        let mut buffer: Vec<BCD<1>> = vec![];
233        while value != 0 {
234            let current = value%100;
235            buffer.push((current as u8).try_into()?);
236            value /= 100;
237        }
238        while buffer.len() < n_bytes {
239            buffer.push(BCD{ data: [0] });
240        }
241        let buffer: [u8; 2] = buffer.into_iter()
242            .rev()
243            .flat_map(|item| item.data)
244            .collect::<Vec<u8>>()
245            .try_into().unwrap();
246        Ok(Self::try_from(buffer).unwrap())
247    }
248}
249
250impl From<BCD<2>> for u16 {
251    fn from(value: BCD<2>) -> Self {
252        value.data.into_iter()
253            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
254    }
255}
256
257impl TryFrom<u32> for BCD<4> {
258    type Error = BCDConversionError;
259
260    fn try_from(value: u32) -> Result<Self, Self::Error> {
261        let n_bytes = value.to_ne_bytes().into_iter().count();
262        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
263        if value > max_val { return Err(Self::Error::new_with_template_description("u32", value, max_val)); }
264        let mut value = value;
265        let mut buffer: Vec<BCD<1>> = vec![];
266        while value != 0 {
267            let current = value%100;
268            buffer.push((current as u8).try_into()?);
269            value /= 100;
270        }
271        while buffer.len() < n_bytes {
272            buffer.push(BCD{ data: [0] });
273        }
274        let buffer: [u8; 4] = buffer.into_iter()
275            .rev()
276            .flat_map(|item| item.data)
277            .collect::<Vec<u8>>()
278            .try_into().unwrap();
279        Ok(Self::try_from(buffer).unwrap())
280    }
281}
282
283impl From<BCD<4>> for u32 {
284    fn from(value: BCD<4>) -> Self {
285        value.data.into_iter()
286            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
287    }
288}
289
290impl TryFrom<u64> for BCD<8> {
291    type Error = BCDConversionError;
292
293    fn try_from(value: u64) -> Result<Self, Self::Error> {
294        let n_bytes = value.to_ne_bytes().into_iter().count();
295        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
296        if value > max_val { return Err(Self::Error::new_with_template_description("u32", value, max_val)); }
297        let mut value = value;
298        let mut buffer: Vec<BCD<1>> = vec![];
299        while value != 0 {
300            let current = value%100;
301            buffer.push((current as u8).try_into()?);
302            value /= 100;
303        }
304        while buffer.len() < n_bytes {
305            buffer.push(BCD{ data: [0] });
306        }
307        let buffer: [u8; 8] = buffer.into_iter()
308            .rev()
309            .flat_map(|item| item.data)
310            .collect::<Vec<u8>>()
311            .try_into().unwrap();
312        Ok(Self::try_from(buffer).unwrap())
313    }
314}
315
316impl From<BCD<8>> for u64 {
317    fn from(value: BCD<8>) -> Self {
318        value.data.into_iter()
319            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
320    }
321}
322
323impl TryFrom<u128> for BCD<16> {
324    type Error = BCDConversionError;
325
326    fn try_from(value: u128) -> Result<Self, Self::Error> {
327        let n_bytes = value.to_ne_bytes().into_iter().count();
328        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
329        if value > max_val { return Err(Self::Error::new_with_template_description("u32", value, max_val)); }
330        let mut value = value;
331        let mut buffer: Vec<BCD<1>> = vec![];
332        while value != 0 {
333            let current = value%100;
334            buffer.push((current as u8).try_into()?);
335            value /= 100;
336        }
337        while buffer.len() < n_bytes {
338            buffer.push(BCD{ data: [0] });
339        }
340        let buffer: [u8; 16] = buffer.into_iter()
341            .rev()
342            .flat_map(|item| item.data)
343            .collect::<Vec<u8>>()
344            .try_into().unwrap();
345        Ok(Self::try_from(buffer).unwrap())
346    }
347}
348
349impl From<BCD<16>> for u128 {
350    fn from(value: BCD<16>) -> Self {
351        value.data.into_iter()
352            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
353    }
354}
355
356impl TryFrom<u8> for DynBCD {
357    type Error = BCDConversionError;
358
359    fn try_from(value: u8) -> Result<DynBCD, Self::Error> {
360        let n_bytes = value.to_ne_bytes().into_iter().count();
361        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
362        if value > max_val { return Err(Self::Error::new_with_template_description("u8", value, max_val)); }
363        let low = value % 10;
364        let high = value / 10;
365        Ok(Self {
366            data: vec![high<<4|low]
367        })
368    }
369}
370
371impl From<DynBCD> for u8 {
372    fn from(value: DynBCD) -> Self {
373        let value = value.data.into_iter().rev().next().unwrap();
374        let high = (value & 0xf0) >> 4;
375        let low = value & 0x0f;
376        high*10+low
377    }
378}
379
380impl TryFrom<u16> for DynBCD {
381    type Error = BCDConversionError;
382    fn try_from(value: u16) -> Result<DynBCD, Self::Error> {
383        let n_bytes = value.to_ne_bytes().into_iter().count();
384        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
385        if value > max_val { return Err(Self::Error::new_with_template_description("u16", value, max_val)); }
386        let mut value = value;
387        let mut buffer: Vec<BCD<1>> = vec![];
388        while value != 0 {
389            let current = (value % 100) as u8;
390            value /= 100;
391            buffer.push(current.try_into().unwrap());
392        }
393        let buffer = buffer.into_iter().rev().flat_map(|item| item.data).collect();
394        Ok(Self {
395            data: buffer
396        })
397    }
398}
399
400impl From<DynBCD> for u16 {
401    fn from(value: DynBCD) -> Self {
402        value.data.into_iter()
403            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
404    }
405}
406
407impl TryFrom<u32> for DynBCD {
408    type Error = BCDConversionError;
409
410    fn try_from(value: u32) -> Result<DynBCD, Self::Error> {
411        let n_bytes = value.to_ne_bytes().into_iter().count();
412        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
413        if value > max_val { return Err(Self::Error::new_with_template_description("u32", value, max_val)); }
414        let mut value = value;
415        let mut buffer: Vec<BCD<1>> = vec![];
416        while value != 0 {
417            let current = (value % 100) as u8;
418            value /= 100;
419            buffer.push(current.try_into().unwrap());
420        }
421        let buffer = buffer.into_iter().rev().flat_map(|item| item.data).collect();
422        Ok(Self {
423            data: buffer
424        })
425    }
426}
427
428impl From<DynBCD> for u32 {
429    fn from(value: DynBCD) -> Self {
430        value.data.into_iter()
431            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
432    }
433}
434
435impl TryFrom<u64> for DynBCD {
436    type Error = BCDConversionError;
437
438    fn try_from(value: u64) -> Result<DynBCD, Self::Error> {
439        let n_bytes = value.to_ne_bytes().into_iter().count();
440        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
441        if value > max_val { return Err(Self::Error::new_with_template_description("u64", value, max_val)); }
442        let mut value = value;
443        let mut buffer: Vec<BCD<1>> = vec![];
444        while value != 0 {
445            let current = (value % 100) as u8;
446            value /= 100;
447            buffer.push(current.try_into().unwrap());
448        }
449        let buffer = buffer.into_iter().rev().flat_map(|item| item.data).collect();
450        Ok(Self {
451            data: buffer
452        })
453    }
454}
455
456impl From<DynBCD> for u64 {
457    fn from(value: DynBCD) -> Self {
458        value.data.into_iter()
459            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
460    }
461}
462
463impl TryFrom<u128> for DynBCD {
464    type Error = BCDConversionError;
465
466    fn try_from(value: u128) -> Result<DynBCD, Self::Error> {
467        let n_bytes = value.to_ne_bytes().into_iter().count();
468        let max_val = (0..n_bytes).into_iter().fold(0, |acc, _| acc*100+99);
469        if value > max_val { return Err(Self::Error::new_with_template_description("u128", value, max_val)); }
470        let mut value = value;
471        let mut buffer: Vec<BCD<1>> = vec![];
472        while value != 0 {
473            let current = (value % 100) as u8;
474            value /= 100;
475            buffer.push(current.try_into().unwrap());
476        }
477        let buffer = buffer.into_iter().rev().flat_map(|item| item.data).collect();
478        Ok(Self {
479            data: buffer
480        })
481    }
482}
483
484impl From<DynBCD> for u128 {
485    fn from(value: DynBCD) -> Self {
486        value.data.into_iter()
487            .fold(0, |acc, x| acc*100 + (Into::<u8>::into(BCD::try_from([x]).unwrap()) as Self))
488    }
489}
490
491impl<const BYTES: usize> BCD<BYTES> {
492    pub fn new(value: u128) -> Self {
493        let new_val: BCD<16> = value.try_into().unwrap();
494        new_val.convert()
495    }
496
497    pub fn get_number(&self) -> u128 {
498        (*self).convert().into()
499    }
500}
501
502impl DynBCD {
503    pub fn new(value: u128) -> Self {
504        value.try_into().unwrap()
505    }
506
507    pub fn get_number(&self) -> u128 {
508        self.clone().into()
509    }
510}