use crate::error::{Error, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinaryImage {
width: usize,
height: usize,
bits: Vec<bool>,
}
impl BinaryImage {
pub fn new(width: usize, height: usize) -> Self {
assert!(
width > 0 && height > 0,
"BinaryImage dimensions must be > 0"
);
BinaryImage {
width,
height,
bits: vec![false; width * height],
}
}
pub fn from_bits(width: usize, height: usize, bits: Vec<bool>) -> Result<Self> {
if width == 0 || height == 0 {
return Err(Error::invalid_parameter("zero-sized binary image"));
}
if bits.len() != width * height {
return Err(Error::invalid_parameter(format!(
"bits length {} does not match {width}x{height}",
bits.len()
)));
}
Ok(BinaryImage {
width,
height,
bits,
})
}
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
pub fn get(&self, x: usize, y: usize) -> bool {
if x >= self.width || y >= self.height {
return false;
}
self.bits[y * self.width + x]
}
pub fn set(&mut self, x: usize, y: usize, dark: bool) {
assert!(
x < self.width && y < self.height,
"BinaryImage::set out of bounds"
);
self.bits[y * self.width + x] = dark;
}
pub fn count_dark(&self) -> usize {
self.bits.iter().filter(|&&b| b).count()
}
pub fn bits(&self) -> &[bool] {
&self.bits
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_is_all_light() {
let img = BinaryImage::new(4, 3);
assert_eq!(img.width(), 4);
assert_eq!(img.height(), 3);
assert_eq!(img.count_dark(), 0);
assert!(!img.get(0, 0));
}
#[test]
fn set_and_get() {
let mut img = BinaryImage::new(3, 3);
img.set(1, 2, true);
assert!(img.get(1, 2));
assert!(!img.get(0, 0));
assert_eq!(img.count_dark(), 1);
}
#[test]
fn out_of_bounds_get_is_light() {
let img = BinaryImage::new(2, 2);
assert!(!img.get(5, 5));
assert!(!img.get(0, 100));
}
#[test]
fn from_bits_validates_length() {
assert!(BinaryImage::from_bits(2, 2, vec![false; 4]).is_ok());
assert!(BinaryImage::from_bits(2, 2, vec![false; 3]).is_err());
assert!(BinaryImage::from_bits(0, 2, vec![]).is_err());
}
}