1use core::iter::{FusedIterator, Iterator};
6
7pub struct BCDBuffer {
18 pub bytes: [u8; 20],
19 pub i: u8,
20}
21
22impl BCDBuffer {
23 #[inline]
25 pub fn new() -> Self {
26 BCDBuffer {
27 bytes: [0; 20],
28 i: 0,
29 }
30 }
31
32 pub fn push_str(&mut self, s: &str) {
36 debug_assert!(s.is_ascii(), "non-ascii passed into BCDBuffer::push_str");
37 s.bytes().for_each(|b| self.push_digit_u8(b));
38 }
39
40 pub fn push_ascii_bytes(&mut self, bytes: &[u8]) {
44 debug_assert!(
45 bytes.is_ascii(),
46 "non-ascii passed into BCDBuffer::push_ascii_bytes"
47 );
48 bytes.iter().for_each(|b| self.push_digit_u8(*b));
49 }
50
51 pub fn push_digit_u8(&mut self, b: u8) {
55 debug_assert!(
56 b.is_ascii_digit(),
57 "non-ascii digit passed into BCDBuffer::push_digit_u8"
58 );
59 let nybble: u8 = b.saturating_sub(0x30);
60 self.push_nybble(nybble);
61 }
62
63 pub fn push_nybble(&mut self, n: u8) {
70 let byte_index = self.i >> 1;
71 if (self.i % 2) > 0 {
72 self.bytes[byte_index as usize] |= n;
74 } else {
75 self.bytes[byte_index as usize] |= n << 4;
76 }
77 self.i += 1;
78 self.i = self.i.clamp(0, 39);
79 }
80
81 pub fn push_byte(&mut self, byte: u8) {
88 let byte_index = self.len_in_bytes();
89 self.bytes[byte_index] = byte;
90 self.i += if (self.i % 2) > 0 { 3 } else { 2 };
91 self.i = self.i.clamp(0, 39);
92 }
93
94 pub fn len_in_bytes(&self) -> usize {
96 ((self.i >> 1) + (self.i % 2)) as usize
97 }
98}
99
100impl AsRef<[u8]> for BCDBuffer {
101 fn as_ref(&self) -> &[u8] {
104 &self.bytes[0..self.len_in_bytes()]
105 }
106}
107
108#[derive(Debug, Clone)]
110pub struct BCDDigitsIter<'a> {
111 bytes: &'a [u8],
112 least_sig_nybble: bool,
113 leading_0_sig: bool,
114 processing_leading_digits: bool,
115 ignore_last_nybble: bool,
116}
117
118impl<'a> BCDDigitsIter<'a> {
119 #[inline]
121 pub fn new(
122 bytes: &'a [u8],
123 leading_0_sig: bool,
124 ignore_last_nybble: bool,
125 least_sig_nybble: bool,
126 processing_leading_digits: bool,
127 ) -> BCDDigitsIter<'a> {
128 BCDDigitsIter {
129 bytes,
130 leading_0_sig,
131 ignore_last_nybble,
132 processing_leading_digits, least_sig_nybble, }
135 }
136}
137
138pub type ShouldBeASCIIDigit = u8;
143
144impl<'a> Iterator for BCDDigitsIter<'a> {
145 type Item = ShouldBeASCIIDigit;
146
147 fn next(&mut self) -> Option<Self::Item> {
150 while self.bytes.len() > 0 {
151 let nybble: u8 = if self.least_sig_nybble {
152 self.bytes[0] & 0b0000_1111
153 } else {
154 (self.bytes[0] & 0b1111_0000) >> 4
155 };
156 if self.least_sig_nybble {
157 self.least_sig_nybble = false;
158 self.bytes = &self.bytes[1..];
159 } else {
160 self.least_sig_nybble = true;
161 }
162 if self.processing_leading_digits {
163 let leading_digit: u8 = if self.leading_0_sig { 1 } else { 0 };
164 if nybble == leading_digit {
165 continue;
166 } else {
167 self.processing_leading_digits = false;
168 }
169 }
170 if self.bytes.len() == 0 && (nybble == 0b1111 || self.ignore_last_nybble) {
173 return None;
174 }
175 return Some(nybble);
176 }
177 None
178 }
179
180 fn size_hint(&self) -> (usize, Option<usize>) {
181 let mut max_digits = self.bytes.len() << 1; if self.least_sig_nybble {
183 max_digits = max_digits.saturating_sub(1);
184 }
185 if self.ignore_last_nybble {
186 max_digits = max_digits.saturating_sub(1);
187 }
188 (0, Some(max_digits))
190 }
191}
192
193impl<'a> FusedIterator for BCDDigitsIter<'a> {}
194
195#[cfg(test)]
196mod tests {
197 use crate::bcd::BCDBuffer;
198
199 #[test]
200 fn test_bcd_buffer_1() {
201 let mut bcd = BCDBuffer::new();
202 assert_eq!(bcd.len_in_bytes(), 0);
203 bcd.push_digit_u8(b'9');
204 assert_eq!(bcd.len_in_bytes(), 1);
205 bcd.push_digit_u8(0x37);
206 assert_eq!(bcd.len_in_bytes(), 1);
207 bcd.push_nybble(0x05);
208 assert_eq!(bcd.len_in_bytes(), 2);
209 bcd.push_byte(0x33);
210 assert_eq!(bcd.len_in_bytes(), 3);
211 assert_eq!(bcd.as_ref(), [0x97, 0x50, 0x33].as_slice());
212 assert_eq!(bcd.len_in_bytes(), 3);
213 }
214
215 #[test]
216 fn test_bcd_buffer_2() {
217 let mut bcd = BCDBuffer::new();
218 assert_eq!(bcd.len_in_bytes(), 0);
219 bcd.push_digit_u8(0x39);
220 assert_eq!(bcd.len_in_bytes(), 1);
221 bcd.push_ascii_bytes([0x37, 0x35].as_slice());
222 assert_eq!(bcd.len_in_bytes(), 2);
223 bcd.push_str("31");
224 assert_eq!(bcd.len_in_bytes(), 3);
225 bcd.push_nybble(0xF);
226 assert_eq!(bcd.len_in_bytes(), 3);
227 assert_eq!(bcd.as_ref(), [0x97, 0x53, 0x1F].as_slice());
228 assert_eq!(bcd.len_in_bytes(), 3);
229 }
230}