2019-06-22 01:33:15 +10:00
use std ::{ error ::Error , fmt , mem } ;
2018-05-08 07:36:21 +10:00
#[ repr(C) ]
#[ derive(Debug) ]
pub ( crate ) struct Pixel {
pub ( crate ) r : u8 ,
pub ( crate ) g : u8 ,
pub ( crate ) b : u8 ,
pub ( crate ) a : u8 ,
}
pub ( crate ) const PIXEL_SIZE : usize = mem ::size_of ::< Pixel > ( ) ;
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
/// An error produced when using `Icon::from_rgba` with invalid arguments.
pub enum BadIcon {
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
/// safely interpreted as 32bpp RGBA pixels.
2019-06-22 01:33:15 +10:00
ByteCountNotDivisibleBy4 { byte_count : usize } ,
2018-05-08 07:36:21 +10:00
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
/// At least one of your arguments is incorrect.
DimensionsVsPixelCount {
width : u32 ,
height : u32 ,
width_x_height : usize ,
pixel_count : usize ,
} ,
}
impl fmt ::Display for BadIcon {
2019-07-10 07:49:07 +10:00
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
2018-05-08 07:36:21 +10:00
let msg = match self {
& BadIcon ::ByteCountNotDivisibleBy4 { byte_count } = > format! (
" The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels. " ,
byte_count ,
) ,
& BadIcon ::DimensionsVsPixelCount {
width ,
height ,
width_x_height ,
pixel_count ,
} = > format! (
" The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}. " ,
width , height , pixel_count , width_x_height ,
) ,
} ;
2019-07-10 07:49:07 +10:00
write! ( f , " {} " , msg )
2018-05-08 07:36:21 +10:00
}
}
impl Error for BadIcon {
fn description ( & self ) -> & str {
" A valid icon cannot be created from these arguments "
}
2019-06-18 04:27:00 +10:00
fn cause ( & self ) -> Option < & dyn Error > {
2018-05-08 07:36:21 +10:00
Some ( self )
}
}
#[ derive(Debug, Clone, PartialEq, Eq) ]
/// An icon used for the window titlebar, taskbar, etc.
pub struct Icon {
pub ( crate ) rgba : Vec < u8 > ,
pub ( crate ) width : u32 ,
pub ( crate ) height : u32 ,
}
impl Icon {
/// Creates an `Icon` from 32bpp RGBA data.
///
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
pub fn from_rgba ( rgba : Vec < u8 > , width : u32 , height : u32 ) -> Result < Self , BadIcon > {
if rgba . len ( ) % PIXEL_SIZE ! = 0 {
2019-06-22 01:33:15 +10:00
return Err ( BadIcon ::ByteCountNotDivisibleBy4 {
byte_count : rgba . len ( ) ,
} ) ;
2018-05-08 07:36:21 +10:00
}
let pixel_count = rgba . len ( ) / PIXEL_SIZE ;
if pixel_count ! = ( width * height ) as usize {
Err ( BadIcon ::DimensionsVsPixelCount {
width ,
height ,
width_x_height : ( width * height ) as usize ,
pixel_count ,
} )
} else {
2019-06-22 01:33:15 +10:00
Ok ( Icon {
rgba ,
width ,
height ,
} )
2018-05-08 07:36:21 +10:00
}
}
}