1use crate::pixelcolor::{
2 raw::{RawU1, RawU16, RawU2, RawU24, RawU32, RawU4, RawU8},
3 PixelColor,
4};
5
6/// Trait to convert colors into a byte array.
7///
8/// See the [module-level documentation](super#converting-colors-to-raw-data) for an example.
9pub trait ToBytes {
10 /// Return type of methods in this trait.
11 type Bytes;
12
13 /// Converts a color into a byte array with big endian byte order.
14 fn to_be_bytes(self) -> Self::Bytes;
15
16 /// Converts a color into a byte array with little endian byte order.
17 fn to_le_bytes(self) -> Self::Bytes;
18
19 /// Converts a color into a byte array with native byte order.
20 fn to_ne_bytes(self) -> Self::Bytes;
21}
22
23macro_rules! impl_to_bytes {
24 ($type:ty, $bytes_type:ty) => {
25 impl ToBytes for $type {
26 type Bytes = $bytes_type;
27
28 fn to_be_bytes(self) -> Self::Bytes {
29 self.0.to_be_bytes()
30 }
31
32 fn to_le_bytes(self) -> Self::Bytes {
33 self.0.to_le_bytes()
34 }
35
36 fn to_ne_bytes(self) -> Self::Bytes {
37 self.0.to_ne_bytes()
38 }
39 }
40 };
41}
42
43impl_to_bytes!(RawU1, [u8; 1]);
44impl_to_bytes!(RawU2, [u8; 1]);
45impl_to_bytes!(RawU4, [u8; 1]);
46impl_to_bytes!(RawU8, [u8; 1]);
47impl_to_bytes!(RawU16, [u8; 2]);
48impl_to_bytes!(RawU32, [u8; 4]);
49
50impl ToBytes for RawU24 {
51 type Bytes = [u8; 3];
52
53 fn to_be_bytes(self) -> Self::Bytes {
54 let mut ret = [0; 3];
55
56 ret.copy_from_slice(&self.0.to_be_bytes()[1..4]);
57
58 ret
59 }
60
61 fn to_le_bytes(self) -> Self::Bytes {
62 let mut ret = [0; 3];
63
64 ret.copy_from_slice(&self.0.to_le_bytes()[0..3]);
65
66 ret
67 }
68
69 #[cfg(target_endian = "big")]
70 fn to_ne_bytes(self) -> Self::Bytes {
71 self.to_be_bytes()
72 }
73
74 #[cfg(target_endian = "little")]
75 fn to_ne_bytes(self) -> Self::Bytes {
76 self.to_le_bytes()
77 }
78}
79
80impl ToBytes for () {
81 type Bytes = [u8; 0];
82
83 fn to_be_bytes(self) -> Self::Bytes {
84 []
85 }
86
87 fn to_le_bytes(self) -> Self::Bytes {
88 []
89 }
90
91 fn to_ne_bytes(self) -> Self::Bytes {
92 []
93 }
94}
95
96impl<C> ToBytes for C
97where
98 C: PixelColor + Into<<C as PixelColor>::Raw>,
99{
100 type Bytes = <<C as PixelColor>::Raw as ToBytes>::Bytes;
101
102 fn to_le_bytes(self) -> Self::Bytes {
103 self.into().to_le_bytes()
104 }
105
106 fn to_be_bytes(self) -> Self::Bytes {
107 self.into().to_be_bytes()
108 }
109
110 fn to_ne_bytes(self) -> Self::Bytes {
111 self.into().to_ne_bytes()
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use crate::pixelcolor::{
119 Bgr565, Bgr666, Bgr888, BinaryColor, Gray2, Gray4, Gray8, Rgb565, Rgb666, Rgb888,
120 };
121
122 fn assert_all_orders<T>(value: T, bytes: T::Bytes)
123 where
124 T: ToBytes + Copy,
125 T::Bytes: PartialEq + core::fmt::Debug,
126 {
127 assert_eq!(value.to_le_bytes(), bytes);
128 assert_eq!(value.to_be_bytes(), bytes);
129 assert_eq!(value.to_ne_bytes(), bytes);
130 }
131
132 #[test]
133 fn bpp1() {
134 assert_all_orders(BinaryColor::Off, [0]);
135 assert_all_orders(BinaryColor::On, [1]);
136 }
137
138 #[test]
139 fn bpp2() {
140 assert_all_orders(Gray2::new(0), [0]);
141 assert_all_orders(Gray2::new(3), [3]);
142 }
143
144 #[test]
145 fn bpp4() {
146 assert_all_orders(Gray4::new(0), [0]);
147 assert_all_orders(Gray4::new(15), [15]);
148 }
149
150 #[test]
151 fn bpp8() {
152 assert_all_orders(Gray8::new(0), [0]);
153 assert_all_orders(Gray8::new(255), [255]);
154 }
155
156 #[test]
157 fn bpp16_rgb_be() {
158 assert_eq!(
159 Rgb565::new(255, 0, 0).to_be_bytes(),
160 [0b11111_000, 0b000_00000]
161 );
162 assert_eq!(
163 Rgb565::new(0, 255, 0).to_be_bytes(),
164 [0b00000_111, 0b111_00000]
165 );
166 assert_eq!(
167 Rgb565::new(0, 0, 255).to_be_bytes(),
168 [0b00000_000, 0b000_11111]
169 );
170 }
171
172 #[test]
173 fn bpp16_rgb_le() {
174 assert_eq!(
175 Rgb565::new(255, 0, 0).to_le_bytes(),
176 [0b000_00000, 0b11111_000]
177 );
178 assert_eq!(
179 Rgb565::new(0, 255, 0).to_le_bytes(),
180 [0b111_00000, 0b00000_111]
181 );
182 assert_eq!(
183 Rgb565::new(0, 0, 255).to_le_bytes(),
184 [0b000_11111, 0b00000_000]
185 );
186 }
187
188 #[test]
189 fn bpp16_bgr_be() {
190 assert_eq!(
191 Bgr565::new(255, 0, 0).to_be_bytes(),
192 [0b00000_000, 0b000_11111]
193 );
194 assert_eq!(
195 Bgr565::new(0, 255, 0).to_be_bytes(),
196 [0b00000_111, 0b111_00000]
197 );
198 assert_eq!(
199 Bgr565::new(0, 0, 255).to_be_bytes(),
200 [0b11111_000, 0b000_00000]
201 );
202 }
203
204 #[test]
205 fn bpp16_bgr_le() {
206 assert_eq!(
207 Bgr565::new(255, 0, 0).to_le_bytes(),
208 [0b000_11111, 0b00000_000]
209 );
210 assert_eq!(
211 Bgr565::new(0, 255, 0).to_le_bytes(),
212 [0b111_00000, 0b00000_111]
213 );
214 assert_eq!(
215 Bgr565::new(0, 0, 255).to_le_bytes(),
216 [0b000_00000, 0b11111_000]
217 );
218 }
219
220 #[test]
221 fn bpp18_bgr_be() {
222 assert_eq!(
223 Bgr666::new(0xFF, 0x00, 0x00).to_be_bytes(),
224 [0b000000000, 0b000000000, 0b00_111111]
225 );
226 assert_eq!(
227 Bgr666::new(0x0, 0xFF, 0x00).to_be_bytes(),
228 [0b000000000, 0b0000_1111, 0b11_000000]
229 );
230 assert_eq!(
231 Bgr666::new(0x00, 0x00, 0xFF).to_be_bytes(),
232 [0b0000000_11, 0b1111_0000, 0b000000000]
233 );
234 }
235
236 #[test]
237 fn bpp18_bgr_le() {
238 assert_eq!(
239 Bgr666::new(0xFF, 0x00, 0x00).to_le_bytes(),
240 [0b00_111111, 0b000000000, 0b000000000]
241 );
242 assert_eq!(
243 Bgr666::new(0x0, 0xFF, 0x00).to_le_bytes(),
244 [0b11_000000, 0b0000_1111, 0b000000000]
245 );
246 assert_eq!(
247 Bgr666::new(0x00, 0x00, 0xFF).to_le_bytes(),
248 [0b000000000, 0b1111_0000, 0b0000000_11]
249 );
250 }
251
252 #[test]
253 fn bpp18_rgb_be() {
254 assert_eq!(
255 Rgb666::new(0xFF, 0x00, 0x00).to_be_bytes(),
256 [0b0000000_11, 0b1111_0000, 0b000000000]
257 );
258 assert_eq!(
259 Rgb666::new(0x0, 0xFF, 0x00).to_be_bytes(),
260 [0b000000000, 0b0000_1111, 0b11_000000]
261 );
262 assert_eq!(
263 Rgb666::new(0x00, 0x00, 0xFF).to_be_bytes(),
264 [0b000000000, 0b000000000, 0b00_111111]
265 );
266 }
267
268 #[test]
269 fn bpp18_rgb_le() {
270 assert_eq!(
271 Rgb666::new(0xFF, 0x00, 0x00).to_le_bytes(),
272 [0b000000000, 0b1111_0000, 0b0000000_11]
273 );
274 assert_eq!(
275 Rgb666::new(0x0, 0xFF, 0x00).to_le_bytes(),
276 [0b11_000000, 0b0000_1111, 0b000000000]
277 );
278 assert_eq!(
279 Rgb666::new(0x00, 0x00, 0xFF).to_le_bytes(),
280 [0b00_111111, 0b000000000, 0b000000000]
281 );
282 }
283
284 #[test]
285 fn bpp24_rgb_be() {
286 assert_eq!(
287 Rgb888::new(0xFF, 0x00, 0x00).to_be_bytes(),
288 [0xFF, 0x00, 0x00]
289 );
290 assert_eq!(
291 Rgb888::new(0x00, 0xFF, 0x00).to_be_bytes(),
292 [0x00, 0xFF, 0x00]
293 );
294 assert_eq!(
295 Rgb888::new(0x00, 0x00, 0xFF).to_be_bytes(),
296 [0x00, 0x00, 0xFF]
297 );
298 }
299
300 #[test]
301 fn bpp24_rgb_le() {
302 assert_eq!(
303 Rgb888::new(0xFF, 0x00, 0x00).to_le_bytes(),
304 [0x00, 0x00, 0xFF]
305 );
306 assert_eq!(
307 Rgb888::new(0x00, 0xFF, 0x00).to_le_bytes(),
308 [0x00, 0xFF, 0x00]
309 );
310 assert_eq!(
311 Rgb888::new(0x00, 0x00, 0xFF).to_le_bytes(),
312 [0xFF, 0x00, 0x00]
313 );
314 }
315
316 #[test]
317 fn bpp24_bgr_be() {
318 assert_eq!(
319 Bgr888::new(0xFF, 0x00, 0x00).to_be_bytes(),
320 [0x00, 0x00, 0xFF]
321 );
322 assert_eq!(
323 Bgr888::new(0x00, 0xFF, 0x00).to_be_bytes(),
324 [0x00, 0xFF, 0x00]
325 );
326 assert_eq!(
327 Bgr888::new(0x00, 0x00, 0xFF).to_be_bytes(),
328 [0xFF, 0x00, 0x00]
329 );
330 }
331
332 #[test]
333 fn bpp24_bgr_le() {
334 assert_eq!(
335 Bgr888::new(0xFF, 0x00, 0x00).to_le_bytes(),
336 [0xFF, 0x00, 0x00]
337 );
338 assert_eq!(
339 Bgr888::new(0x00, 0xFF, 0x00).to_le_bytes(),
340 [0x00, 0xFF, 0x00]
341 );
342 assert_eq!(
343 Bgr888::new(0x00, 0x00, 0xFF).to_le_bytes(),
344 [0x00, 0x00, 0xFF]
345 );
346 }
347
348 #[test]
349 fn bpp32_be() {
350 // This test uses `RawU32` instead of a color, because no color included
351 // in this crate uses 32 bpp.
352 assert_eq!(
353 RawU32::new(0x11223344).to_be_bytes(),
354 [0x11, 0x22, 0x33, 0x44]
355 );
356 }
357
358 #[test]
359 fn bpp32_le() {
360 // This test uses `RawU32` instead of a color, because no color included
361 // in this crate uses 32 bpp.
362 assert_eq!(
363 RawU32::new(0x11223344).to_le_bytes(),
364 [0x44, 0x33, 0x22, 0x11]
365 );
366 }
367
368 #[test]
369 fn native_byte_ordering() {
370 #[cfg(target_endian = "big")]
371 {
372 assert_eq!(RawU1::new(0x1).to_ne_bytes(), RawU1::new(0x1).to_be_bytes());
373 assert_eq!(RawU2::new(0x1).to_ne_bytes(), RawU2::new(0x1).to_be_bytes());
374 assert_eq!(RawU4::new(0x1).to_ne_bytes(), RawU4::new(0x1).to_be_bytes());
375 assert_eq!(
376 RawU8::new(0x12).to_ne_bytes(),
377 RawU8::new(0x12).to_be_bytes()
378 );
379 assert_eq!(
380 RawU16::new(0x1234).to_ne_bytes(),
381 RawU16::new(0x1234).to_be_bytes()
382 );
383 assert_eq!(
384 RawU24::new(0x123456).to_ne_bytes(),
385 RawU24::new(0x123456).to_be_bytes()
386 );
387 assert_eq!(
388 RawU32::new(0x12345678).to_ne_bytes(),
389 RawU32::new(0x12345678).to_be_bytes()
390 );
391 }
392
393 #[cfg(target_endian = "little")]
394 {
395 assert_eq!(RawU1::new(0x1).to_ne_bytes(), RawU1::new(0x1).to_le_bytes());
396 assert_eq!(RawU2::new(0x1).to_ne_bytes(), RawU2::new(0x1).to_le_bytes());
397 assert_eq!(RawU4::new(0x1).to_ne_bytes(), RawU4::new(0x1).to_le_bytes());
398 assert_eq!(
399 RawU8::new(0x12).to_ne_bytes(),
400 RawU8::new(0x12).to_le_bytes()
401 );
402 assert_eq!(
403 RawU16::new(0x1234).to_ne_bytes(),
404 RawU16::new(0x1234).to_le_bytes()
405 );
406 assert_eq!(
407 RawU24::new(0x123456).to_ne_bytes(),
408 RawU24::new(0x123456).to_le_bytes()
409 );
410 assert_eq!(
411 RawU32::new(0x12345678).to_ne_bytes(),
412 RawU32::new(0x12345678).to_le_bytes()
413 );
414 }
415 }
416}
417