standard-plugin-sdk 0.1.0

Write Standard Code plugins in Rust: wasm components against standard:plugin@2.0.0
Documentation
//! The built-in 5x7 pixel font for printable ASCII, drawn for this SDK: the
//! font [`Shapes::label`](crate::Shapes::label) paints on pixels surfaces.
//! Each glyph is seven rows of five bits, the top row first and the leftmost
//! column in bit 4, so a plugin can draw the same letters its own way (in
//! cells, scaled, masked):
//!
//! ```rust,ignore
//! use standard_plugin::font::{glyph, lit, GLYPH_HEIGHT, GLYPH_WIDTH};
//! let rows = glyph('A').unwrap();
//! for y in 0..GLYPH_HEIGHT {
//!     for x in 0..GLYPH_WIDTH {
//!         if lit(&rows, x, y) { /* paint (x, y) */ }
//!     }
//! }
//! ```

/// Glyph width in pixels at scale 1.
pub const GLYPH_WIDTH: u32 = 5;
/// Glyph height in pixels at scale 1.
pub const GLYPH_HEIGHT: u32 = 7;
/// Pixels from one character to the next at scale 1.
pub const GLYPH_ADVANCE: u32 = 6;

/// The box shown for characters outside printable ASCII.
pub const MISSING: [u8; 7] = [0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1f];

const GLYPHS: [[u8; 7]; 95] = [
    [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // ' '
    [0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04], // '!'
    [0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00], // '"'
    [0x0a, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x0a], // '#'
    [0x04, 0x0f, 0x14, 0x0e, 0x05, 0x1e, 0x04], // '$'
    [0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03], // '%'
    [0x0c, 0x12, 0x14, 0x08, 0x15, 0x12, 0x0d], // '&'
    [0x04, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00], // '\''
    [0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02], // '('
    [0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08], // ')'
    [0x00, 0x04, 0x15, 0x0e, 0x15, 0x04, 0x00], // '*'
    [0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x00], // '+'
    [0x00, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x08], // ','
    [0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00], // '-'
    [0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c], // '.'
    [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00], // '/'
    [0x0e, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0e], // '0'
    [0x04, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x0e], // '1'
    [0x0e, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1f], // '2'
    [0x1f, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0e], // '3'
    [0x02, 0x06, 0x0a, 0x12, 0x1f, 0x02, 0x02], // '4'
    [0x1f, 0x10, 0x1e, 0x01, 0x01, 0x11, 0x0e], // '5'
    [0x06, 0x08, 0x10, 0x1e, 0x11, 0x11, 0x0e], // '6'
    [0x1f, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08], // '7'
    [0x0e, 0x11, 0x11, 0x0e, 0x11, 0x11, 0x0e], // '8'
    [0x0e, 0x11, 0x11, 0x0f, 0x01, 0x02, 0x0c], // '9'
    [0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x00], // ':'
    [0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x04, 0x08], // ';'
    [0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02], // '<'
    [0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00], // '='
    [0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08], // '>'
    [0x0e, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04], // '?'
    [0x0e, 0x11, 0x01, 0x0d, 0x15, 0x15, 0x0e], // '@'
    [0x0e, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11], // 'A'
    [0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e], // 'B'
    [0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e], // 'C'
    [0x1c, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1c], // 'D'
    [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f], // 'E'
    [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10], // 'F'
    [0x0e, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0f], // 'G'
    [0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11], // 'H'
    [0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e], // 'I'
    [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0c], // 'J'
    [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11], // 'K'
    [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f], // 'L'
    [0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11], // 'M'
    [0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11], // 'N'
    [0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e], // 'O'
    [0x1e, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x10], // 'P'
    [0x0e, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0d], // 'Q'
    [0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11], // 'R'
    [0x0f, 0x10, 0x10, 0x0e, 0x01, 0x01, 0x1e], // 'S'
    [0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04], // 'T'
    [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e], // 'U'
    [0x11, 0x11, 0x11, 0x11, 0x11, 0x0a, 0x04], // 'V'
    [0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0a], // 'W'
    [0x11, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x11], // 'X'
    [0x11, 0x11, 0x0a, 0x04, 0x04, 0x04, 0x04], // 'Y'
    [0x1f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1f], // 'Z'
    [0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e], // '['
    [0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00], // '\\'
    [0x0e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0e], // ']'
    [0x04, 0x0a, 0x11, 0x00, 0x00, 0x00, 0x00], // '^'
    [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f], // '_'
    [0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00], // '`'
    [0x00, 0x00, 0x0e, 0x01, 0x0f, 0x11, 0x0f], // 'a'
    [0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x1e], // 'b'
    [0x00, 0x00, 0x0e, 0x10, 0x10, 0x11, 0x0e], // 'c'
    [0x01, 0x01, 0x0d, 0x13, 0x11, 0x11, 0x0f], // 'd'
    [0x00, 0x00, 0x0e, 0x11, 0x1f, 0x10, 0x0e], // 'e'
    [0x06, 0x09, 0x08, 0x1c, 0x08, 0x08, 0x08], // 'f'
    [0x00, 0x0f, 0x11, 0x11, 0x0f, 0x01, 0x0e], // 'g'
    [0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11], // 'h'
    [0x04, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x0e], // 'i'
    [0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0c], // 'j'
    [0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12], // 'k'
    [0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e], // 'l'
    [0x00, 0x00, 0x1a, 0x15, 0x15, 0x11, 0x11], // 'm'
    [0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11], // 'n'
    [0x00, 0x00, 0x0e, 0x11, 0x11, 0x11, 0x0e], // 'o'
    [0x00, 0x00, 0x1e, 0x11, 0x1e, 0x10, 0x10], // 'p'
    [0x00, 0x00, 0x0d, 0x13, 0x0f, 0x01, 0x01], // 'q'
    [0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10], // 'r'
    [0x00, 0x00, 0x0e, 0x10, 0x0e, 0x01, 0x1e], // 's'
    [0x08, 0x08, 0x1c, 0x08, 0x08, 0x09, 0x06], // 't'
    [0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0d], // 'u'
    [0x00, 0x00, 0x11, 0x11, 0x11, 0x0a, 0x04], // 'v'
    [0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0a], // 'w'
    [0x00, 0x00, 0x11, 0x0a, 0x04, 0x0a, 0x11], // 'x'
    [0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0x0e], // 'y'
    [0x00, 0x00, 0x1f, 0x02, 0x04, 0x08, 0x1f], // 'z'
    [0x02, 0x04, 0x04, 0x08, 0x04, 0x04, 0x02], // '{'
    [0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04], // '|'
    [0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08], // '}'
    [0x00, 0x00, 0x08, 0x15, 0x02, 0x00, 0x00], // '~'
];

/// The seven rows of `character`'s glyph, or `None` outside printable
/// ASCII (U+0020 to U+007E), which [`Shapes::label`](crate::Shapes::label)
/// shows as a box ([`MISSING`]).
pub fn glyph(character: char) -> Option<[u8; 7]> {
    let code = character as u32;
    (0x20..0x7f)
        .contains(&code)
        .then(|| GLYPHS[(code - 0x20) as usize])
}

/// Whether the glyph pixel at column `x` (0 to 4) and row `y` (0 to 6) is
/// lit; false outside the glyph.
pub fn lit(rows: &[u8; 7], x: u32, y: u32) -> bool {
    x < GLYPH_WIDTH
        && (y as usize) < rows.len()
        && rows[y as usize] & (1 << (GLYPH_WIDTH - 1 - x)) != 0
}

/// The rows `label` draws for `character`: its glyph, else the box.
pub(crate) fn glyph_or_box(character: char) -> [u8; 7] {
    glyph(character).unwrap_or(MISSING)
}