lender/adapters/
chunky.rs1use core::ops::ControlFlow;
2
3use crate::{
4 Chunk, ExactSizeFallibleLender, ExactSizeLender, FallibleLender, FusedLender, Lend, Lender,
5 Lending, try_trait_v2::Try,
6};
7
8#[derive(Debug, Clone)]
40#[must_use = "lenders are lazy and do nothing unless consumed"]
41pub struct Chunky<L> {
42 pub(crate) lender: L,
43 pub(crate) chunk_size: usize,
44 pub(crate) len: usize,
45}
46
47impl<L> Chunky<L>
48where
49 L: Lender + ExactSizeLender,
50{
51 #[inline]
52 pub(crate) fn new(lender: L, chunk_size: usize) -> Self {
53 let _ = L::__check_covariance(crate::CovariantProof::new());
54 assert!(chunk_size != 0, "chunk size must be non-zero");
55 let len = lender.len().div_ceil(chunk_size);
56 Self {
57 lender,
58 chunk_size,
59 len,
60 }
61 }
62}
63
64impl<L> Chunky<L>
65where
66 L: FallibleLender + ExactSizeFallibleLender,
67{
68 #[inline]
69 pub(crate) fn new_fallible(lender: L, chunk_size: usize) -> Self {
70 let _ = L::__check_covariance(crate::CovariantProof::new());
71 assert!(chunk_size != 0, "chunk size must be non-zero");
72 let len = lender.len().div_ceil(chunk_size);
73 Self {
74 lender,
75 chunk_size,
76 len,
77 }
78 }
79}
80
81impl<L> Chunky<L> {
82 #[inline(always)]
84 pub fn into_inner(self) -> L {
85 self.lender
86 }
87
88 #[inline(always)]
90 pub fn into_parts(self) -> (L, usize) {
91 (self.lender, self.chunk_size)
92 }
93}
94
95impl<'lend, L> Lending<'lend> for Chunky<L>
96where
97 L: Lender,
98{
99 type Lend = Chunk<'lend, L>;
100}
101
102impl<L> Lender for Chunky<L>
103where
104 L: Lender,
105{
106 crate::unsafe_assume_covariance!();
108 #[inline]
109 fn next(&mut self) -> Option<Lend<'_, Self>> {
110 if self.len > 0 {
111 self.len -= 1;
112 Some(self.lender.next_chunk(self.chunk_size))
113 } else {
114 None
115 }
116 }
117
118 #[inline]
119 fn nth(&mut self, n: usize) -> Option<Lend<'_, Self>> {
120 if n < self.len {
121 let skip = n
123 .checked_mul(self.chunk_size)
124 .expect("overflow in Chunky::nth");
125 self.len -= n;
126 if self.lender.advance_by(skip).is_err() {
127 unreachable!();
128 }
129 self.next()
130 } else {
131 if self.len > 0 {
133 let skip = self
134 .len
135 .checked_mul(self.chunk_size)
136 .expect("overflow in Chunky::nth");
137 let _ = self.lender.advance_by(skip);
138 self.len = 0;
139 }
140 None
141 }
142 }
143
144 #[inline(always)]
145 fn size_hint(&self) -> (usize, Option<usize>) {
146 (self.len, Some(self.len))
147 }
148
149 #[inline(always)]
150 fn count(self) -> usize {
151 self.len
152 }
153
154 #[inline]
155 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
156 where
157 Self: Sized,
158 F: FnMut(B, Lend<'_, Self>) -> R,
159 R: Try<Output = B>,
160 {
161 let mut acc = init;
162 let sz = self.chunk_size;
163 while self.len > 0 {
164 self.len -= 1;
165 acc = match f(acc, self.lender.next_chunk(sz)).branch() {
166 ControlFlow::Break(x) => return R::from_residual(x),
167 ControlFlow::Continue(x) => x,
168 };
169 }
170 R::from_output(acc)
171 }
172
173 #[inline]
174 fn fold<B, F>(mut self, init: B, mut f: F) -> B
175 where
176 Self: Sized,
177 F: FnMut(B, Lend<'_, Self>) -> B,
178 {
179 let mut accum = init;
180 let sz = self.chunk_size;
181 while self.len > 0 {
182 self.len -= 1;
183 accum = f(accum, self.lender.next_chunk(sz));
184 }
185 accum
186 }
187}
188
189impl<L> FusedLender for Chunky<L> where L: FusedLender {}
190
191