1use alloc::vec::Vec;
2use core::fmt;
3use core::ops::{Deref, DerefMut};
4use rayon::iter::plumbing::*;
5use rayon::iter::{IndexedParallelIterator, ParallelIterator};
6use rayon::slice::{ChunksExact, ChunksExactMut, ParallelSlice, ParallelSliceMut};
7
8use crate::traits::Pixel;
9use crate::ImageBuffer;
10
11#[derive(Clone)]
13pub struct PixelsPar<'a, P>
14where
15 P: Pixel + Sync + 'a,
16 P::Subpixel: Sync + 'a,
17{
18 chunks: ChunksExact<'a, P::Subpixel>,
19}
20
21impl<'a, P> ParallelIterator for PixelsPar<'a, P>
22where
23 P: Pixel + Sync + 'a,
24 P::Subpixel: Sync + 'a,
25{
26 type Item = &'a P;
27
28 fn drive_unindexed<C>(self, consumer: C) -> C::Result
29 where
30 C: UnindexedConsumer<Self::Item>,
31 {
32 self.chunks
33 .map(|v| <P as Pixel>::from_slice(v))
34 .drive_unindexed(consumer)
35 }
36
37 fn opt_len(&self) -> Option<usize> {
38 Some(self.len())
39 }
40}
41
42impl<'a, P> IndexedParallelIterator for PixelsPar<'a, P>
43where
44 P: Pixel + Sync + 'a,
45 P::Subpixel: Sync + 'a,
46{
47 fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
48 self.chunks
49 .map(|v| <P as Pixel>::from_slice(v))
50 .drive(consumer)
51 }
52
53 fn len(&self) -> usize {
54 self.chunks.len()
55 }
56
57 fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output {
58 self.chunks
59 .map(|v| <P as Pixel>::from_slice(v))
60 .with_producer(callback)
61 }
62}
63
64impl<P> fmt::Debug for PixelsPar<'_, P>
65where
66 P: Pixel + Sync,
67 P::Subpixel: Sync + fmt::Debug,
68{
69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 f.debug_struct("PixelsPar")
71 .field("chunks", &self.chunks)
72 .finish()
73 }
74}
75
76pub struct PixelsMutPar<'a, P>
78where
79 P: Pixel + Send + Sync + 'a,
80 P::Subpixel: Send + Sync + 'a,
81{
82 chunks: ChunksExactMut<'a, P::Subpixel>,
83}
84
85impl<'a, P> ParallelIterator for PixelsMutPar<'a, P>
86where
87 P: Pixel + Send + Sync + 'a,
88 P::Subpixel: Send + Sync + 'a,
89{
90 type Item = &'a mut P;
91
92 fn drive_unindexed<C>(self, consumer: C) -> C::Result
93 where
94 C: UnindexedConsumer<Self::Item>,
95 {
96 self.chunks
97 .map(|v| <P as Pixel>::from_slice_mut(v))
98 .drive_unindexed(consumer)
99 }
100
101 fn opt_len(&self) -> Option<usize> {
102 Some(self.len())
103 }
104}
105
106impl<'a, P> IndexedParallelIterator for PixelsMutPar<'a, P>
107where
108 P: Pixel + Send + Sync + 'a,
109 P::Subpixel: Send + Sync + 'a,
110{
111 fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
112 self.chunks
113 .map(|v| <P as Pixel>::from_slice_mut(v))
114 .drive(consumer)
115 }
116
117 fn len(&self) -> usize {
118 self.chunks.len()
119 }
120
121 fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output {
122 self.chunks
123 .map(|v| <P as Pixel>::from_slice_mut(v))
124 .with_producer(callback)
125 }
126}
127
128impl<P> fmt::Debug for PixelsMutPar<'_, P>
129where
130 P: Pixel + Send + Sync,
131 P::Subpixel: Send + Sync + fmt::Debug,
132{
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 f.debug_struct("PixelsMutPar")
135 .field("chunks", &self.chunks)
136 .finish()
137 }
138}
139
140#[derive(Clone)]
142pub struct EnumeratePixelsPar<'a, P>
143where
144 P: Pixel + Sync + 'a,
145 P::Subpixel: Sync + 'a,
146{
147 pixels: PixelsPar<'a, P>,
148 width: u32,
149}
150
151impl<'a, P> ParallelIterator for EnumeratePixelsPar<'a, P>
152where
153 P: Pixel + Sync + 'a,
154 P::Subpixel: Sync + 'a,
155{
156 type Item = (u32, u32, &'a P);
157
158 fn drive_unindexed<C>(self, consumer: C) -> C::Result
159 where
160 C: UnindexedConsumer<Self::Item>,
161 {
162 self.pixels
163 .enumerate()
164 .map(|(i, p)| {
165 (
166 (i % self.width as usize) as u32,
167 (i / self.width as usize) as u32,
168 p,
169 )
170 })
171 .drive_unindexed(consumer)
172 }
173
174 fn opt_len(&self) -> Option<usize> {
175 Some(self.len())
176 }
177}
178
179impl<'a, P> IndexedParallelIterator for EnumeratePixelsPar<'a, P>
180where
181 P: Pixel + Sync + 'a,
182 P::Subpixel: Sync + 'a,
183{
184 fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
185 self.pixels
186 .enumerate()
187 .map(|(i, p)| {
188 (
189 (i % self.width as usize) as u32,
190 (i / self.width as usize) as u32,
191 p,
192 )
193 })
194 .drive(consumer)
195 }
196
197 fn len(&self) -> usize {
198 self.pixels.len()
199 }
200
201 fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output {
202 self.pixels
203 .enumerate()
204 .map(|(i, p)| {
205 (
206 (i % self.width as usize) as u32,
207 (i / self.width as usize) as u32,
208 p,
209 )
210 })
211 .with_producer(callback)
212 }
213}
214
215impl<P> fmt::Debug for EnumeratePixelsPar<'_, P>
216where
217 P: Pixel + Sync,
218 P::Subpixel: Sync + fmt::Debug,
219{
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 f.debug_struct("EnumeratePixelsPar")
222 .field("pixels", &self.pixels)
223 .field("width", &self.width)
224 .finish()
225 }
226}
227
228pub struct EnumeratePixelsMutPar<'a, P>
230where
231 P: Pixel + Send + Sync + 'a,
232 P::Subpixel: Send + Sync + 'a,
233{
234 pixels: PixelsMutPar<'a, P>,
235 width: u32,
236}
237
238impl<'a, P> ParallelIterator for EnumeratePixelsMutPar<'a, P>
239where
240 P: Pixel + Send + Sync + 'a,
241 P::Subpixel: Send + Sync + 'a,
242{
243 type Item = (u32, u32, &'a mut P);
244
245 fn drive_unindexed<C>(self, consumer: C) -> C::Result
246 where
247 C: UnindexedConsumer<Self::Item>,
248 {
249 self.pixels
250 .enumerate()
251 .map(|(i, p)| {
252 (
253 (i % self.width as usize) as u32,
254 (i / self.width as usize) as u32,
255 p,
256 )
257 })
258 .drive_unindexed(consumer)
259 }
260
261 fn opt_len(&self) -> Option<usize> {
262 Some(self.len())
263 }
264}
265
266impl<'a, P> IndexedParallelIterator for EnumeratePixelsMutPar<'a, P>
267where
268 P: Pixel + Send + Sync + 'a,
269 P::Subpixel: Send + Sync + 'a,
270{
271 fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
272 self.pixels
273 .enumerate()
274 .map(|(i, p)| {
275 (
276 (i % self.width as usize) as u32,
277 (i / self.width as usize) as u32,
278 p,
279 )
280 })
281 .drive(consumer)
282 }
283
284 fn len(&self) -> usize {
285 self.pixels.len()
286 }
287
288 fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output {
289 self.pixels
290 .enumerate()
291 .map(|(i, p)| {
292 (
293 (i % self.width as usize) as u32,
294 (i / self.width as usize) as u32,
295 p,
296 )
297 })
298 .with_producer(callback)
299 }
300}
301
302impl<P> fmt::Debug for EnumeratePixelsMutPar<'_, P>
303where
304 P: Pixel + Send + Sync,
305 P::Subpixel: Send + Sync + fmt::Debug,
306{
307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308 f.debug_struct("EnumeratePixelsMutPar")
309 .field("pixels", &self.pixels)
310 .field("width", &self.width)
311 .finish()
312 }
313}
314
315impl<P, Container> ImageBuffer<P, Container>
316where
317 P: Pixel + Sync,
318 P::Subpixel: Sync,
319 Container: Deref<Target = [P::Subpixel]>,
320{
321 pub fn par_pixels(&self) -> PixelsPar<'_, P> {
326 PixelsPar {
327 chunks: self
328 .inner_pixels()
329 .par_chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize),
330 }
331 }
332
333 pub fn par_enumerate_pixels(&self) -> EnumeratePixelsPar<'_, P> {
338 EnumeratePixelsPar {
339 pixels: self.par_pixels(),
340 width: self.width(),
341 }
342 }
343}
344
345impl<P, Container> ImageBuffer<P, Container>
346where
347 P: Pixel + Send + Sync,
348 P::Subpixel: Send + Sync,
349 Container: Deref<Target = [P::Subpixel]> + DerefMut,
350{
351 pub fn par_pixels_mut(&mut self) -> PixelsMutPar<'_, P> {
356 PixelsMutPar {
357 chunks: self
358 .inner_pixels_mut()
359 .par_chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
360 }
361 }
362
363 pub fn par_enumerate_pixels_mut(&mut self) -> EnumeratePixelsMutPar<'_, P> {
368 let width = self.width();
369 EnumeratePixelsMutPar {
370 pixels: self.par_pixels_mut(),
371 width,
372 }
373 }
374}
375
376impl<P> ImageBuffer<P, Vec<P::Subpixel>>
377where
378 P: Pixel + Send + Sync,
379 P::Subpixel: Send + Sync,
380{
381 pub fn from_par_fn<F>(width: u32, height: u32, f: F) -> ImageBuffer<P, Vec<P::Subpixel>>
390 where
391 F: Fn(u32, u32) -> P + Send + Sync,
392 {
393 let mut buf = ImageBuffer::new(width, height);
394 buf.par_enumerate_pixels_mut().for_each(|(x, y, p)| {
395 *p = f(x, y);
396 });
397
398 buf
399 }
400}
401
402#[cfg(test)]
403mod test {
404 use crate::{Rgb, RgbImage};
405 use rayon::iter::{IndexedParallelIterator, ParallelIterator};
406
407 fn test_width_height(width: u32, height: u32, len: usize) {
408 let mut image = RgbImage::new(width, height);
409
410 assert_eq!(image.par_enumerate_pixels_mut().len(), len);
411 assert_eq!(image.par_enumerate_pixels().len(), len);
412 assert_eq!(image.par_pixels_mut().len(), len);
413 assert_eq!(image.par_pixels().len(), len);
414 }
415
416 #[test]
417 fn zero_width_zero_height() {
418 test_width_height(0, 0, 0);
419 }
420
421 #[test]
422 fn zero_width_nonzero_height() {
423 test_width_height(0, 2, 0);
424 }
425
426 #[test]
427 fn nonzero_width_zero_height() {
428 test_width_height(2, 0, 0);
429 }
430
431 #[test]
432 fn iter_parity() {
433 let mut image1 = RgbImage::from_fn(17, 29, |x, y| {
434 Rgb(core::array::from_fn(|i| {
435 ((x + y * 98 + i as u32 * 27) % 255) as u8
436 }))
437 });
438 let mut image2 = image1.clone();
439
440 assert_eq!(
441 image1.enumerate_pixels_mut().collect::<Vec<_>>(),
442 image2.par_enumerate_pixels_mut().collect::<Vec<_>>()
443 );
444 assert_eq!(
445 image1.enumerate_pixels().collect::<Vec<_>>(),
446 image2.par_enumerate_pixels().collect::<Vec<_>>()
447 );
448 assert_eq!(
449 image1.pixels_mut().collect::<Vec<_>>(),
450 image2.par_pixels_mut().collect::<Vec<_>>()
451 );
452 assert_eq!(
453 image1.pixels().collect::<Vec<_>>(),
454 image2.par_pixels().collect::<Vec<_>>()
455 );
456 }
457}
458
459#[cfg(test)]
460#[cfg(feature = "benchmarks")]
461mod benchmarks {
462 use crate::{Rgb, RgbImage};
463
464 const S: u32 = 1024;
465
466 #[bench]
467 fn creation(b: &mut test::Bencher) {
468 let mut bytes = 0;
469 b.iter(|| {
470 let img = RgbImage::from_fn(S, S, |_, _| test::black_box(pixel_func()));
471
472 bytes += img.as_raw().len() as u64;
473 });
474
475 b.bytes = bytes;
476 }
477
478 #[bench]
479 fn creation_par(b: &mut test::Bencher) {
480 let mut bytes = 0;
481 b.iter(|| {
482 let img = RgbImage::from_par_fn(S, S, |_, _| test::black_box(pixel_func()));
483
484 bytes += img.as_raw().len() as u64;
485 });
486
487 b.bytes = bytes;
488 }
489
490 fn pixel_func() -> Rgb<u8> {
491 use std::collections::hash_map::RandomState;
492 use std::hash::{BuildHasher, Hasher};
493 Rgb(core::array::from_fn(|_| {
494 RandomState::new().build_hasher().finish() as u8
495 }))
496 }
497}