1use image::{imageops, DynamicImage, GenericImageView, GrayImage, ImageBuffer, Pixel};
2
3use std::borrow::Cow;
4use std::ops;
5
6pub trait HashBytes {
10 fn from_iter<I: Iterator<Item = u8>>(iter: I) -> Self
16 where
17 Self: Sized;
18
19 fn max_bits() -> usize;
23
24 fn as_slice(&self) -> &[u8];
26}
27
28impl HashBytes for Box<[u8]> {
29 fn from_iter<I: Iterator<Item = u8>>(iter: I) -> Self {
30 iter.collect()
31 }
32
33 fn max_bits() -> usize {
34 usize::max_value()
35 }
36
37 fn as_slice(&self) -> &[u8] {
38 self
39 }
40}
41
42impl HashBytes for Vec<u8> {
43 fn from_iter<I: Iterator<Item = u8>>(iter: I) -> Self {
44 iter.collect()
45 }
46
47 fn max_bits() -> usize {
48 usize::max_value()
49 }
50
51 fn as_slice(&self) -> &[u8] {
52 self
53 }
54}
55
56impl<const N: usize> HashBytes for [u8; N] {
57 fn from_iter<I: Iterator<Item = u8>>(mut iter: I) -> Self {
58 let mut out = [0; N];
59
60 for (src, dest) in iter.by_ref().zip(out.as_mut()) {
61 *dest = src;
62 }
63
64 out
65 }
66
67 fn max_bits() -> usize {
68 N * 8
69 }
70
71 fn as_slice(&self) -> &[u8] {
72 self
73 }
74}
75
76struct BoolsToBytes<I> {
77 iter: I,
78}
79
80impl<I> Iterator for BoolsToBytes<I>
81where
82 I: Iterator<Item = bool>,
83{
84 type Item = u8;
85
86 fn next(&mut self) -> Option<<Self as Iterator>::Item> {
87 self.iter
89 .by_ref()
90 .take(8)
91 .enumerate()
92 .fold(None, |accum, (n, val)| {
93 accum.or(Some(0)).map(|accum| accum | ((val as u8) << n))
94 })
95 }
96
97 fn size_hint(&self) -> (usize, Option<usize>) {
98 let (lower, upper) = self.iter.size_hint();
99 (
100 lower / 8,
101 upper.map(|upper| {
103 if upper % 8 == 0 {
104 upper / 8
105 } else {
106 upper / 8 + 1
107 }
108 }),
109 )
110 }
111}
112
113pub(crate) trait BitSet: HashBytes {
114 fn from_bools<I: Iterator<Item = bool>>(iter: I) -> Self
115 where
116 Self: Sized,
117 {
118 Self::from_iter(BoolsToBytes { iter })
119 }
120
121 fn hamming(&self, other: &Self) -> u32 {
122 self.as_slice()
123 .iter()
124 .zip(other.as_slice())
125 .map(|(l, r)| (l ^ r).count_ones())
126 .sum()
127 }
128}
129
130impl<T: HashBytes> BitSet for T {}
131
132pub trait Image: GenericImageView + 'static {
136 type Buf: Image + DiffImage;
138
139 fn to_grayscale(&self) -> Cow<GrayImage>;
141
142 fn blur(&self, sigma: f32) -> Self::Buf;
144
145 fn foreach_pixel8<F>(&self, foreach: F)
156 where
157 F: FnMut(u32, u32, &[u8]);
158}
159
160pub trait DiffImage {
162 fn diff_inplace(&mut self, other: &Self);
164}
165
166#[cfg(not(feature = "nightly"))]
167impl<P: 'static, C: 'static> Image for ImageBuffer<P, C>
168where
169 P: Pixel<Subpixel = u8>,
170 C: ops::Deref<Target = [u8]>,
171{
172 type Buf = ImageBuffer<P, Vec<u8>>;
173
174 fn to_grayscale(&self) -> Cow<GrayImage> {
175 Cow::Owned(imageops::grayscale(self))
176 }
177
178 fn blur(&self, sigma: f32) -> Self::Buf {
179 imageops::blur(self, sigma)
180 }
181
182 fn foreach_pixel8<F>(&self, mut foreach: F)
183 where
184 F: FnMut(u32, u32, &[u8]),
185 {
186 self.enumerate_pixels()
187 .for_each(|(x, y, px)| foreach(x, y, px.channels()))
188 }
189}
190
191#[cfg(feature = "nightly")]
192impl<P: 'static, C: 'static> Image for ImageBuffer<P, C>
193where
194 P: Pixel<Subpixel = u8>,
195 C: ops::Deref<Target = [u8]>,
196{
197 type Buf = ImageBuffer<P, Vec<u8>>;
198
199 default fn to_grayscale(&self) -> Cow<GrayImage> {
200 Cow::Owned(imageops::grayscale(self))
201 }
202
203 default fn blur(&self, sigma: f32) -> Self::Buf {
204 imageops::blur(self, sigma)
205 }
206
207 default fn foreach_pixel8<F>(&self, mut foreach: F)
208 where
209 F: FnMut(u32, u32, &[u8]),
210 {
211 self.enumerate_pixels()
212 .for_each(|(x, y, px)| foreach(x, y, px.channels()))
213 }
214}
215
216impl<P: 'static> DiffImage for ImageBuffer<P, Vec<u8>>
217where
218 P: Pixel<Subpixel = u8>,
219{
220 fn diff_inplace(&mut self, other: &Self) {
221 self.iter_mut().zip(other.iter()).for_each(|(l, r)| *l -= r);
222 }
223}
224
225impl Image for DynamicImage {
226 type Buf = image::RgbaImage;
227
228 fn to_grayscale(&self) -> Cow<GrayImage> {
229 self.as_luma8()
230 .map_or_else(|| Cow::Owned(self.to_luma8()), Cow::Borrowed)
231 }
232
233 fn blur(&self, sigma: f32) -> Self::Buf {
234 imageops::blur(self, sigma)
235 }
236
237 fn foreach_pixel8<F>(&self, mut foreach: F)
238 where
239 F: FnMut(u32, u32, &[u8]),
240 {
241 self.pixels()
242 .for_each(|(x, y, px)| foreach(x, y, px.channels()))
243 }
244}
245
246#[cfg(feature = "nightly")]
247impl Image for GrayImage {
248 fn to_grayscale(&self) -> Cow<GrayImage> {
252 Cow::Borrowed(self)
253 }
254}
255
256#[test]
257fn test_bools_to_bytes() {
258 let bools = (0..16).map(|x| x & 1 == 0);
259 let bytes = Vec::from_bools(bools.clone());
260 assert_eq!(*bytes, [0b01010101; 2]);
261
262 let bools_to_bytes = BoolsToBytes { iter: bools };
263 assert_eq!(bools_to_bytes.size_hint(), (2, Some(2)));
264}