1use crate::Size;
3
4use std::mem;
5
6pub fn from_rgba(
8 rgba: Vec<u8>,
9 width: u32,
10 height: u32,
11) -> Result<Icon, Error> {
12 const PIXEL_SIZE: usize = mem::size_of::<u8>() * 4;
13
14 if rgba.len() % PIXEL_SIZE != 0 {
15 return Err(Error::ByteCountNotDivisibleBy4 {
16 byte_count: rgba.len(),
17 });
18 }
19
20 let pixel_count = rgba.len() / PIXEL_SIZE;
21
22 if pixel_count != (width * height) as usize {
23 return Err(Error::DimensionsVsPixelCount {
24 width,
25 height,
26 width_x_height: (width * height) as usize,
27 pixel_count,
28 });
29 }
30
31 Ok(Icon {
32 rgba,
33 size: Size::new(width, height),
34 })
35}
36
37#[derive(Clone)]
39pub struct Icon {
40 rgba: Vec<u8>,
41 size: Size<u32>,
42}
43
44impl Icon {
45 pub fn into_raw(self) -> (Vec<u8>, Size<u32>) {
47 (self.rgba, self.size)
48 }
49}
50
51impl std::fmt::Debug for Icon {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("Icon")
54 .field("rgba", &format!("{} pixels", self.rgba.len() / 4))
55 .field("size", &self.size)
56 .finish()
57 }
58}
59
60#[derive(Debug, thiserror::Error)]
61pub enum Error {
63 #[error(
66 "The provided RGBA data (with length {byte_count}) isn't divisible \
67 by 4. Therefore, it cannot be safely interpreted as 32bpp RGBA pixels"
68 )]
69 ByteCountNotDivisibleBy4 {
70 byte_count: usize,
72 },
73 #[error(
76 "The number of RGBA pixels ({pixel_count}) does not match the \
77 provided dimensions ({width}x{height})."
78 )]
79 DimensionsVsPixelCount {
80 width: u32,
82 height: u32,
84 width_x_height: usize,
86 pixel_count: usize,
88 },
89}