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 match self {
63 BadIcon::OsError(e) => Some(e),
64 _ => None,
65 }
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub(crate) struct RgbaIcon {
71 pub(crate) rgba: Vec<u8>,
72 pub(crate) width: u32,
73 pub(crate) height: u32,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
78pub(crate) struct NoIcon;
79
80#[allow(dead_code)] mod constructors {
82 use super::*;
83
84 impl RgbaIcon {
85 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
86 if rgba.len() % PIXEL_SIZE != 0 {
87 return Err(BadIcon::ByteCountNotDivisibleBy4 {
88 byte_count: rgba.len(),
89 });
90 }
91 let pixel_count = rgba.len() / PIXEL_SIZE;
92 if pixel_count != (width * height) as usize {
93 Err(BadIcon::DimensionsVsPixelCount {
94 width,
95 height,
96 width_x_height: (width * height) as usize,
97 pixel_count,
98 })
99 } else {
100 Ok(RgbaIcon {
101 rgba,
102 width,
103 height,
104 })
105 }
106 }
107 }
108
109 impl NoIcon {
110 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
111 let _ = RgbaIcon::from_rgba(rgba, width, height)?;
113 Ok(NoIcon)
114 }
115 }
116}
117
118#[derive(Clone)]
120pub struct Icon {
121 pub(crate) inner: PlatformIcon,
122}
123
124impl fmt::Debug for Icon {
125 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
126 fmt::Debug::fmt(&self.inner, formatter)
127 }
128}
129
130impl Icon {
131 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
136 Ok(Icon {
137 inner: PlatformIcon::from_rgba(rgba, width, height)?,
138 })
139 }
140
141 #[cfg(windows)]
149 pub fn from_path<P: AsRef<std::path::Path>>(
150 path: P,
151 size: Option<(u32, u32)>,
152 ) -> Result<Self, BadIcon> {
153 let win_icon = PlatformIcon::from_path(path, size)?;
154 Ok(Icon { inner: win_icon })
155 }
156
157 #[cfg(windows)]
165 pub fn from_resource(ordinal: u16, size: Option<(u32, u32)>) -> Result<Self, BadIcon> {
166 let win_icon = PlatformIcon::from_resource(ordinal, size)?;
167 Ok(Icon { inner: win_icon })
168 }
169
170 #[cfg(windows)]
173 pub fn from_resource_name(
174 resource_name: &str,
175 size: Option<(u32, u32)>,
176 ) -> Result<Self, BadIcon> {
177 let win_icon = PlatformIcon::from_resource_name(resource_name, size)?;
178 Ok(Icon { inner: win_icon })
179 }
180
181 #[cfg(windows)]
183 pub fn from_handle(handle: isize) -> Self {
184 let win_icon = PlatformIcon::from_handle(handle as _);
185 Icon { inner: win_icon }
186 }
187}