Skip to main content

bitcoin_consensus_encoding/encode/
iter.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::fmt;
4
5use super::{Encode, Encoder, EncoderStatus};
6
7/// An iterator bridge which maps consensus encodable items to its encoder.
8///
9/// This type is a wrapper around [`core::slice::Iter`] that bridges it to the [`IterEncoder`]
10/// driver. This allows drivers such as [`SliceEncoder`] to store an [`IterEncoder`] with a
11/// nameable type.
12///
13/// [`SliceEncoder`]: super::encoders::SliceEncoder
14pub(super) struct Encoders<'e, T: Encode> {
15    iter: core::slice::Iter<'e, T>,
16}
17
18impl<'e, T: Encode> Encoders<'e, T> {
19    pub(super) fn new(sl: &'e [T]) -> Self { Self { iter: sl.iter() } }
20}
21
22impl<'e, T: Encode> Iterator for Encoders<'e, T> {
23    type Item = T::Encoder<'e>;
24    fn next(&mut self) -> Option<T::Encoder<'e>> {
25        // A closure is required since MSRV (1.74.0) cannot infer the `Self: 'e` GAT bound on
26        // `Encode::encoder` when passed as a bare function item here.
27        #[allow(clippy::redundant_closure_for_method_calls)]
28        self.iter.next().map(|item| item.encoder())
29    }
30}
31
32impl<'e, T: Encode> fmt::Debug for Encoders<'e, T> {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        f.debug_struct("Encoders").field("remaining", &self.iter.as_slice().len()).finish()
35    }
36}
37
38impl<'e, T: Encode> Clone for Encoders<'e, T> {
39    fn clone(&self) -> Self { Self { iter: self.iter.clone() } }
40}
41
42enum EncoderState<I: Iterator>
43where
44    I::Item: Encoder,
45{
46    Encoding { current: I::Item, remaining: core::iter::Fuse<I> },
47    Done,
48}
49
50/// An encoder that drives a sequence of encoders yielded by an iterator.
51///
52/// Items are encoded one after another with no separators.
53pub struct IterEncoder<I: Iterator>
54where
55    I::Item: Encoder,
56{
57    state: EncoderState<I>,
58}
59
60impl<I: Iterator> IterEncoder<I>
61where
62    I::Item: Encoder,
63{
64    /// Constructs an `IterEncoder` from anything that can produce an iterator of encoders.
65    pub fn new(iter: impl IntoIterator<IntoIter = I>) -> Self {
66        // Protect against poorly implemented iterators.
67        let mut iter = iter.into_iter().fuse();
68        // Advance past any leading empty encoders so that the first call to
69        // `current_chunk` satisfies the `Encoder` contract that it must return
70        // non-empty bytes or the encoder must be `Done`.
71        let state = loop {
72            match iter.next() {
73                Some(enc) if !enc.current_chunk().is_empty() =>
74                    break EncoderState::Encoding { current: enc, remaining: iter },
75                Some(_) => {}
76                None => break EncoderState::Done,
77            }
78        };
79        Self { state }
80    }
81}
82
83impl<I: Iterator> fmt::Debug for IterEncoder<I>
84where
85    I::Item: Encoder + fmt::Debug,
86{
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match &self.state {
89            EncoderState::Encoding { current, .. } =>
90                f.debug_struct("IterEncoder").field("current", current).finish(),
91            EncoderState::Done => f.debug_struct("IterEncoder").finish(),
92        }
93    }
94}
95
96impl<I: Iterator> Clone for IterEncoder<I>
97where
98    I: Clone,
99    I::Item: Encoder + Clone,
100{
101    fn clone(&self) -> Self {
102        let state = match &self.state {
103            EncoderState::Encoding { current, remaining } =>
104                EncoderState::Encoding { current: current.clone(), remaining: remaining.clone() },
105            EncoderState::Done => EncoderState::Done,
106        };
107        Self { state }
108    }
109}
110
111impl<I: Iterator> Encoder for IterEncoder<I>
112where
113    I::Item: Encoder,
114{
115    fn current_chunk(&self) -> &[u8] {
116        match &self.state {
117            EncoderState::Encoding { current, .. } => current.current_chunk(),
118            EncoderState::Done => &[],
119        }
120    }
121
122    fn advance(&mut self) -> EncoderStatus {
123        let EncoderState::Encoding { current, remaining } = &mut self.state else {
124            return EncoderStatus::Finished;
125        };
126
127        loop {
128            if current.advance().has_more() {
129                return EncoderStatus::HasMore;
130            }
131
132            if let Some(next) = remaining.next() {
133                *current = next;
134                // If the next encoder is empty, skip in order to maintain `Encoder` contract
135                // that it must return non-empty bytes or the encoder must be `Done`
136                if !current.current_chunk().is_empty() {
137                    return EncoderStatus::HasMore;
138                }
139            } else {
140                self.state = EncoderState::Done;
141                return EncoderStatus::Finished;
142            }
143        }
144    }
145}