Coverage Report

Created: 2025-10-10 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/imgref-1.12.0/src/iter.rs
Line
Count
Source
1
use core::iter::FusedIterator;
2
use core::marker::PhantomData;
3
use core::num::NonZeroUsize;
4
use core::slice;
5
6
#[cfg(test)]
7
use alloc::vec;
8
9
/// Rows of the image. Call `Img.rows()` to create it.
10
///
11
/// Each element is a slice `width` pixels wide. Ignores padding, if there's any.
12
#[derive(Debug)]
13
#[must_use]
14
pub struct RowsIter<'a, T> {
15
    pub(crate) inner: slice::Chunks<'a, T>,
16
    pub(crate) width: usize,
17
}
18
19
impl<'a, T: 'a> Iterator for RowsIter<'a, T> {
20
    type Item = &'a [T];
21
22
    #[inline]
23
0
    fn next(&mut self) -> Option<Self::Item> {
24
0
        match self.inner.next() {
25
0
            Some(s) => {
26
                // guaranteed during creation of chunks iterator
27
0
                debug_assert!(s.len() >= self.width);
28
                unsafe {
29
0
                    Some(s.get_unchecked(0..self.width))
30
                }
31
            },
32
0
            None => None,
33
        }
34
0
    }
35
36
    #[inline]
37
0
    fn size_hint(&self) -> (usize, Option<usize>) {
38
0
        self.inner.size_hint()
39
0
    }
40
41
    #[inline]
42
0
    fn nth(&mut self, n: usize) -> Option<Self::Item> {
43
0
        match self.inner.nth(n) {
44
0
            Some(s) => {
45
                // guaranteed during creation of chunks iterator
46
0
                debug_assert!(s.len() >= self.width);
47
                unsafe {
48
0
                    Some(s.get_unchecked(0..self.width))
49
                }
50
            },
51
0
            None => None,
52
        }
53
0
    }
54
55
    #[inline]
56
0
    fn count(self) -> usize {
57
0
        self.inner.count()
58
0
    }
59
}
60
61
impl<T> ExactSizeIterator for RowsIter<'_, T> {
62
    #[inline]
63
0
    fn len(&self) -> usize {
64
0
        self.inner.len()
65
0
    }
66
}
67
68
impl<T> FusedIterator for RowsIter<'_, T> {}
69
70
impl<'a, T: 'a> DoubleEndedIterator for RowsIter<'a, T> {
71
    #[inline]
72
0
    fn next_back(&mut self) -> Option<Self::Item> {
73
0
        match self.inner.next_back() {
74
0
            Some(s) => {
75
                // guaranteed during creation of chunks iterator
76
0
                debug_assert!(s.len() >= self.width);
77
                unsafe {
78
0
                    Some(s.get_unchecked(0..self.width))
79
                }
80
            },
81
0
            None => None,
82
        }
83
0
    }
84
}
85
86
/// Rows of the image. Call `Img.rows_mut()` to create it.
87
///
88
/// Each element is a slice `width` pixels wide. Ignores padding, if there's any.
89
#[derive(Debug)]
90
#[must_use]
91
pub struct RowsIterMut<'a, T> {
92
    pub(crate) width: usize,
93
    pub(crate) inner: slice::ChunksMut<'a, T>,
94
}
95
96
impl<'a, T: 'a> Iterator for RowsIterMut<'a, T> {
97
    type Item = &'a mut [T];
98
99
    #[inline]
100
0
    fn next(&mut self) -> Option<Self::Item> {
101
0
        match self.inner.next() {
102
0
            Some(s) => Some(&mut s[0..self.width]),
103
0
            None => None,
104
        }
105
0
    }
106
107
    #[inline]
108
0
    fn size_hint(&self) -> (usize, Option<usize>) {
109
0
        self.inner.size_hint()
110
0
    }
111
112
    #[inline]
113
0
    fn nth(&mut self, n: usize) -> Option<Self::Item> {
114
0
        match self.inner.nth(n) {
115
0
            Some(s) => Some(&mut s[0..self.width]),
116
0
            None => None,
117
        }
118
0
    }
119
120
    #[inline]
121
0
    fn count(self) -> usize {
122
0
        self.inner.count()
123
0
    }
124
}
125
126
impl<T> ExactSizeIterator for RowsIterMut<'_, T> {}
127
impl<T> FusedIterator for RowsIterMut<'_, T> {}
128
129
impl<'a, T: 'a> DoubleEndedIterator for RowsIterMut<'a, T> {
130
    #[inline]
131
0
    fn next_back(&mut self) -> Option<Self::Item> {
132
0
        match self.inner.next_back() {
133
0
            Some(s) => Some(&mut s[0..self.width]),
134
0
            None => None,
135
        }
136
0
    }
137
}
138
139
/// Iterates over pixels in the (sub)image. Call `Img.pixels()` to create it.
140
///
141
/// Ignores padding, if there's any.
142
#[must_use]
143
pub struct PixelsIter<'a, T: Copy> {
144
    inner: PixelsRefIter<'a, T>,
145
}
146
147
impl<'a, T: Copy + 'a> PixelsIter<'a, T> {
148
    #[inline(always)]
149
    #[track_caller]
150
0
    pub(crate) fn new(img: super::ImgRef<'a, T>) -> Self {
151
0
        Self {
152
0
            inner: PixelsRefIter::new(img)
153
0
        }
154
0
    }
Unexecuted instantiation: <imgref::iter::PixelsIter<rgb::formats::rgba::Rgba<u8>>>::new
Unexecuted instantiation: <imgref::iter::PixelsIter<_>>::new
Unexecuted instantiation: <imgref::iter::PixelsIter<rgb::formats::rgb::Rgb<u8>>>::new
155
}
156
157
impl<'a, T: Copy + 'a> Iterator for PixelsIter<'a, T> {
158
    type Item = T;
159
160
    #[inline(always)]
161
0
    fn next(&mut self) -> Option<Self::Item> {
162
0
        self.inner.next().copied()
163
0
    }
Unexecuted instantiation: <imgref::iter::PixelsIter<rgb::formats::rgba::Rgba<u8>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <imgref::iter::PixelsIter<_> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <imgref::iter::PixelsIter<rgb::formats::rgb::Rgb<u8>> as core::iter::traits::iterator::Iterator>::next
164
}
165
166
impl<T: Copy> ExactSizeIterator for PixelsIter<'_, T> {
167
    #[inline]
168
0
    fn len(&self) -> usize {
169
0
        self.inner.len()
170
0
    }
171
}
172
173
/// Iterates over pixels in the (sub)image. Call `Img.pixels_ref()` to create it.
174
///
175
/// Ignores padding, if there's any.
176
#[derive(Debug)]
177
#[must_use]
178
pub struct PixelsRefIter<'a, T> {
179
    current: *const T,
180
    current_line_end: *const T,
181
    rows_left: usize,
182
    width: NonZeroUsize,
183
    pad: usize,
184
    _dat: PhantomData<&'a [T]>,
185
}
186
187
unsafe impl<T> Send for PixelsRefIter<'_, T> where T: Send {}
188
unsafe impl<T> Sync for PixelsRefIter<'_, T> where T: Sync {}
189
190
impl<'a, T: 'a> PixelsRefIter<'a, T> {
191
    #[inline]
192
    #[track_caller]
193
0
    pub(crate) fn new(img: super::ImgRef<'a, T>) -> Self {
194
0
        let width = NonZeroUsize::new(img.width()).expect("width > 0");
195
0
        let height = img.height();
196
0
        let stride = img.stride();
197
0
        assert!(stride >= width.get());
198
0
        let pad = stride - width.get();
199
0
        debug_assert!(img.buf().len() + stride >= stride * height + width.get(),
200
0
            "buffer len {} is less than {} (({}+{})x{})", img.buf().len(),
201
0
            stride * height - pad, width, pad, height);
202
0
        Self {
203
0
            current: img.buf().as_ptr(),
204
0
            current_line_end: img.buf()[width.get()..].as_ptr(),
205
0
            width,
206
0
            rows_left: height,
207
0
            pad,
208
0
            _dat: PhantomData,
209
0
        }
210
0
    }
Unexecuted instantiation: <imgref::iter::PixelsRefIter<rgb::formats::rgba::Rgba<u8>>>::new
Unexecuted instantiation: <imgref::iter::PixelsRefIter<_>>::new
Unexecuted instantiation: <imgref::iter::PixelsRefIter<rgb::formats::rgb::Rgb<u8>>>::new
211
}
212
213
impl<'a, T: 'a> Iterator for PixelsRefIter<'a, T> {
214
    type Item = &'a T;
215
216
    #[inline(always)]
217
0
    fn next(&mut self) -> Option<Self::Item> {
218
        unsafe {
219
0
            if self.current >= self.current_line_end {
220
0
                if self.rows_left <= 1 {
221
0
                    return None;
222
0
                }
223
0
                self.rows_left -= 1;
224
0
                self.current = self.current_line_end.add(self.pad);
225
0
                self.current_line_end = self.current.add(self.width.get());
226
0
            }
227
0
            let px = &*self.current;
228
0
            self.current = self.current.add(1);
229
0
            Some(px)
230
        }
231
0
    }
Unexecuted instantiation: <imgref::iter::PixelsRefIter<rgb::formats::rgba::Rgba<u8>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <imgref::iter::PixelsRefIter<_> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <imgref::iter::PixelsRefIter<rgb::formats::rgb::Rgb<u8>> as core::iter::traits::iterator::Iterator>::next
232
233
    #[inline]
234
    #[cfg_attr(debug_assertions, track_caller)]
235
0
    fn size_hint(&self) -> (usize, Option<usize>) {
236
0
        let this_line = unsafe {
237
0
            self.current_line_end.offset_from(self.current)
238
        };
239
0
        debug_assert!(this_line >= 0);
240
0
        let len = this_line as usize + (self.rows_left - 1) * self.width.get();
241
0
        (len, Some(len))
242
0
    }
243
}
244
245
impl<T: Copy> ExactSizeIterator for PixelsRefIter<'_, T> {
246
}
247
248
/// Iterates over pixels in the (sub)image. Call `Img.pixels_mut()` to create it.
249
///
250
/// Ignores padding, if there's any.
251
#[derive(Debug)]
252
#[must_use]
253
pub struct PixelsIterMut<'a, T> {
254
    current: *mut T,
255
    current_line_end: *mut T,
256
    y: usize,
257
    width: NonZeroUsize,
258
    pad: usize,
259
    _dat: PhantomData<&'a mut [T]>,
260
}
261
262
unsafe impl<T> Send for PixelsIterMut<'_, T> where T: Send {}
263
unsafe impl<T> Sync for PixelsIterMut<'_, T> where T: Sync {}
264
265
impl<'a, T: 'a> PixelsIterMut<'a, T> {
266
    #[inline]
267
    #[track_caller]
268
0
    pub(crate) fn new(img: &mut super::ImgRefMut<'a, T>) -> Self {
269
0
        let width = NonZeroUsize::new(img.width()).expect("width > 0");
270
0
        let stride = img.stride();
271
0
        debug_assert!(!img.buf().is_empty() && img.buf().len() + stride >= stride * img.height() + width.get());
272
0
        Self {
273
0
            current: img.buf_mut().as_mut_ptr(),
274
0
            current_line_end: img.buf_mut()[width.get()..].as_mut_ptr(),
275
0
            width,
276
0
            y: img.height(),
277
0
            pad: stride - width.get(),
278
0
            _dat: PhantomData,
279
0
        }
280
0
    }
281
}
282
283
impl<'a, T: 'a> Iterator for PixelsIterMut<'a, T> {
284
    type Item = &'a mut T;
285
286
    #[inline(always)]
287
0
    fn next(&mut self) -> Option<Self::Item> {
288
        unsafe {
289
0
            if self.current >= self.current_line_end {
290
0
                self.y -= 1;
291
0
                if self.y == 0 {
292
0
                    return None;
293
0
                }
294
0
                self.current = self.current_line_end.add(self.pad);
295
0
                self.current_line_end = self.current.add(self.width.get());
296
0
            }
297
0
            let px = &mut *self.current;
298
0
            self.current = self.current.add(1);
299
0
            Some(px)
300
        }
301
0
    }
302
}
303
304
#[test]
305
fn iter() {
306
    let img = super::Img::new(vec![1u8, 2], 1, 2);
307
    let mut it = img.pixels();
308
    assert_eq!(Some(1), it.next());
309
    assert_eq!(Some(2), it.next());
310
    assert_eq!(None, it.next());
311
312
    let buf = [1u8; (16 + 3) * (8 + 1)];
313
    for width in 1..16 {
314
        for height in 1..8 {
315
            for pad in 0..3 {
316
                let stride = width + pad;
317
                let img = super::Img::new_stride(&buf[..stride * height + stride - width], width, height, stride);
318
                assert_eq!(width * height, img.pixels().map(|a| a as usize).sum(), "{width}x{height}");
319
                assert_eq!(width * height, img.pixels().count(), "{width}x{height}");
320
                assert_eq!(height, img.rows().count());
321
322
                let mut iter1 = img.pixels();
323
                let mut left = width * height;
324
                while let Some(_px) = iter1.next() {
325
                    left -= 1;
326
                    assert_eq!(left, iter1.len());
327
                }
328
                assert_eq!(0, iter1.len());
329
                iter1.next();
330
                assert_eq!(0, iter1.len());
331
332
                let mut iter2 = img.rows();
333
                match iter2.next() {
334
                    Some(_) => {
335
                        assert_eq!(height - 1, iter2.size_hint().0);
336
                        assert_eq!(height - 1, iter2.filter(|_| true).count());
337
                    },
338
                    None => {
339
                        assert_eq!(height, 0);
340
                    },
341
                };
342
            }
343
        }
344
    }
345
}