use const_default::ConstDefault;
use std::fmt::Display;
#[derive(Debug, Clone, Copy)]
pub struct Pixel {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl ConstDefault for Pixel {
const DEFAULT: Pixel = Pixel::new(0, 0, 0);
}
impl Display for Pixel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}\t{}\t{}", self.r, self.g, self.b)
}
}
pub struct Ppm<const W: usize, const H: usize> {
rows: Vec<Vec<Pixel>>,
}
impl Pixel {
pub const fn new(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b }
}
}
impl<const W: usize, const H: usize> Ppm<W, H> {
pub fn new(rows: Vec<Vec<Pixel>>) -> Self {
assert_eq!(rows.len(), H);
for row in rows.iter() {
assert_eq!(row.len(), W);
}
unsafe { Self::new_unchecked(rows) }
}
pub unsafe fn new_unchecked(rows: Vec<Vec<Pixel>>) -> Self {
Self { rows }
}
pub fn gen<F>(f: F) -> Self
where
F: Fn(usize, usize) -> Pixel,
{
let mut rows = Vec::<Vec<Pixel>>::with_capacity(H);
for y in 0..H {
let mut row_data = Vec::<Pixel>::with_capacity(W);
for x in 0..W {
row_data.push(f(x, y));
}
rows.push(row_data);
}
unsafe { Self::new_unchecked(rows) }
}
}
impl<const W: usize, const H: usize> Display for Ppm<W, H> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "P3")?;
writeln!(f, "{}\t{}", W, H)?;
writeln!(f, "255")?;
for row in self.rows.iter() {
for pixel in row.iter() {
writeln!(f, "{}", pixel)?;
}
}
Ok(())
}
}
impl IntoIterator for Pixel {
type Item = u8;
type IntoIter = std::array::IntoIter<u8, 3>;
fn into_iter(self) -> Self::IntoIter {
[self.r, self.g, self.b].into_iter()
}
}