tcrab_console 0.2.0

A roguelike-friendly abstraction around console/terminal emulators
Documentation
use std::hash::Hash;
use std::collections::HashMap;

#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};

use crate::Color;

pub trait CustomGlyph: Eq + Hash + Copy {}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Glyph<C: CustomGlyph> {
    Char(char),
    Custom(C),
}

impl<C: CustomGlyph> From<char> for Glyph<C> {
    fn from(c: char) -> Glyph<C> {
        Glyph::Char(c)
    }
}

impl<C: CustomGlyph> From<C> for Glyph<C> {
    fn from(c: C) -> Glyph<C> {
        Glyph::Custom(c)
    }
}

pub struct GlyphLibrary<C: CustomGlyph, D> {
    glyphs: HashMap<Glyph<C>, D>,
}

impl<C: CustomGlyph, D> GlyphLibrary<C, D> {
    pub fn new() -> GlyphLibrary<C, D> {
        GlyphLibrary {
            glyphs: HashMap::new(),
        }
    }

    pub fn define_glyph<T: Into<Glyph<C>>>(&mut self, glyph: T, def: D) {
        self.glyphs.insert(glyph.into(), def);
    }

    pub fn get_glyph_def(&self, glyph: Glyph<C>) -> &D {
        self.glyphs.get(&glyph).unwrap()
    }
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Cell<C: CustomGlyph> {
    pub glyph: Glyph<C>,
    pub foreground_color: Color,
    pub background_color: Color,
}

impl<C: CustomGlyph> Default for Cell<C> {
    fn default() -> Cell<C> {
        Cell {
            glyph: ' '.into(),
            foreground_color: Color::WHITE,
            background_color: Color::BLACK,
        }
    }
}

pub trait Canvas<C: CustomGlyph> {
    fn size(&self) -> (usize, usize);
    
    fn get_cell(&self, x: usize, y: usize) -> Cell<C>;
    fn set_cell(&mut self, x: usize, y: usize, cell: Cell<C>);

    fn fill(&mut self, cell: Cell<C>) {
        let (width, height) = self.size();
        for y in 0..height {
            for x in 0..width {
                self.set_cell(x, y, cell);
            }
        }
    }
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CellBuffer<C: CustomGlyph> {
    width: usize,
    height: usize,
    cells: Box<[Cell<C>]>,
}

impl<C: CustomGlyph> CellBuffer<C> {
    pub fn new(width: usize, height: usize, fill_cell: Cell<C>) -> CellBuffer<C> {
        CellBuffer {
            width,
            height,
            cells: vec![fill_cell; width * height].into_boxed_slice(),
        }
    }
}

impl<C: CustomGlyph> Canvas<C> for CellBuffer<C> {
    fn size(&self) -> (usize, usize) {
        (self.width, self.height)
    }
    
    fn get_cell(&self, x: usize, y: usize) -> Cell<C> {
        self.cells[y * self.width + x]
    }

    fn set_cell(&mut self, x: usize, y: usize, cell: Cell<C>) {
        self.cells[y * self.width + x] = cell;
    }
}