ceratophrys 0.0.3

Library to draw pixel art as code
Documentation
use crate::{Color, Image, Pixel, Position};

#[derive(Debug, Clone, Copy)]
pub struct Line {
    pub color: Color,
    pub position: Position,
    pub vector: Position,
}

impl Line {
    pub const fn new() -> Self {
        Self {
            color: Color::BLACK,
            position: Position::ORIGIN,
            vector: Position::ORIGIN,
        }
    }

    pub const fn color(self, color: Color) -> Self {
        Self { color, ..self }
    }

    pub const fn position(self, position: Position) -> Self {
        Self { position, ..self }
    }

    pub const fn vector(self, vector: Position) -> Self {
        Self { vector, ..self }
    }

    pub fn to_image(self) -> Image {
        self.into_iter().collect()
    }
}

impl Default for Line {
    fn default() -> Self {
        Self::new()
    }
}

impl IntoIterator for Line {
    type Item = Pixel;
    type IntoIter = Box<dyn Iterator<Item = Pixel>>;

    fn into_iter(self) -> Self::IntoIter {
        let p0 = Position::ORIGIN;
        let p1 = self.vector;
        let dx = (p1.x - p0.x).abs() + 1;
        let dy = (p1.y - p0.y).abs() + 1;
        let sign_y = if p1.y > p0.y { 1 } else { -1 };
        let sign_x = if p1.x > p0.x { 1 } else { -1 };
        let (f, r, n, v0, sign0, mut v1, sign1) = if dx > dy {
            let f = Position::xy as fn(i16, i16) -> Position;
            let r = Rational::new(dx, dy);
            (f, r, dx, p0.x, sign_x, p0.y, sign_y)
        } else {
            let f = Position::yx as fn(i16, i16) -> Position;
            let r = Rational::new(dy, dx);
            (f, r, dy, p0.y, sign_y, p0.x, sign_x)
        };
        Box::new((0..n).map(move |i| {
            if i != 0 && (i - 1) / r != i / r {
                v1 += sign1;
            }
            Pixel::new(f(v0 + i * sign0, v1) + self.position, self.color)
        }))
    }
}

#[derive(Debug, Clone, Copy)]
struct Rational {
    num: i16,
    den: i16,
}

impl Rational {
    const fn new(num: i16, den: i16) -> Self {
        Self { num, den }
    }
}

impl std::ops::Div<Rational> for i16 {
    type Output = i16;

    fn div(self, rhs: Rational) -> Self::Output {
        self * rhs.den / rhs.num
    }
}