Skip to main content

orx_concurrent_iter/chain/
con_iter_unknown_len_i.rs

1use crate::{
2    ConcurrentIter, ExactSizeConcurrentIter,
3    chain::chunk_puller_unknown_len_i::ChainedChunkPullerUnknownLenI,
4};
5use core::sync::atomic::{AtomicUsize, Ordering};
6
7/// Chain of two concurrent iterators where the length of the first iterator is not
8/// known with certainly; i.e., `I` does not implement `ExactSizeConcurrentIter`.
9pub struct ChainUnknownLenI<I, J>
10where
11    I: ConcurrentIter,
12    J: ConcurrentIter<Item = I::Item>,
13{
14    pub(super) i: I,
15    pub(super) j: J,
16    pub(super) num_pulled_i: AtomicUsize,
17}
18
19impl<I, J> ChainUnknownLenI<I, J>
20where
21    I: ConcurrentIter,
22    J: ConcurrentIter<Item = I::Item>,
23{
24    pub(crate) fn new(i: I, j: J) -> Self {
25        Self {
26            i,
27            j,
28            num_pulled_i: 0.into(),
29        }
30    }
31
32    #[inline(always)]
33    pub(super) fn num_pulled_i(&self) -> usize {
34        self.num_pulled_i.load(Ordering::SeqCst)
35    }
36}
37
38impl<I, J> ConcurrentIter for ChainUnknownLenI<I, J>
39where
40    I: ConcurrentIter,
41    J: ConcurrentIter<Item = I::Item>,
42{
43    type Item = I::Item;
44
45    type SequentialIter = core::iter::Chain<I::SequentialIter, J::SequentialIter>;
46
47    type ChunkPuller<'i>
48        = ChainedChunkPullerUnknownLenI<'i, I, J>
49    where
50        Self: 'i;
51
52    fn is_source_serialized() -> bool {
53        I::is_source_serialized() || J::is_source_serialized()
54    }
55
56    fn into_seq_iter(self) -> Self::SequentialIter {
57        self.i.into_seq_iter().chain(self.j.into_seq_iter())
58    }
59
60    fn skip_to_end(&self) {
61        self.i.skip_to_end();
62        self.j.skip_to_end();
63    }
64
65    fn next(&self) -> Option<Self::Item> {
66        match self.i.next() {
67            Some(x) => {
68                _ = self.num_pulled_i.fetch_add(1, Ordering::SeqCst);
69                Some(x)
70            }
71            None => self.j.next(),
72        }
73    }
74
75    fn next_with_idx(&self) -> Option<(usize, Self::Item)> {
76        match self.i.next_with_idx() {
77            Some((idx, x)) => {
78                _ = self.num_pulled_i.fetch_add(1, Ordering::SeqCst);
79                Some((idx, x))
80            }
81            None => self
82                .j
83                .next_with_idx()
84                .map(|(idx, x)| (self.num_pulled_i() + idx, x)),
85        }
86    }
87
88    fn size_hint(&self) -> (usize, Option<usize>) {
89        let (l1, u1) = self.i.size_hint();
90        let (l2, u2) = self.j.size_hint();
91        match (u1, u2) {
92            (Some(u1), Some(u2)) => (l1 + l2, Some(u1 + u2)),
93            _ => (l1 + l2, None),
94        }
95    }
96
97    fn is_completed_when_none_returned(&self) -> bool {
98        true
99    }
100
101    fn chunk_puller(&self, chunk_size: usize) -> Self::ChunkPuller<'_> {
102        ChainedChunkPullerUnknownLenI::new(self, chunk_size)
103    }
104}
105
106impl<I, J> ExactSizeConcurrentIter for ChainUnknownLenI<I, J>
107where
108    I: ExactSizeConcurrentIter,
109    J: ExactSizeConcurrentIter<Item = I::Item>,
110{
111    fn len(&self) -> usize {
112        self.i.len() + self.j.len()
113    }
114}