bcd_convert/
lib.rs

1use std::convert::TryFrom;
2use std::fmt;
3use std::str::FromStr;
4use thiserror::Error;
5
6/// An error type indicating issues that occur during BCD parsing or conversion.
7#[derive(Debug, Error, PartialEq)]
8pub enum BcdError {
9    /// Indicates that a nibble (4-bit segment) of the provided BCD byte
10    /// is invalid (greater than 9).
11    #[error("invalid BCD nibble: {0:#X}")]
12    InvalidBcdNibble(u8),
13
14    /// Indicates that the input string contains non-digit characters.
15    #[error("input string contains non-digit character: {0}")]
16    NonDigitChar(char),
17
18    /// Indicates that the numeric value represented by the BCD number
19    /// exceeds the range of `u64`.
20    #[error("cannot convert BcdNumber to u64: number too large")]
21    Overflow,
22}
23
24/// `BcdNumber` is a representation of a numeric value encoded in BCD (Binary Coded Decimal) form.
25/// Each byte holds two decimal digits: the upper nibble (4 bits) for the higher digit
26/// and the lower nibble (4 bits) for the lower digit. For example, 0x12 represents the digits "1" and "2".
27///
28/// The internal byte vector is arranged such that the most significant decimal digits are stored
29/// toward the start of the vector. Thus, `BcdNumber(vec![0x12, 0x34])` corresponds to the decimal number "1234".
30///
31/// This type provides conversions to and from `u64`, as well as parsing from strings and raw BCD bytes.
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct BcdNumber(Vec<u8>);
34
35impl BcdNumber {
36    /// Creates a `BcdNumber` from a `u64` value.
37    /// Leading zeros are removed except when the value is zero, in which case a single `0x00` byte is used.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use bcd_convert::BcdNumber;
43    ///
44    /// let b = BcdNumber::from_u64(1234);
45    /// assert_eq!(b.to_string(), "1234");
46    /// ```
47    pub fn from_u64(mut value: u64) -> Self {
48        if value == 0 {
49            return BcdNumber(vec![0x00]);
50        }
51
52        let mut digits = Vec::new();
53        while value > 0 {
54            let d = (value % 10) as u8;
55            digits.push(d);
56            value /= 10;
57        }
58        digits.reverse();
59
60        let mut bytes = Vec::new();
61        if digits.len() == 1 {
62            bytes.push(digits[0] & 0x0F);
63        } else if digits.len() % 2 == 1 {
64            // odd number of digits
65            let first = digits[0];
66            bytes.push(first);
67            for chunk in digits[1..].chunks(2) {
68                let hi = chunk[0];
69                let lo = chunk[1];
70                bytes.push((hi << 4) | lo);
71            }
72        } else {
73            // even number of digits
74            for chunk in digits.chunks(2) {
75                let hi = chunk[0];
76                let lo = chunk[1];
77                bytes.push((hi << 4) | lo);
78            }
79        }
80
81        BcdNumber(bytes)
82    }
83
84    /// Creates a `BcdNumber` from a decimal string.
85    /// Leading zeros are removed except when the entire string is zero,
86    /// in which case a single zero digit is stored.
87    ///
88    /// Returns `Err(BcdError::NonDigitChar(_))` if any non-digit character is found.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// use bcd_convert::BcdNumber;
94    ///
95    /// let b = BcdNumber::from_str_strict("001234").unwrap();
96    /// assert_eq!(b.to_string(), "1234");
97    /// ```
98    pub fn from_str_strict(s: &str) -> Result<Self, BcdError> {
99        let mut digits: Vec<u8> = Vec::new();
100        for c in s.chars() {
101            if !c.is_ascii_digit() {
102                return Err(BcdError::NonDigitChar(c));
103            }
104            digits.push(c as u8 - b'0');
105        }
106
107        while digits.len() > 1 && digits[0] == 0 {
108            digits.remove(0);
109        }
110
111        if digits.is_empty() {
112            digits.push(0);
113        }
114
115        let mut bytes = Vec::new();
116        if digits.len() == 1 {
117            bytes.push(digits[0] & 0x0F);
118        } else if digits.len() % 2 == 1 {
119            let first = digits[0];
120            bytes.push(first);
121            for chunk in digits[1..].chunks(2) {
122                bytes.push((chunk[0] << 4) | chunk[1]);
123            }
124        } else {
125            for chunk in digits.chunks(2) {
126                bytes.push((chunk[0] << 4) | chunk[1]);
127            }
128        }
129
130        Ok(BcdNumber(bytes))
131    }
132
133    /// Converts this `BcdNumber` into a `u64`.
134    ///
135    /// Returns `Err(BcdError::InvalidBcdNibble(_))` if the BCD contains invalid digits.
136    /// Returns `Err(BcdError::Overflow)` if the number cannot fit into a `u64`.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use bcd_convert::BcdNumber;
142    ///
143    /// let b = BcdNumber::from_u64(9999);
144    /// let val = b.to_u64().unwrap();
145    /// assert_eq!(val, 9999);
146    /// ```
147    pub fn to_u64(&self) -> Result<u64, BcdError> {
148        let mut result = 0u64;
149        for &b in &self.0 {
150            let hi = (b >> 4) & 0x0F;
151            let lo = b & 0x0F;
152
153            if hi > 9 || lo > 9 {
154                return Err(BcdError::InvalidBcdNibble(b));
155            }
156
157            let digit_val = (hi as u64) * 10 + (lo as u64);
158            let (res, overflow1) = result.overflowing_mul(100);
159            let (res, overflow2) = res.overflowing_add(digit_val);
160            if overflow1 || overflow2 {
161                return Err(BcdError::Overflow);
162            }
163            result = res;
164        }
165        Ok(result)
166    }
167
168    /// Converts the BCD number into a decimal string.
169    ///
170    /// This function assumes the internal representation is always valid BCD,
171    /// so it never returns an error.
172    ///
173    /// # Examples
174    ///
175    /// ```
176    /// use bcd_convert::BcdNumber;
177    ///
178    /// let b = BcdNumber::from_u64(1234);
179    /// assert_eq!(b.to_string(), "1234");
180    /// ```
181    pub fn to_string(&self) -> String {
182        let mut s = String::new();
183        for &b in &self.0 {
184            let hi = (b >> 4) & 0x0F;
185            let lo = b & 0x0F;
186            s.push((b'0' + hi) as char);
187            s.push((b'0' + lo) as char);
188        }
189        s
190    }
191
192    /// Returns the Nth digit of the decimal number, starting from 0 at the leftmost (most significant) digit.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use bcd_convert::BcdNumber;
198    ///
199    /// let b = BcdNumber::from_u64(1234);
200    /// assert_eq!(b.get_digit(0), Some(1));
201    /// assert_eq!(b.get_digit(1), Some(2));
202    /// assert_eq!(b.get_digit(2), Some(3));
203    /// assert_eq!(b.get_digit(3), Some(4));
204    /// assert_eq!(b.get_digit(4), None);
205    /// ```
206    pub fn get_digit(&self, index: usize) -> Option<u8> {
207        let total_digits = self.0.len() * 2;
208        if index >= total_digits {
209            return None;
210        }
211
212        let byte_index = index / 2;
213        let nibble_in_byte = index % 2;
214        let b = self.0[byte_index];
215        let digit = if nibble_in_byte == 0 {
216            (b >> 4) & 0x0F
217        } else {
218            b & 0x0F
219        };
220        Some(digit)
221    }
222}
223
224impl FromStr for BcdNumber {
225    type Err = BcdError;
226    /// Parses a `BcdNumber` from a string slice containing decimal digits.
227    ///
228    /// Leading zeros are removed except when all digits are zero.
229    ///
230    /// # Errors
231    ///
232    /// Returns `Err(BcdError::NonDigitChar(_))` if any character is not a decimal digit.
233    fn from_str(s: &str) -> Result<Self, Self::Err> {
234        BcdNumber::from_str_strict(s)
235    }
236}
237
238impl fmt::Display for BcdNumber {
239    /// Formats the BCD number as a sequence of decimal digits.
240    ///
241    /// This does not remove leading zeros, as `BcdNumber` maintains a minimal representation internally.
242    /// For zero, it will print "00" because a single zero digit is stored as `[0x00]`. You may handle that case
243    /// separately if needed.
244    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245        for &b in &self.0 {
246            let hi = (b >> 4) & 0x0F;
247            let lo = b & 0x0F;
248            write!(f, "{}{}", hi, lo)?;
249        }
250        Ok(())
251    }
252}
253
254impl TryFrom<BcdNumber> for u64 {
255    type Error = BcdError;
256    /// Attempts to convert a `BcdNumber` into a `u64`.
257    ///
258    /// Returns `Err(BcdError::InvalidBcdNibble(_))` if invalid digits are found,
259    /// or `Err(BcdError::Overflow)` if the number is too large for `u64`.
260    fn try_from(value: BcdNumber) -> Result<Self, Self::Error> {
261        value.to_u64()
262    }
263}
264
265impl From<u64> for BcdNumber {
266    /// Converts a `u64` into a `BcdNumber`.
267    fn from(value: u64) -> Self {
268        BcdNumber::from_u64(value)
269    }
270}
271
272impl TryFrom<&[u8]> for BcdNumber {
273    type Error = BcdError;
274    /// Converts a raw BCD byte slice into a `BcdNumber`.
275    ///
276    /// This function checks that each nibble is within 0–9.
277    /// If invalid data is detected, it returns `Err(BcdError::InvalidBcdNibble(_))`.
278    ///
279    /// Note: Leading zeros are not stripped here. The provided BCD bytes are stored as is.
280    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
281        let mut digits = Vec::new();
282        for &b in value {
283            let hi = (b >> 4) & 0x0F;
284            let lo = b & 0x0F;
285            if hi > 9 || lo > 9 {
286                return Err(BcdError::InvalidBcdNibble(b));
287            }
288            digits.push(hi);
289            digits.push(lo);
290        }
291
292        Ok(BcdNumber(value.to_vec()))
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use std::vec;
299
300    use super::*;
301
302    #[test]
303    fn test_from_u64() {
304        assert_eq!(BcdNumber::from_u64(0), BcdNumber(vec![0x00]));
305        assert_eq!(BcdNumber::from_u64(1), BcdNumber(vec![0x01]));
306        assert_eq!(BcdNumber::from_u64(99), BcdNumber(vec![0x99]));
307        assert_eq!(BcdNumber::from_u64(100), BcdNumber(vec![0x01, 0x00]));
308        assert_eq!(BcdNumber::from_u64(101), BcdNumber(vec![0x01, 0x01]));
309        assert_eq!(BcdNumber::from_u64(1000), BcdNumber(vec![0x10, 0x00]));
310        assert_eq!(BcdNumber::from_u64(1234), BcdNumber(vec![0x12, 0x34]));
311        assert_eq!(BcdNumber::from_u64(9999), BcdNumber(vec![0x99, 0x99]));
312        assert_eq!(
313            BcdNumber::from_u64(11010),
314            BcdNumber(vec![0x01, 0x10, 0x10])
315        );
316    }
317
318    #[test]
319    fn test_from_str_strict() {
320        assert_eq!(
321            BcdNumber::from_str_strict("0").unwrap(),
322            BcdNumber(vec![0x00])
323        );
324        assert_eq!(
325            BcdNumber::from_str_strict("1").unwrap(),
326            BcdNumber(vec![0x01])
327        );
328        assert_eq!(
329            BcdNumber::from_str_strict("99").unwrap(),
330            BcdNumber(vec![0x99])
331        );
332        assert_eq!(
333            BcdNumber::from_str_strict("100").unwrap(),
334            BcdNumber(vec![0x01, 0x00])
335        );
336        assert_eq!(
337            BcdNumber::from_str_strict("101").unwrap(),
338            BcdNumber(vec![0x01, 0x01])
339        );
340        assert_eq!(
341            BcdNumber::from_str_strict("1000").unwrap(),
342            BcdNumber(vec![0x10, 0x00])
343        );
344        assert_eq!(
345            BcdNumber::from_str_strict("1234").unwrap(),
346            BcdNumber(vec![0x12, 0x34])
347        );
348        assert_eq!(
349            BcdNumber::from_str_strict("9999").unwrap(),
350            BcdNumber(vec![0x99, 0x99])
351        );
352        assert_eq!(
353            BcdNumber::from_str_strict("11010").unwrap(),
354            BcdNumber(vec![0x01, 0x10, 0x10])
355        );
356    }
357
358    #[test]
359    fn test_from_str_strict_non_digit_char() {
360        assert!(matches!(
361            BcdNumber::from_str_strict("abcd"),
362            Err(BcdError::NonDigitChar('a'))
363        ));
364    }
365
366    #[test]
367    fn test_to_u64() {
368        assert_eq!(BcdNumber(vec![0x00]).to_u64().unwrap(), 0);
369        assert_eq!(BcdNumber(vec![0x01]).to_u64().unwrap(), 1);
370        assert_eq!(BcdNumber(vec![0x99]).to_u64().unwrap(), 99);
371        assert_eq!(BcdNumber(vec![0x01, 0x00]).to_u64().unwrap(), 100);
372        assert_eq!(BcdNumber(vec![0x01, 0x01]).to_u64().unwrap(), 101);
373        assert_eq!(BcdNumber(vec![0x10, 0x00]).to_u64().unwrap(), 1000);
374        assert_eq!(BcdNumber(vec![0x12, 0x34]).to_u64().unwrap(), 1234);
375        assert_eq!(BcdNumber(vec![0x99, 0x99]).to_u64().unwrap(), 9999);
376        assert_eq!(BcdNumber(vec![0x01, 0x10, 0x10]).to_u64().unwrap(), 11010);
377    }
378
379    #[test]
380    fn test_to_u64_invalid_bcd_nibble() {
381        assert!(matches!(
382            BcdNumber(vec![0x1A, 0xFF]).to_u64(),
383            Err(BcdError::InvalidBcdNibble(0x1A))
384        ));
385    }
386
387    #[test]
388    fn test_to_u64_overflow() {
389        assert!(matches!(
390            BcdNumber(vec![
391                0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
392            ])
393            .to_u64(),
394            Err(BcdError::Overflow)
395        ));
396    }
397
398    #[test]
399    fn test_to_string() {
400        assert_eq!(BcdNumber(vec![0x0]).to_string(), "00");
401        assert_eq!(BcdNumber(vec![0x00]).to_string(), "00");
402        assert_eq!(BcdNumber(vec![0x1]).to_string(), "01");
403        assert_eq!(BcdNumber(vec![0x01]).to_string(), "01");
404        assert_eq!(BcdNumber(vec![0x99]).to_string(), "99");
405        assert_eq!(BcdNumber(vec![0x1, 0x0]).to_string(), "0100");
406        assert_eq!(BcdNumber(vec![0x01, 0x00]).to_string(), "0100");
407        assert_eq!(BcdNumber(vec![0x1, 0x1]).to_string(), "0101");
408        assert_eq!(BcdNumber(vec![0x01, 0x01]).to_string(), "0101");
409        assert_eq!(BcdNumber(vec![0x10, 0x00]).to_string(), "1000");
410        assert_eq!(BcdNumber(vec![0x12, 0x34]).to_string(), "1234");
411        assert_eq!(BcdNumber(vec![0x99, 0x99]).to_string(), "9999");
412        assert_eq!(BcdNumber(vec![0x01, 0x10, 0x10]).to_string(), "011010");
413    }
414
415    #[test]
416    fn test_get_digit() {
417        {
418            let b = BcdNumber(vec![0x0]);
419            assert_eq!(b.get_digit(0), Some(0));
420            assert_eq!(b.get_digit(1), Some(0));
421            assert_eq!(b.get_digit(2), None);
422        }
423        {
424            let b = BcdNumber(vec![0x00]);
425            assert_eq!(b.get_digit(0), Some(0));
426            assert_eq!(b.get_digit(1), Some(0));
427            assert_eq!(b.get_digit(2), None);
428        }
429        {
430            let b = BcdNumber(vec![0x1]);
431            assert_eq!(b.get_digit(0), Some(0));
432            assert_eq!(b.get_digit(1), Some(1));
433            assert_eq!(b.get_digit(2), None);
434        }
435        {
436            let b = BcdNumber(vec![0x01]);
437            assert_eq!(b.get_digit(0), Some(0));
438            assert_eq!(b.get_digit(1), Some(1));
439            assert_eq!(b.get_digit(2), None);
440        }
441        {
442            let b = BcdNumber(vec![0x99]);
443            assert_eq!(b.get_digit(0), Some(9));
444            assert_eq!(b.get_digit(1), Some(9));
445            assert_eq!(b.get_digit(2), None);
446        }
447        {
448            let b = BcdNumber(vec![0x01, 0x00]);
449            assert_eq!(b.get_digit(0), Some(0));
450            assert_eq!(b.get_digit(1), Some(1));
451            assert_eq!(b.get_digit(2), Some(0));
452            assert_eq!(b.get_digit(3), Some(0));
453            assert_eq!(b.get_digit(4), None);
454        }
455        {
456            let b = BcdNumber(vec![0x1, 0x00]);
457            assert_eq!(b.get_digit(0), Some(0));
458            assert_eq!(b.get_digit(1), Some(1));
459            assert_eq!(b.get_digit(2), Some(0));
460            assert_eq!(b.get_digit(3), Some(0));
461            assert_eq!(b.get_digit(4), None);
462        }
463        {
464            let b = BcdNumber(vec![0x01, 0x01]);
465            assert_eq!(b.get_digit(0), Some(0));
466            assert_eq!(b.get_digit(1), Some(1));
467            assert_eq!(b.get_digit(2), Some(0));
468            assert_eq!(b.get_digit(3), Some(1));
469            assert_eq!(b.get_digit(4), None);
470        }
471        {
472            let b = BcdNumber(vec![0x1, 0x01]);
473            assert_eq!(b.get_digit(0), Some(0));
474            assert_eq!(b.get_digit(1), Some(1));
475            assert_eq!(b.get_digit(2), Some(0));
476            assert_eq!(b.get_digit(3), Some(1));
477            assert_eq!(b.get_digit(4), None);
478        }
479        {
480            let b = BcdNumber(vec![0x10, 0x00]);
481            assert_eq!(b.get_digit(0), Some(1));
482            assert_eq!(b.get_digit(1), Some(0));
483            assert_eq!(b.get_digit(2), Some(0));
484            assert_eq!(b.get_digit(3), Some(0));
485            assert_eq!(b.get_digit(4), None);
486        }
487        {
488            let b = BcdNumber(vec![0x12, 0x34]);
489            assert_eq!(b.get_digit(0), Some(1));
490            assert_eq!(b.get_digit(1), Some(2));
491            assert_eq!(b.get_digit(2), Some(3));
492            assert_eq!(b.get_digit(3), Some(4));
493            assert_eq!(b.get_digit(4), None);
494        }
495        {
496            let b = BcdNumber(vec![0x99, 0x99]);
497            assert_eq!(b.get_digit(0), Some(9));
498            assert_eq!(b.get_digit(1), Some(9));
499            assert_eq!(b.get_digit(2), Some(9));
500            assert_eq!(b.get_digit(3), Some(9));
501            assert_eq!(b.get_digit(4), None);
502        }
503        {
504            let b = BcdNumber(vec![0x01, 0x10, 0x10]);
505            assert_eq!(b.get_digit(0), Some(0));
506            assert_eq!(b.get_digit(1), Some(1));
507            assert_eq!(b.get_digit(2), Some(1));
508            assert_eq!(b.get_digit(3), Some(0));
509            assert_eq!(b.get_digit(4), Some(1));
510            assert_eq!(b.get_digit(5), Some(0));
511            assert_eq!(b.get_digit(6), None);
512        }
513    }
514
515    #[test]
516    fn test_from_str() {
517        assert_eq!("0".parse::<BcdNumber>().unwrap(), BcdNumber(vec![0x00]));
518        assert_eq!("00".parse::<BcdNumber>().unwrap(), BcdNumber(vec![0x00]));
519        assert_eq!("1".parse::<BcdNumber>().unwrap(), BcdNumber(vec![0x01]));
520        assert_eq!("01".parse::<BcdNumber>().unwrap(), BcdNumber(vec![0x01]));
521        assert_eq!("99".parse::<BcdNumber>().unwrap(), BcdNumber(vec![0x99]));
522        assert_eq!(
523            "100".parse::<BcdNumber>().unwrap(),
524            BcdNumber(vec![0x01, 0x00])
525        );
526        assert_eq!(
527            "0100".parse::<BcdNumber>().unwrap(),
528            BcdNumber(vec![0x01, 0x00])
529        );
530        assert_eq!(
531            "101".parse::<BcdNumber>().unwrap(),
532            BcdNumber(vec![0x01, 0x01])
533        );
534        assert_eq!(
535            "0101".parse::<BcdNumber>().unwrap(),
536            BcdNumber(vec![0x01, 0x01])
537        );
538        assert_eq!(
539            "1234".parse::<BcdNumber>().unwrap(),
540            BcdNumber(vec![0x12, 0x34])
541        );
542        assert_eq!(
543            "9999".parse::<BcdNumber>().unwrap(),
544            BcdNumber(vec![0x99, 0x99])
545        );
546        assert_eq!(
547            "011010".parse::<BcdNumber>().unwrap(),
548            BcdNumber(vec![0x01, 0x10, 0x10])
549        );
550        assert_eq!(
551            "0001234".parse::<BcdNumber>().unwrap(),
552            BcdNumber(vec![0x12, 0x34])
553        );
554    }
555
556    #[test]
557    fn test_from_str_error() {
558        assert!(matches!(
559            BcdNumber::from_str("abcd"),
560            Err(BcdError::NonDigitChar('a'))
561        ));
562        assert!(matches!(
563            "abcd".parse::<BcdNumber>(),
564            Err(BcdError::NonDigitChar('a'))
565        ));
566    }
567
568    #[test]
569    fn test_try_from_u64() {
570        assert_eq!(u64::try_from(BcdNumber(vec![0x0])).unwrap(), 0);
571        assert_eq!(u64::try_from(BcdNumber(vec![0x00])).unwrap(), 0);
572        assert_eq!(u64::try_from(BcdNumber(vec![0x1])).unwrap(), 1);
573        assert_eq!(u64::try_from(BcdNumber(vec![0x01])).unwrap(), 1);
574        assert_eq!(u64::try_from(BcdNumber(vec![0x99])).unwrap(), 99);
575        assert_eq!(u64::try_from(BcdNumber(vec![0x1, 0x00])).unwrap(), 100);
576        assert_eq!(u64::try_from(BcdNumber(vec![0x01, 0x00])).unwrap(), 100);
577        assert_eq!(u64::try_from(BcdNumber(vec![0x1, 0x01])).unwrap(), 101);
578        assert_eq!(u64::try_from(BcdNumber(vec![0x01, 0x01])).unwrap(), 101);
579        assert_eq!(u64::try_from(BcdNumber(vec![0x10, 0x00])).unwrap(), 1000);
580        assert_eq!(u64::try_from(BcdNumber(vec![0x12, 0x34])).unwrap(), 1234);
581        assert_eq!(u64::try_from(BcdNumber(vec![0x99, 0x99])).unwrap(), 9999);
582        assert_eq!(
583            u64::try_from(BcdNumber(vec![0x01, 0x10, 0x10])).unwrap(),
584            11010
585        );
586    }
587
588    #[test]
589    fn test_try_from_u64_error() {
590        assert!(matches!(
591            u64::try_from(BcdNumber(vec![0x1A, 0xFF])),
592            Err(BcdError::InvalidBcdNibble(0x1A))
593        ));
594    }
595
596    #[test]
597    fn test_from() {
598        assert_eq!(BcdNumber::from(0), BcdNumber(vec![0x00]));
599        assert_eq!(BcdNumber::from(1), BcdNumber(vec![0x01]));
600        assert_eq!(BcdNumber::from(99), BcdNumber(vec![0x99]));
601        assert_eq!(BcdNumber::from(100), BcdNumber(vec![0x01, 0x00]));
602        assert_eq!(BcdNumber::from(101), BcdNumber(vec![0x01, 0x01]));
603        assert_eq!(BcdNumber::from(1000), BcdNumber(vec![0x10, 0x00]));
604        assert_eq!(BcdNumber::from(1234), BcdNumber(vec![0x12, 0x34]));
605        assert_eq!(BcdNumber::from(9999), BcdNumber(vec![0x99, 0x99]));
606        assert_eq!(BcdNumber::from(11010), BcdNumber(vec![0x01, 0x10, 0x10]));
607    }
608
609    #[test]
610    fn test_try_from_slice() {
611        assert_eq!(
612            BcdNumber::try_from(&[0x0][..]).unwrap(),
613            BcdNumber(vec![0x00])
614        );
615        assert_eq!(
616            BcdNumber::try_from(&[0x00][..]).unwrap(),
617            BcdNumber(vec![0x00])
618        );
619        assert_eq!(
620            BcdNumber::try_from(&[0x1][..]).unwrap(),
621            BcdNumber(vec![0x01])
622        );
623        assert_eq!(
624            BcdNumber::try_from(&[0x01][..]).unwrap(),
625            BcdNumber(vec![0x01])
626        );
627        assert_eq!(
628            BcdNumber::try_from(&[0x99][..]).unwrap(),
629            BcdNumber(vec![0x99])
630        );
631        assert_eq!(
632            BcdNumber::try_from(&[0x1, 0x00][..]).unwrap(),
633            BcdNumber(vec![0x01, 0x00])
634        );
635        assert_eq!(
636            BcdNumber::try_from(&[0x01, 0x00][..]).unwrap(),
637            BcdNumber(vec![0x01, 0x00])
638        );
639        assert_eq!(
640            BcdNumber::try_from(&[0x1, 0x01][..]).unwrap(),
641            BcdNumber(vec![0x01, 0x01])
642        );
643        assert_eq!(
644            BcdNumber::try_from(&[0x01, 0x01][..]).unwrap(),
645            BcdNumber(vec![0x01, 0x01])
646        );
647        assert_eq!(
648            BcdNumber::try_from(&[0x10, 0x00][..]).unwrap(),
649            BcdNumber(vec![0x10, 0x00])
650        );
651        assert_eq!(
652            BcdNumber::try_from(&[0x12, 0x34][..]).unwrap(),
653            BcdNumber(vec![0x12, 0x34])
654        );
655        assert_eq!(
656            BcdNumber::try_from(&[0x99, 0x99][..]).unwrap(),
657            BcdNumber(vec![0x99, 0x99])
658        );
659        assert_eq!(
660            BcdNumber::try_from(&[0x01, 0x10, 0x10][..]).unwrap(),
661            BcdNumber(vec![0x01, 0x10, 0x10])
662        );
663    }
664
665    #[test]
666    fn test_try_from_slice_invalid_bcd_nibble() {
667        assert!(matches!(
668            BcdNumber::try_from(&[0xA][..]),
669            Err(BcdError::InvalidBcdNibble(0xA))
670        ));
671    }
672
673    #[test]
674    fn test_format() {
675        let b = BcdNumber(vec![0x01]);
676        let s = format!("Hello, {} !!", b); // s = "Hello, Rust !!"
677        println!("{}", s);
678    }
679}