Coverage Report

Created: 2025-11-11 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/loop9-0.1.5/src/lib.rs
Line
Count
Source
1
use core::ops::Deref;
2
use imgref::ImgRef;
3
4
/// Previous, current, and next pixel or row
5
#[derive(Copy,Clone,Debug,Eq,PartialEq)]
6
#[repr(C)]
7
pub struct Triple<T> {
8
    pub prev: T,
9
    pub curr: T,
10
    pub next: T,
11
}
12
13
impl<T> Triple<T> {
14
    #[must_use]
15
    #[inline(always)]
16
0
    pub fn new(prev: T, curr: T, next: T) -> Self {
17
0
        Triple { prev, curr, next }
18
0
    }
19
}
20
21
impl<T> AsRef<[T]> for Triple<T> {
22
    #[inline(always)]
23
0
    fn as_ref(&self) -> &[T] {
24
        unsafe {
25
0
            std::slice::from_raw_parts(self as *const Triple<T> as *const T, 3)
26
        }
27
0
    }
28
}
29
30
impl<T> Deref for Triple<T> {
31
    type Target = [T];
32
33
    #[inline(always)]
34
0
    fn deref(&self) -> &Self::Target {
35
0
        self.as_ref()
36
0
    }
37
}
38
39
impl<T: Copy> Triple<T> {
40
    /// Add the next item, and shift others (prev is gone, prev = current)
41
    /// If the item is `None`, it'll copy the last one instead.
42
    #[must_use]
43
    #[inline(always)]
44
0
    pub fn advance(self, next: Option<T>) -> Self {
45
0
        Triple {
46
0
            prev: self.curr,
47
0
            curr: self.next,
48
0
            next: next.unwrap_or(self.next),
49
0
        }
50
0
    }
51
}
52
53
/// Loop over 9 neighboring pixels in the image described by [`ImgRef`] (`Img.as_ref()`)
54
///
55
/// The callback is: (`x`, `y`, `previous_row`, `current_row`, `next_row`)
56
///
57
/// This function will never panic, if your callback doesn't panic.
58
#[inline(always)]
59
0
pub fn loop9_img<Pixel, Callback>(img: ImgRef<'_, Pixel>, cb: Callback)
60
0
    where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>)
61
{
62
0
    loop9(img, 0, 0, img.width(), img.height(), cb);
63
0
}
Unexecuted instantiation: loop9::loop9_img::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::bleed_opaque_color::{closure#0}>
Unexecuted instantiation: loop9::loop9_img::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blurred_dirty_alpha::{closure#0}>
Unexecuted instantiation: loop9::loop9_img::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blur_transparent_pixels::{closure#0}>
64
65
/// Loop over 9 neighboring pixels in the left/top/width/height fragment of the image described by [`ImgRef`] (`Img.as_ref()`)
66
///
67
/// The callback is: (`x`, `y`, `previous_row`, `current_row`, `next_row`)
68
///
69
/// This function will never panic, if your callback doesn't panic.
70
0
pub fn loop9<Pixel, Callback>(img: ImgRef<'_, Pixel>, left: usize, top: usize, width: usize, height: usize, mut cb: Callback)
71
0
    where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>)
72
{
73
0
    let max_width = img.width();
74
0
    let max_height = img.height();
75
0
    let stride = img.stride();
76
0
    if stride == 0 || max_height == 0 || max_width == 0 {
77
0
        return;
78
0
    }
79
0
    let data = img.buf();
80
0
    let t = top.min(max_height-1) * stride;
81
0
    let start_row = if let Some(r) = data.get(t..t+max_width) { r } else { return };
82
0
    if start_row.is_empty() { return; }
83
0
    let mut row = Triple {
84
0
        prev: start_row,
85
0
        curr: start_row,
86
0
        next: start_row,
87
0
    };
88
0
    for y in top..top+height {
89
0
        row = row.advance({
90
0
            let t = (y+1) * stride;
91
0
            data.get(t..t+max_width)
92
0
        });
93
0
        if row.prev.is_empty() || row.curr.is_empty() || row.next.is_empty() {
94
0
            return;
95
0
        }
96
        let mut tp;
97
0
        let mut tn = row.prev[left.min(row.prev.len()-1)];
98
0
        let mut tc = row.prev[left.saturating_sub(1).min(row.prev.len()-1)];
99
        let mut mp;
100
0
        let mut mn = row.curr[left.min(row.curr.len()-1)];
101
0
        let mut mc = row.curr[left.saturating_sub(1).min(row.curr.len()-1)];
102
        let mut bp;
103
0
        let mut bn = row.next[left.min(row.next.len()-1)];
104
0
        let mut bc = row.next[left.saturating_sub(1).min(row.next.len()-1)];
105
0
        for x in left..left+width {
106
0
            tp = tc;
107
0
            tc = tn;
108
0
            tn = row.prev.get(x+1).copied().unwrap_or(tc);
109
0
            mp = mc;
110
0
            mc = mn;
111
0
            mn = row.curr.get(x+1).copied().unwrap_or(mc);
112
0
            bp = bc;
113
0
            bc = bn;
114
0
            bn = row.next.get(x+1).copied().unwrap_or(bc);
115
0
            cb(x-left, y-top, Triple::new(tp, tc, tn), Triple::new(mp, mc, mn), Triple::new(bp, bc, bn));
116
0
        }
117
    }
118
0
}
Unexecuted instantiation: loop9::loop9::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::bleed_opaque_color::{closure#0}>
Unexecuted instantiation: loop9::loop9::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blurred_dirty_alpha::{closure#0}>
Unexecuted instantiation: loop9::loop9::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blur_transparent_pixels::{closure#0}>
119
120
121
#[test]
122
fn test_oob() {
123
    use imgref::Img;
124
    let img = Img::new(vec![0; 5*4], 5, 4);
125
    for w in 1..8 {
126
        for h in 1..8 {
127
            for x in 0..8 {
128
                for y in 0..8 {
129
                    let mut n = 0;
130
                    loop9(img.as_ref(), x,y,w,h, |_x,_y,_top,_mid,_bot| { n += 1 });
131
                    assert_eq!(n, w*h, "{x},{y},{w},{h}");
132
                }
133
            }
134
        }
135
    }
136
}
137
138
#[test]
139
fn test_loop9() {
140
    use imgref::Img;
141
142
    let src = vec![
143
         1, 2, 3, 4, 0,
144
         5, 6, 7, 8, 0,
145
         9,10,11,12, 0,
146
        13,14,15,16, 0,
147
    ];
148
    let img = Img::new_stride(src.clone(), 4, 4, 5);
149
    assert_eq!(4, img.width());
150
    assert_eq!(5, img.stride());
151
    assert_eq!(4, img.height());
152
153
    let check = |l,t,w,h,exp: &[_]|{
154
        let mut res = Vec::new();
155
        loop9(img.as_ref(), l,t,w,h, |_x,_y,_top,mid,_bot| res.push(mid.curr));
156
        assert_eq!(exp, res);
157
    };
158
159
    check(0,0,4,4, &[
160
         1, 2, 3, 4,
161
         5, 6, 7, 8,
162
         9,10,11,12,
163
        13,14,15,16,
164
    ]);
165
166
    check(0,0,4,1, &[1, 2, 3, 4]);
167
168
    check(0,3,4,1, &[13,14,15,16]);
169
170
    check(0,0,3,3, &[
171
         1, 2, 3,
172
         5, 6, 7,
173
         9,10,11,
174
    ]);
175
176
    check(0,0,1,1, &[1]);
177
    check(1,0,1,1, &[2]);
178
    check(2,0,1,1, &[3]);
179
    check(3,0,1,1, &[4]);
180
181
    check(1,0,3,4,&[
182
         2, 3, 4,
183
         6, 7, 8,
184
        10,11,12,
185
        14,15,16,
186
    ]);
187
}