monospace-core 0.1.0

Core library for Monospace: parsing, layout and ASCII rendering of diagrams
Documentation
//! The fragments: the leaves that actually call [`Surface::stamp`](crate::Surface::stamp). Each
//! writes only the cells its description names, and derives those cells from the sides and
//! positions it is handed rather than being given a cell — so the rule that fixes a cell is stated
//! once, in the fragment that owns it, instead of once per figure above. See _Complete and
//! fragment_ in [`docs/model.md`](../../../../docs/model.md).

use crate::{Orientation, Pos, Size};

pub(crate) mod border;
pub(crate) mod corner;
pub(crate) mod end;
pub(crate) mod fill;
pub(crate) mod literal;
pub(crate) mod segment;
pub(crate) mod symbol;

/// The `len` positions of a run starting at `from` and continuing in `orientation`.
///
/// A position whose coordinate would overflow `i16` is skipped rather than panicking, the same
/// way [`Buffer`](crate::Buffer) treats a position it cannot address.
pub(crate) fn run(from: Pos, len: u16, orientation: Orientation) -> impl Iterator<Item = Pos> {
    (0..len).filter_map(move |i| match orientation {
        Orientation::Horizontal => from.x.checked_add_unsigned(i).map(|x| Pos { x, y: from.y }),
        Orientation::Vertical => from.y.checked_add_unsigned(i).map(|y| Pos { x: from.x, y }),
    })
}

/// Every position of a `size`-shaped rectangle whose top-left corner is `at`.
///
/// A position whose coordinate would overflow `i16` is skipped, for the same reason [`run`] skips
/// one.
pub(crate) fn rect(at: Pos, size: Size) -> impl Iterator<Item = Pos> {
    (0..size.height).flat_map(move |dy| {
        (0..size.width).filter_map(move |dx| {
            at.y.checked_add_unsigned(dy)
                .and_then(|y| at.x.checked_add_unsigned(dx).map(|x| Pos { x, y }))
        })
    })
}