1use core::iter::Iterator;
44use core::marker::PhantomData;
45
46use crate::primitives::checksum::HrpFe32Iter;
47use crate::primitives::hrp::{self, Hrp};
48use crate::primitives::iter::Checksummed;
49use crate::{Checksum, Fe32};
50
51#[derive(Clone, PartialEq, Eq)]
74pub struct Encoder<'hrp, I, Ck>
75where
76 I: Iterator<Item = Fe32>,
77 Ck: Checksum,
78{
79 data: I,
81 hrp: &'hrp Hrp,
83 witness_version: Option<Fe32>,
85 marker: PhantomData<Ck>,
87}
88
89impl<'hrp, I, Ck> Encoder<'hrp, I, Ck>
90where
91 I: Iterator<Item = Fe32>,
92 Ck: Checksum,
93{
94 #[inline]
96 pub fn new(data: I, hrp: &'hrp Hrp) -> Self {
97 Self { data, hrp, witness_version: None, marker: PhantomData::<Ck> }
98 }
99
100 #[inline]
104 pub fn with_witness_version(mut self, witness_version: Fe32) -> Self {
105 self.witness_version = Some(witness_version);
106 self
107 }
108
109 #[inline]
111 pub fn chars(self) -> CharIter<'hrp, I, Ck> {
112 let witver_iter = WitnessVersionIter::new(self.witness_version, self.data);
113 CharIter::new(self.hrp, witver_iter)
114 }
115
116 #[inline]
119 pub fn bytes(self) -> ByteIter<'hrp, I, Ck> {
120 let char_iter = self.chars();
121 ByteIter::new(char_iter)
122 }
123
124 #[inline]
128 pub fn fes(self) -> Fe32Iter<'hrp, I, Ck> {
129 let witver_iter = WitnessVersionIter::new(self.witness_version, self.data);
130 Fe32Iter::new(self.hrp, witver_iter)
131 }
132}
133
134pub struct WitnessVersionIter<I>
138where
139 I: Iterator<Item = Fe32>,
140{
141 witness_version: Option<Fe32>,
142 iter: I,
143}
144
145impl<I> WitnessVersionIter<I>
146where
147 I: Iterator<Item = Fe32>,
148{
149 #[inline]
151 pub fn new(witness_version: Option<Fe32>, iter: I) -> Self { Self { witness_version, iter } }
152}
153
154impl<I> Iterator for WitnessVersionIter<I>
155where
156 I: Iterator<Item = Fe32>,
157{
158 type Item = Fe32;
159
160 #[inline]
161 fn next(&mut self) -> Option<Fe32> { self.witness_version.take().or_else(|| self.iter.next()) }
162
163 #[inline]
164 fn size_hint(&self) -> (usize, Option<usize>) {
165 let (min, max) = self.iter.size_hint();
166 match self.witness_version {
167 Some(_) => (min + 1, max.map(|max| max + 1)),
168 None => (min, max),
169 }
170 }
171}
172
173pub struct CharIter<'hrp, I, Ck>
177where
178 I: Iterator<Item = Fe32>,
179 Ck: Checksum,
180{
181 hrp_iter: Option<hrp::LowercaseCharIter<'hrp>>,
183 checksummed: Checksummed<WitnessVersionIter<I>, Ck>,
186}
187
188impl<'hrp, I, Ck> CharIter<'hrp, I, Ck>
189where
190 I: Iterator<Item = Fe32>,
191 Ck: Checksum,
192{
193 #[inline]
195 pub fn new(hrp: &'hrp Hrp, data: WitnessVersionIter<I>) -> Self {
196 let checksummed = Checksummed::new_hrp(*hrp, data);
197 Self { hrp_iter: Some(hrp.lowercase_char_iter()), checksummed }
198 }
199}
200
201impl<'a, I, Ck> Iterator for CharIter<'a, I, Ck>
202where
203 I: Iterator<Item = Fe32>,
204 Ck: Checksum,
205{
206 type Item = char;
207
208 #[inline]
209 fn next(&mut self) -> Option<char> {
210 if let Some(ref mut hrp_iter) = self.hrp_iter {
211 match hrp_iter.next() {
212 Some(c) => return Some(c),
213 None => {
214 self.hrp_iter = None;
215 return Some('1');
216 }
217 }
218 }
219
220 self.checksummed.next().map(|fe| fe.to_char())
221 }
222
223 #[inline]
224 fn size_hint(&self) -> (usize, Option<usize>) {
225 match &self.hrp_iter {
226 None => self.checksummed.size_hint(),
228 Some(hrp_iter) => {
230 let (hrp_min, hrp_max) = hrp_iter.size_hint();
231 let (chk_min, chk_max) = self.checksummed.size_hint();
232
233 let min = hrp_min + 1 + chk_min; let max = match (hrp_max, chk_max) {
238 (Some(hrp_max), Some(chk_max)) => Some(hrp_max + 1 + chk_max),
239 (_, _) => None,
240 };
241
242 (min, max)
243 }
244 }
245 }
246}
247
248pub struct ByteIter<'hrp, I, Ck>
254where
255 I: Iterator<Item = Fe32>,
256 Ck: Checksum,
257{
258 char_iter: CharIter<'hrp, I, Ck>,
259}
260
261impl<'hrp, I, Ck> ByteIter<'hrp, I, Ck>
262where
263 I: Iterator<Item = Fe32>,
264 Ck: Checksum,
265{
266 #[inline]
268 pub fn new(char_iter: CharIter<'hrp, I, Ck>) -> Self { Self { char_iter } }
269}
270
271impl<'a, I, Ck> Iterator for ByteIter<'a, I, Ck>
272where
273 I: Iterator<Item = Fe32>,
274 Ck: Checksum,
275{
276 type Item = u8;
277
278 #[inline]
279 fn next(&mut self) -> Option<u8> { self.char_iter.next().map(|c| c as u8) }
280
281 #[inline]
282 fn size_hint(&self) -> (usize, Option<usize>) { self.char_iter.size_hint() }
283}
284
285pub struct Fe32Iter<'hrp, I, Ck>
288where
289 I: Iterator<Item = Fe32>,
290 Ck: Checksum,
291{
292 hrp_iter: Option<HrpFe32Iter<'hrp>>,
294 checksummed: Checksummed<WitnessVersionIter<I>, Ck>,
297}
298
299impl<'hrp, I, Ck> Fe32Iter<'hrp, I, Ck>
300where
301 I: Iterator<Item = Fe32>,
302 Ck: Checksum,
303{
304 #[inline]
306 pub fn new(hrp: &'hrp Hrp, data: WitnessVersionIter<I>) -> Self {
307 let hrp_iter = HrpFe32Iter::new(hrp);
308 let checksummed = Checksummed::new_hrp(*hrp, data);
309 Self { hrp_iter: Some(hrp_iter), checksummed }
310 }
311}
312
313impl<'hrp, I, Ck> Iterator for Fe32Iter<'hrp, I, Ck>
314where
315 I: Iterator<Item = Fe32>,
316 Ck: Checksum,
317{
318 type Item = Fe32;
319 #[inline]
320 fn next(&mut self) -> Option<Fe32> {
321 if let Some(ref mut hrp_iter) = &mut self.hrp_iter {
322 match hrp_iter.next() {
323 Some(fe) => return Some(fe),
324 None => self.hrp_iter = None,
325 }
326 }
327 self.checksummed.next()
328 }
329
330 #[inline]
331 fn size_hint(&self) -> (usize, Option<usize>) {
332 let hrp = match &self.hrp_iter {
333 Some(hrp_iter) => hrp_iter.size_hint(),
334 None => (0, Some(0)),
335 };
336
337 let data = self.checksummed.size_hint();
338
339 let min = hrp.0 + data.0;
340 let max = hrp.1.zip(data.1).map(|(hrp, data)| hrp + data);
341
342 (min, max)
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use crate::{Bech32, ByteIterExt, Fe32, Fe32IterExt, Hrp};
349
350 #[rustfmt::skip]
353 const DATA: [u8; 20] = [
354 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4,
355 0x54, 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23,
356 0xf1, 0x43, 0x3b, 0xd6,
357 ];
358
359 #[test]
360 fn hrpstring_iter() {
361 let iter = DATA.iter().copied().bytes_to_fes();
362
363 let hrp = Hrp::parse_unchecked("bc");
364 let iter = iter.with_checksum::<Bech32>(&hrp).with_witness_version(Fe32::Q).chars();
365
366 assert!(iter.eq("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4".chars()));
367 }
368
369 #[test]
370 #[cfg(feature = "alloc")]
371 fn hrpstring_iter_collect() {
372 let iter = DATA.iter().copied().bytes_to_fes();
373
374 let hrp = Hrp::parse_unchecked("bc");
375 let iter = iter.with_checksum::<Bech32>(&hrp).with_witness_version(Fe32::Q).chars();
376
377 let encoded = iter.collect::<String>();
378 assert_eq!(encoded, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4");
379 }
380
381 #[test]
382 fn hrpstring_iter_size_hint() {
383 let char_len = "w508d6qejxtdg4y5r3zarvary0c5xw7k".len();
384 let iter = DATA.iter().copied().bytes_to_fes();
385
386 let hrp = Hrp::parse_unchecked("bc");
387 let iter = iter.with_checksum::<Bech32>(&hrp).with_witness_version(Fe32::Q).chars();
388
389 let checksummed_len = 2 + 1 + 1 + char_len + 6; assert_eq!(iter.size_hint().0, checksummed_len);
391 }
392
393 #[test]
394 #[cfg(feature = "alloc")]
395 fn hrpstring_iter_bytes() {
396 let hrp = Hrp::parse_unchecked("bc");
397 let fes = DATA.iter().copied().bytes_to_fes();
398 let iter = fes.with_checksum::<Bech32>(&hrp).with_witness_version(Fe32::Q);
399
400 let chars = iter.clone().chars();
401 let bytes = iter.bytes();
402
403 for (c, b) in chars.zip(bytes) {
404 assert_eq!(c as u8, b)
405 }
406 }
407}