1use crate::platform_impl::PlatformIcon;
8use std::{error::Error, fmt, io, mem};
9
10#[repr(C)]
11#[derive(Debug)]
12pub(crate) struct Pixel {
13 pub(crate) r: u8,
14 pub(crate) g: u8,
15 pub(crate) b: u8,
16 pub(crate) a: u8,
17}
18
19pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
20
21#[derive(Debug)]
22pub enum BadIcon {
24 ByteCountNotDivisibleBy4 { byte_count: usize },
27 DimensionsVsPixelCount {
30 width: u32,
31 height: u32,
32 width_x_height: usize,
33 pixel_count: usize,
34 },
35 OsError(io::Error),
37}
38
39impl fmt::Display for BadIcon {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f,
43 "The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
44 byte_count,
45 ),
46 BadIcon::DimensionsVsPixelCount {
47 width,
48 height,
49 width_x_height,
50 pixel_count,
51 } => write!(f,
52 "The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.",
53 width, height, pixel_count, width_x_height,
54 ),
55 BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {:?}", e),
56 }
57 }
58}
59
60impl Error for BadIcon {
61 fn source(&self) -> Option<&(dyn Error + 'static)> {
62 Some(self)
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub(crate) struct RgbaIcon {
68 pub(crate) rgba: Vec<u8>,
69 pub(crate) width: u32,
70 pub(crate) height: u32,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub(crate) struct NoIcon;
76
77#[allow(dead_code)] mod constructors {
79 use super::*;
80
81 impl RgbaIcon {
82 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
83 if rgba.len() % PIXEL_SIZE != 0 {
84 return Err(BadIcon::ByteCountNotDivisibleBy4 {
85 byte_count: rgba.len(),
86 });
87 }
88 let pixel_count = rgba.len() / PIXEL_SIZE;
89 if pixel_count != (width * height) as usize {
90 Err(BadIcon::DimensionsVsPixelCount {
91 width,
92 height,
93 width_x_height: (width * height) as usize,
94 pixel_count,
95 })
96 } else {
97 Ok(RgbaIcon {
98 rgba,
99 width,
100 height,
101 })
102 }
103 }
104 }
105
106 impl NoIcon {
107 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
108 let _ = RgbaIcon::from_rgba(rgba, width, height)?;
110 Ok(NoIcon)
111 }
112 }
113}
114
115#[derive(Clone)]
117pub struct Icon {
118 pub(crate) inner: PlatformIcon,
119}
120
121impl fmt::Debug for Icon {
122 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
123 fmt::Debug::fmt(&self.inner, formatter)
124 }
125}
126
127impl Icon {
128 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
133 Ok(Icon {
134 inner: PlatformIcon::from_rgba(rgba, width, height)?,
135 })
136 }
137
138 #[cfg(windows)]
146 pub fn from_path<P: AsRef<std::path::Path>>(
147 path: P,
148 size: Option<(u32, u32)>,
149 ) -> Result<Self, BadIcon> {
150 let win_icon = PlatformIcon::from_path(path, size)?;
151 Ok(Icon { inner: win_icon })
152 }
153
154 #[cfg(windows)]
162 pub fn from_resource(ordinal: u16, size: Option<(u32, u32)>) -> Result<Self, BadIcon> {
163 let win_icon = PlatformIcon::from_resource(ordinal, size)?;
164 Ok(Icon { inner: win_icon })
165 }
166
167 #[cfg(windows)]
170 pub fn from_resource_name(
171 resource_name: &str,
172 size: Option<(u32, u32)>,
173 ) -> Result<Self, BadIcon> {
174 let win_icon = PlatformIcon::from_resource_name(resource_name, size)?;
175 Ok(Icon { inner: win_icon })
176 }
177
178 #[cfg(windows)]
180 pub fn from_handle(handle: isize) -> Self {
181 let win_icon = PlatformIcon::from_handle(handle as _);
182 Icon { inner: win_icon }
183 }
184}