use std::fmt;
use crate::error::{Error, Result};
#[derive(Clone)]
pub struct Icon {
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) rgba: Vec<u8>,
}
impl Icon {
pub fn from_rgba(width: u32, height: u32, rgba: Vec<u8>) -> Result<Icon> {
let expected = (width as usize)
.checked_mul(height as usize)
.and_then(|pixels| pixels.checked_mul(4));
match expected {
Some(n) if n != 0 && n == rgba.len() => Ok(Icon {
width,
height,
rgba,
}),
_ => Err(Error::Backend(format!(
"icon data is {} bytes but {}x{} RGBA needs {}",
rgba.len(),
width,
height,
(width as u64) * (height as u64) * 4,
))),
}
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn rgba(&self) -> &[u8] {
&self.rgba
}
}
impl fmt::Debug for Icon {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Icon")
.field("width", &self.width)
.field("height", &self.height)
.field("bytes", &self.rgba.len())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accepts_matching_length() {
let icon = Icon::from_rgba(2, 1, vec![0; 8]).unwrap();
assert_eq!(icon.width(), 2);
assert_eq!(icon.height(), 1);
assert_eq!(icon.rgba().len(), 8);
}
#[test]
fn rejects_wrong_length() {
assert!(Icon::from_rgba(2, 2, vec![0; 8]).is_err());
}
#[test]
fn rejects_empty() {
assert!(Icon::from_rgba(0, 0, vec![]).is_err());
}
}