1use crate::rendering_buffer::RowAccessor;
10
11pub trait ImageSource {
20 fn span(&mut self, x: i32, y: i32, len: u32) -> &[u8];
22
23 fn next_x(&mut self) -> &[u8];
25
26 fn next_y(&mut self) -> &[u8];
28}
29
30impl<const PIX_WIDTH: usize> ImageSource for ImageAccessorClip<'_, PIX_WIDTH> {
31 fn span(&mut self, x: i32, y: i32, len: u32) -> &[u8] {
32 self.span(x, y, len)
33 }
34 fn next_x(&mut self) -> &[u8] {
35 self.next_x()
36 }
37 fn next_y(&mut self) -> &[u8] {
38 self.next_y()
39 }
40}
41
42impl<const PIX_WIDTH: usize> ImageSource for ImageAccessorNoClip<'_, PIX_WIDTH> {
43 fn span(&mut self, x: i32, y: i32, len: u32) -> &[u8] {
44 self.span(x, y, len)
45 }
46 fn next_x(&mut self) -> &[u8] {
47 self.next_x()
48 }
49 fn next_y(&mut self) -> &[u8] {
50 self.next_y()
51 }
52}
53
54impl<const PIX_WIDTH: usize> ImageSource for ImageAccessorClone<'_, PIX_WIDTH> {
55 fn span(&mut self, x: i32, y: i32, len: u32) -> &[u8] {
56 self.span(x, y, len)
57 }
58 fn next_x(&mut self) -> &[u8] {
59 self.next_x()
60 }
61 fn next_y(&mut self) -> &[u8] {
62 self.next_y()
63 }
64}
65
66impl<const PIX_WIDTH: usize, WX: WrapMode, WY: WrapMode> ImageSource
67 for ImageAccessorWrap<'_, PIX_WIDTH, WX, WY>
68{
69 fn span(&mut self, x: i32, y: i32, len: u32) -> &[u8] {
70 self.span(x, y, len)
71 }
72 fn next_x(&mut self) -> &[u8] {
73 self.next_x()
74 }
75 fn next_y(&mut self) -> &[u8] {
76 self.next_y()
77 }
78}
79
80pub trait WrapMode {
86 fn new(size: u32) -> Self;
88
89 fn func(&mut self, v: i32) -> u32;
91
92 fn inc(&mut self) -> u32;
94}
95
96pub struct WrapModeRepeat {
104 size: u32,
105 add: u32,
106 value: u32,
107}
108
109impl WrapMode for WrapModeRepeat {
110 fn new(size: u32) -> Self {
111 Self {
112 size,
113 add: size.wrapping_mul(0x3FFF_FFFF / size),
114 value: 0,
115 }
116 }
117
118 #[inline]
119 fn func(&mut self, v: i32) -> u32 {
120 self.value = (v as u32).wrapping_add(self.add) % self.size;
121 self.value
122 }
123
124 #[inline]
125 fn inc(&mut self) -> u32 {
126 self.value += 1;
127 if self.value >= self.size {
128 self.value = 0;
129 }
130 self.value
131 }
132}
133
134pub struct WrapModeRepeatPow2 {
142 mask: u32,
143 value: u32,
144}
145
146impl WrapMode for WrapModeRepeatPow2 {
147 fn new(size: u32) -> Self {
148 let mut mask = 1u32;
149 while mask < size {
150 mask = (mask << 1) | 1;
151 }
152 mask >>= 1;
153 Self { mask, value: 0 }
154 }
155
156 #[inline]
157 fn func(&mut self, v: i32) -> u32 {
158 self.value = v as u32 & self.mask;
159 self.value
160 }
161
162 #[inline]
163 fn inc(&mut self) -> u32 {
164 self.value += 1;
165 if self.value > self.mask {
166 self.value = 0;
167 }
168 self.value
169 }
170}
171
172pub struct WrapModeRepeatAutoPow2 {
180 size: u32,
181 add: u32,
182 mask: u32,
183 value: u32,
184}
185
186impl WrapMode for WrapModeRepeatAutoPow2 {
187 fn new(size: u32) -> Self {
188 let mask = if size & (size - 1) == 0 { size - 1 } else { 0 };
189 Self {
190 size,
191 add: size.wrapping_mul(0x3FFF_FFFF / size),
192 mask,
193 value: 0,
194 }
195 }
196
197 #[inline]
198 fn func(&mut self, v: i32) -> u32 {
199 if self.mask != 0 {
200 self.value = v as u32 & self.mask;
201 } else {
202 self.value = (v as u32).wrapping_add(self.add) % self.size;
203 }
204 self.value
205 }
206
207 #[inline]
208 fn inc(&mut self) -> u32 {
209 self.value += 1;
210 if self.value >= self.size {
211 self.value = 0;
212 }
213 self.value
214 }
215}
216
217pub struct WrapModeReflect {
225 size: u32,
226 size2: u32,
227 add: u32,
228 value: u32,
229}
230
231impl WrapMode for WrapModeReflect {
232 fn new(size: u32) -> Self {
233 let size2 = size * 2;
234 Self {
235 size,
236 size2,
237 add: size2.wrapping_mul(0x3FFF_FFFF / size2),
238 value: 0,
239 }
240 }
241
242 #[inline]
243 fn func(&mut self, v: i32) -> u32 {
244 self.value = (v as u32).wrapping_add(self.add) % self.size2;
245 if self.value >= self.size {
246 self.size2 - self.value - 1
247 } else {
248 self.value
249 }
250 }
251
252 #[inline]
253 fn inc(&mut self) -> u32 {
254 self.value += 1;
255 if self.value >= self.size2 {
256 self.value = 0;
257 }
258 if self.value >= self.size {
259 self.size2 - self.value - 1
260 } else {
261 self.value
262 }
263 }
264}
265
266pub struct WrapModeReflectPow2 {
274 size: u32,
275 mask: u32,
276 value: u32,
277}
278
279impl WrapMode for WrapModeReflectPow2 {
280 fn new(size: u32) -> Self {
281 let mut mask = 1u32;
282 let mut sz = 1u32;
283 while mask < size {
284 mask = (mask << 1) | 1;
285 sz <<= 1;
286 }
287 Self {
288 size: sz,
289 mask,
290 value: 0,
291 }
292 }
293
294 #[inline]
295 fn func(&mut self, v: i32) -> u32 {
296 self.value = v as u32 & self.mask;
297 if self.value >= self.size {
298 self.mask - self.value
299 } else {
300 self.value
301 }
302 }
303
304 #[inline]
305 fn inc(&mut self) -> u32 {
306 self.value += 1;
307 self.value &= self.mask;
308 if self.value >= self.size {
309 self.mask - self.value
310 } else {
311 self.value
312 }
313 }
314}
315
316pub struct WrapModeReflectAutoPow2 {
324 size: u32,
325 size2: u32,
326 add: u32,
327 mask: u32,
328 value: u32,
329}
330
331impl WrapMode for WrapModeReflectAutoPow2 {
332 fn new(size: u32) -> Self {
333 let size2 = size * 2;
334 let mask = if size2 & (size2 - 1) == 0 {
335 size2 - 1
336 } else {
337 0
338 };
339 Self {
340 size,
341 size2,
342 add: size2.wrapping_mul(0x3FFF_FFFF / size2),
343 mask,
344 value: 0,
345 }
346 }
347
348 #[inline]
349 fn func(&mut self, v: i32) -> u32 {
350 self.value = if self.mask != 0 {
351 v as u32 & self.mask
352 } else {
353 (v as u32).wrapping_add(self.add) % self.size2
354 };
355 if self.value >= self.size {
356 self.size2 - self.value - 1
357 } else {
358 self.value
359 }
360 }
361
362 #[inline]
363 fn inc(&mut self) -> u32 {
364 self.value += 1;
365 if self.value >= self.size2 {
366 self.value = 0;
367 }
368 if self.value >= self.size {
369 self.size2 - self.value - 1
370 } else {
371 self.value
372 }
373 }
374}
375
376pub struct ImageAccessorClip<'a, const PIX_WIDTH: usize> {
384 rbuf: &'a RowAccessor,
385 bk_buf: [u8; 8], x: i32,
387 x0: i32,
388 y: i32,
389 fast_path: bool,
390 pix_off: usize,
391}
392
393impl<'a, const PIX_WIDTH: usize> ImageAccessorClip<'a, PIX_WIDTH> {
394 pub fn new(rbuf: &'a RowAccessor, bk_color: &[u8]) -> Self {
395 let mut bk_buf = [0u8; 8];
396 let len = bk_color.len().min(8);
397 bk_buf[..len].copy_from_slice(&bk_color[..len]);
398 Self {
399 rbuf,
400 bk_buf,
401 x: 0,
402 x0: 0,
403 y: 0,
404 fast_path: false,
405 pix_off: 0,
406 }
407 }
408
409 pub fn set_background(&mut self, bk_color: &[u8]) {
410 let len = bk_color.len().min(8);
411 self.bk_buf[..len].copy_from_slice(&bk_color[..len]);
412 }
413
414 fn pixel(&self) -> &[u8] {
415 if self.y >= 0
416 && self.y < self.rbuf.height() as i32
417 && self.x >= 0
418 && self.x < self.rbuf.width() as i32
419 {
420 let row = self.rbuf.row_slice(self.y as u32);
421 let off = self.x as usize * PIX_WIDTH;
422 &row[off..off + PIX_WIDTH]
423 } else {
424 &self.bk_buf[..PIX_WIDTH]
425 }
426 }
427
428 pub fn span(&mut self, x: i32, y: i32, len: u32) -> &[u8] {
429 self.x = x;
430 self.x0 = x;
431 self.y = y;
432 if y >= 0
433 && y < self.rbuf.height() as i32
434 && x >= 0
435 && (x + len as i32) <= self.rbuf.width() as i32
436 {
437 self.fast_path = true;
438 self.pix_off = x as usize * PIX_WIDTH;
439 let row = self.rbuf.row_slice(y as u32);
440 &row[self.pix_off..self.pix_off + PIX_WIDTH]
441 } else {
442 self.fast_path = false;
443 self.pixel()
444 }
445 }
446
447 pub fn next_x(&mut self) -> &[u8] {
448 if self.fast_path {
449 self.pix_off += PIX_WIDTH;
450 let row = self.rbuf.row_slice(self.y as u32);
451 &row[self.pix_off..self.pix_off + PIX_WIDTH]
452 } else {
453 self.x += 1;
454 self.pixel()
455 }
456 }
457
458 pub fn next_y(&mut self) -> &[u8] {
459 self.y += 1;
460 self.x = self.x0;
461 if self.fast_path && self.y >= 0 && self.y < self.rbuf.height() as i32 {
462 self.pix_off = self.x as usize * PIX_WIDTH;
463 let row = self.rbuf.row_slice(self.y as u32);
464 &row[self.pix_off..self.pix_off + PIX_WIDTH]
465 } else {
466 self.fast_path = false;
467 self.pixel()
468 }
469 }
470}
471
472pub struct ImageAccessorNoClip<'a, const PIX_WIDTH: usize> {
480 rbuf: &'a RowAccessor,
481 x: i32,
482 y: i32,
483 pix_off: usize,
484}
485
486impl<'a, const PIX_WIDTH: usize> ImageAccessorNoClip<'a, PIX_WIDTH> {
487 pub fn new(rbuf: &'a RowAccessor) -> Self {
488 Self {
489 rbuf,
490 x: 0,
491 y: 0,
492 pix_off: 0,
493 }
494 }
495
496 pub fn span(&mut self, x: i32, y: i32, _len: u32) -> &[u8] {
497 self.x = x;
498 self.y = y;
499 self.pix_off = x as usize * PIX_WIDTH;
500 let row = self.rbuf.row_slice(y as u32);
501 &row[self.pix_off..self.pix_off + PIX_WIDTH]
502 }
503
504 pub fn next_x(&mut self) -> &[u8] {
505 self.pix_off += PIX_WIDTH;
506 let row = self.rbuf.row_slice(self.y as u32);
507 &row[self.pix_off..self.pix_off + PIX_WIDTH]
508 }
509
510 pub fn next_y(&mut self) -> &[u8] {
511 self.y += 1;
512 self.pix_off = self.x as usize * PIX_WIDTH;
513 let row = self.rbuf.row_slice(self.y as u32);
514 &row[self.pix_off..self.pix_off + PIX_WIDTH]
515 }
516}
517
518pub struct ImageAccessorClone<'a, const PIX_WIDTH: usize> {
526 rbuf: &'a RowAccessor,
527 x: i32,
528 x0: i32,
529 y: i32,
530 pix_ptr: *const u8,
535}
536
537impl<'a, const PIX_WIDTH: usize> ImageAccessorClone<'a, PIX_WIDTH> {
538 pub fn new(rbuf: &'a RowAccessor) -> Self {
539 Self {
540 rbuf,
541 x: 0,
542 x0: 0,
543 y: 0,
544 pix_ptr: std::ptr::null(),
545 }
546 }
547
548 fn pixel(&self) -> &[u8] {
549 let cx = self.x.max(0).min(self.rbuf.width() as i32 - 1);
550 let cy = self.y.max(0).min(self.rbuf.height() as i32 - 1);
551 let row = self.rbuf.row_slice(cy as u32);
552 let off = cx as usize * PIX_WIDTH;
553 &row[off..off + PIX_WIDTH]
554 }
555
556 #[inline]
562 unsafe fn pix_slice(&self) -> &[u8] {
563 std::slice::from_raw_parts(self.pix_ptr, PIX_WIDTH)
564 }
565
566 pub fn span(&mut self, x: i32, y: i32, len: u32) -> &[u8] {
567 self.x = x;
568 self.x0 = x;
569 self.y = y;
570 if y >= 0
571 && y < self.rbuf.height() as i32
572 && x >= 0
573 && (x + len as i32) <= self.rbuf.width() as i32
574 {
575 unsafe {
578 self.pix_ptr = self.rbuf.row_ptr(y).add(x as usize * PIX_WIDTH);
579 self.pix_slice()
580 }
581 } else {
582 self.pix_ptr = std::ptr::null();
583 self.pixel()
584 }
585 }
586
587 pub fn next_x(&mut self) -> &[u8] {
588 if !self.pix_ptr.is_null() {
589 unsafe {
592 self.pix_ptr = self.pix_ptr.add(PIX_WIDTH);
593 self.pix_slice()
594 }
595 } else {
596 self.x += 1;
597 self.pixel()
598 }
599 }
600
601 pub fn next_y(&mut self) -> &[u8] {
602 self.y += 1;
603 self.x = self.x0;
604 if !self.pix_ptr.is_null() && self.y >= 0 && self.y < self.rbuf.height() as i32 {
605 unsafe {
607 self.pix_ptr = self.rbuf.row_ptr(self.y).add(self.x as usize * PIX_WIDTH);
608 self.pix_slice()
609 }
610 } else {
611 self.pix_ptr = std::ptr::null();
612 self.pixel()
613 }
614 }
615}
616
617pub struct ImageAccessorWrap<'a, const PIX_WIDTH: usize, WX: WrapMode, WY: WrapMode> {
625 rbuf: &'a RowAccessor,
626 x: i32,
627 wrap_x: WX,
628 wrap_y: WY,
629 row_y: u32,
630}
631
632impl<'a, const PIX_WIDTH: usize, WX: WrapMode, WY: WrapMode>
633 ImageAccessorWrap<'a, PIX_WIDTH, WX, WY>
634{
635 pub fn new(rbuf: &'a RowAccessor) -> Self {
636 Self {
637 rbuf,
638 x: 0,
639 wrap_x: WX::new(rbuf.width()),
640 wrap_y: WY::new(rbuf.height()),
641 row_y: 0,
642 }
643 }
644
645 pub fn span(&mut self, x: i32, y: i32, _len: u32) -> &[u8] {
646 self.x = x;
647 self.row_y = self.wrap_y.func(y);
648 let wx = self.wrap_x.func(x) as usize * PIX_WIDTH;
649 let row = self.rbuf.row_slice(self.row_y);
650 &row[wx..wx + PIX_WIDTH]
651 }
652
653 pub fn next_x(&mut self) -> &[u8] {
654 let wx = self.wrap_x.inc() as usize * PIX_WIDTH;
655 let row = self.rbuf.row_slice(self.row_y);
656 &row[wx..wx + PIX_WIDTH]
657 }
658
659 pub fn next_y(&mut self) -> &[u8] {
660 self.row_y = self.wrap_y.inc();
661 let wx = self.wrap_x.func(self.x) as usize * PIX_WIDTH;
662 let row = self.rbuf.row_slice(self.row_y);
663 &row[wx..wx + PIX_WIDTH]
664 }
665}
666
667#[cfg(test)]
672mod tests {
673 use super::*;
674
675 fn make_rgba_buffer(width: u32, height: u32, data: &mut Vec<u8>) -> RowAccessor {
676 let stride = width as usize * 4;
677 data.resize(stride * height as usize, 0);
678 unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), width, height, stride as i32) }
679 }
680
681 fn set_rgba_pixel(data: &mut [u8], width: u32, x: u32, y: u32, rgba: [u8; 4]) {
682 let off = (y * width * 4 + x * 4) as usize;
683 data[off..off + 4].copy_from_slice(&rgba);
684 }
685
686 #[test]
689 fn test_wrap_repeat() {
690 let mut w = WrapModeRepeat::new(4);
691 assert_eq!(w.func(0), 0);
692 assert_eq!(w.func(3), 3);
693 assert_eq!(w.func(4), 0);
694 assert_eq!(w.func(5), 1);
695 assert_eq!(w.func(-1), 3);
696 }
697
698 #[test]
699 fn test_wrap_repeat_inc() {
700 let mut w = WrapModeRepeat::new(3);
701 w.func(0);
702 assert_eq!(w.inc(), 1);
703 assert_eq!(w.inc(), 2);
704 assert_eq!(w.inc(), 0); }
706
707 #[test]
708 fn test_wrap_repeat_pow2() {
709 let mut w = WrapModeRepeatPow2::new(4); assert_eq!(w.func(0), 0);
711 assert_eq!(w.func(3), 3);
712 assert_eq!(w.func(4), 0);
713 assert_eq!(w.func(7), 3);
714 }
715
716 #[test]
717 fn test_wrap_reflect() {
718 let mut w = WrapModeReflect::new(4); assert_eq!(w.func(0), 0);
720 assert_eq!(w.func(3), 3);
721 assert_eq!(w.func(4), 3); assert_eq!(w.func(7), 0); }
724
725 #[test]
726 fn test_wrap_reflect_inc() {
727 let mut w = WrapModeReflect::new(3); w.func(0);
729 assert_eq!(w.inc(), 1);
730 assert_eq!(w.inc(), 2);
731 assert_eq!(w.inc(), 2); assert_eq!(w.inc(), 1); assert_eq!(w.inc(), 0); assert_eq!(w.inc(), 0); }
736
737 #[test]
738 fn test_wrap_repeat_auto_pow2() {
739 let mut w = WrapModeRepeatAutoPow2::new(8);
741 assert_eq!(w.func(8), 0);
742 assert_eq!(w.func(9), 1);
743
744 let mut w2 = WrapModeRepeatAutoPow2::new(5);
746 assert_eq!(w2.func(5), 0);
747 assert_eq!(w2.func(7), 2);
748 }
749
750 #[test]
751 fn test_wrap_reflect_pow2() {
752 let mut w = WrapModeReflectPow2::new(4);
753 assert_eq!(w.func(0), 0);
754 assert_eq!(w.func(3), 3);
755 assert_eq!(w.func(4), 3); assert_eq!(w.func(7), 0); }
758
759 #[test]
762 fn test_clip_in_bounds() {
763 let mut data = Vec::new();
764 let rbuf = make_rgba_buffer(4, 4, &mut data);
765 set_rgba_pixel(&mut data, 4, 1, 1, [10, 20, 30, 40]);
766
767 let mut acc = ImageAccessorClip::<4>::new(&rbuf, &[0, 0, 0, 0]);
768 let pix = acc.span(1, 1, 1);
769 assert_eq!(&pix[..4], &[10, 20, 30, 40]);
770 }
771
772 #[test]
773 fn test_clip_out_of_bounds() {
774 let mut data = Vec::new();
775 let rbuf = make_rgba_buffer(4, 4, &mut data);
776
777 let mut acc = ImageAccessorClip::<4>::new(&rbuf, &[99, 88, 77, 66]);
778 let pix = acc.span(-1, 0, 1);
779 assert_eq!(&pix[..4], &[99, 88, 77, 66]);
780 }
781
782 #[test]
783 fn test_clip_span_fast_path() {
784 let mut data = Vec::new();
785 let rbuf = make_rgba_buffer(4, 4, &mut data);
786 set_rgba_pixel(&mut data, 4, 0, 0, [1, 2, 3, 4]);
787 set_rgba_pixel(&mut data, 4, 1, 0, [5, 6, 7, 8]);
788
789 let mut acc = ImageAccessorClip::<4>::new(&rbuf, &[0, 0, 0, 0]);
790 let pix = acc.span(0, 0, 2);
791 assert_eq!(&pix[..4], &[1, 2, 3, 4]);
792 let pix = acc.next_x();
793 assert_eq!(&pix[..4], &[5, 6, 7, 8]);
794 }
795
796 #[test]
799 fn test_no_clip_span() {
800 let mut data = Vec::new();
801 let rbuf = make_rgba_buffer(4, 4, &mut data);
802 set_rgba_pixel(&mut data, 4, 2, 1, [11, 22, 33, 44]);
803
804 let mut acc = ImageAccessorNoClip::<4>::new(&rbuf);
805 let pix = acc.span(2, 1, 1);
806 assert_eq!(&pix[..4], &[11, 22, 33, 44]);
807 }
808
809 #[test]
810 fn test_no_clip_next_x() {
811 let mut data = Vec::new();
812 let rbuf = make_rgba_buffer(4, 4, &mut data);
813 set_rgba_pixel(&mut data, 4, 0, 0, [10, 0, 0, 0]);
814 set_rgba_pixel(&mut data, 4, 1, 0, [20, 0, 0, 0]);
815 set_rgba_pixel(&mut data, 4, 2, 0, [30, 0, 0, 0]);
816
817 let mut acc = ImageAccessorNoClip::<4>::new(&rbuf);
818 acc.span(0, 0, 3);
819 let p1 = acc.next_x();
820 assert_eq!(p1[0], 20);
821 let p2 = acc.next_x();
822 assert_eq!(p2[0], 30);
823 }
824
825 #[test]
828 fn test_clone_in_bounds() {
829 let mut data = Vec::new();
830 let rbuf = make_rgba_buffer(4, 4, &mut data);
831 set_rgba_pixel(&mut data, 4, 1, 1, [50, 60, 70, 80]);
832
833 let mut acc = ImageAccessorClone::<4>::new(&rbuf);
834 let pix = acc.span(1, 1, 1);
835 assert_eq!(&pix[..4], &[50, 60, 70, 80]);
836 }
837
838 #[test]
839 fn test_clone_clamps_negative() {
840 let mut data = Vec::new();
841 let rbuf = make_rgba_buffer(4, 4, &mut data);
842 set_rgba_pixel(&mut data, 4, 0, 0, [10, 20, 30, 40]);
843
844 let mut acc = ImageAccessorClone::<4>::new(&rbuf);
845 let pix = acc.span(-5, -3, 1);
846 assert_eq!(&pix[..4], &[10, 20, 30, 40]);
848 }
849
850 #[test]
851 fn test_clone_clamps_overflow() {
852 let mut data = Vec::new();
853 let rbuf = make_rgba_buffer(4, 4, &mut data);
854 set_rgba_pixel(&mut data, 4, 3, 3, [99, 88, 77, 66]);
855
856 let mut acc = ImageAccessorClone::<4>::new(&rbuf);
857 let pix = acc.span(100, 100, 1);
858 assert_eq!(&pix[..4], &[99, 88, 77, 66]);
860 }
861
862 #[test]
863 fn test_clone_fast_path_border_walk() {
864 let mut data = Vec::new();
870 let rbuf = make_rgba_buffer(4, 4, &mut data);
871 for y in 0..4u32 {
872 for x in 0..4u32 {
873 set_rgba_pixel(&mut data, 4, x, y, [x as u8, y as u8, (x * 4 + y) as u8, 255]);
874 }
875 }
876
877 let clamp_pixel = |x: i32, y: i32| -> [u8; 4] {
882 let mut oracle = ImageAccessorClone::<4>::new(&rbuf);
883 let p = oracle.span(x, y, 1_000_000);
884 [p[0], p[1], p[2], p[3]]
885 };
886
887 let mut acc = ImageAccessorClone::<4>::new(&rbuf);
890 let p = acc.span(2, 3, 2);
891 assert_eq!(&p[..4], &clamp_pixel(2, 3), "span at right/bottom border");
892
893 let p = acc.next_x();
895 assert_eq!(&p[..4], &clamp_pixel(3, 3), "next_x fast-path advance");
896
897 let p = acc.next_y();
900 assert_eq!(&p[..4], &clamp_pixel(2, 4), "next_y off bottom edge clamps");
901
902 let p = acc.next_x();
905 assert_eq!(&p[..4], &clamp_pixel(3, 4), "next_x after clamp fallback");
906
907 let mut acc2 = ImageAccessorClone::<4>::new(&rbuf);
910 let p = acc2.span(0, 1, 4);
911 assert_eq!(&p[..4], &clamp_pixel(0, 1));
912 for x in 1..4 {
913 let p = acc2.next_x();
914 assert_eq!(&p[..4], &clamp_pixel(x, 1), "in-bounds fast-path next_x");
915 }
916 }
917
918 #[test]
921 fn test_wrap_repeat_access() {
922 let mut data = Vec::new();
923 let rbuf = make_rgba_buffer(2, 2, &mut data);
924 set_rgba_pixel(&mut data, 2, 0, 0, [10, 0, 0, 0]);
925 set_rgba_pixel(&mut data, 2, 1, 0, [20, 0, 0, 0]);
926 set_rgba_pixel(&mut data, 2, 0, 1, [30, 0, 0, 0]);
927 set_rgba_pixel(&mut data, 2, 1, 1, [40, 0, 0, 0]);
928
929 let mut acc = ImageAccessorWrap::<4, WrapModeRepeat, WrapModeRepeat>::new(&rbuf);
930 let pix = acc.span(2, 0, 1);
932 assert_eq!(pix[0], 10);
933 let pix = acc.next_x();
935 assert_eq!(pix[0], 20);
936 }
937
938 #[test]
939 fn test_wrap_next_y() {
940 let mut data = Vec::new();
941 let rbuf = make_rgba_buffer(2, 2, &mut data);
942 set_rgba_pixel(&mut data, 2, 0, 0, [10, 0, 0, 0]);
943 set_rgba_pixel(&mut data, 2, 0, 1, [30, 0, 0, 0]);
944
945 let mut acc = ImageAccessorWrap::<4, WrapModeRepeat, WrapModeRepeat>::new(&rbuf);
946 acc.span(0, 0, 1);
947 let pix = acc.next_y();
948 assert_eq!(pix[0], 30);
949 }
950}