multi-mono-font 0.5.0

Multi mono font mixed typesetting for embedded-graphics
Documentation
//! Glyph mapping.
//!
//! A glyph mapping defines the position of characters in a [`MultiMonoFont`] image. This module provides
//! predefined mappings for common glyph subsets, but custom mappings are also supported.
//!
//! # Custom mappings
//!
//! Custom mappings can be defined in three different ways:
//! * The [`StrGlyphMapping`] type can be used to specify a character mapping by encoding the
//!   mapping as a string.
//!
//! # `StrGlyphMapping` encoding
//!
//! Strings without a `\0` character can be used to directly map a character to its position in
//! the mapping string:
//!
//! ```
//! use multi_mono_font::mapping::StrGlyphMapping;
//!
//! let mapping = StrGlyphMapping::new("abcdef1234", 0);
//! assert_eq!(mapping.index('a'), 0);
//! assert_eq!(mapping.index('b'), 1);
//! assert_eq!(mapping.index('1'), 6);
//! assert_eq!(mapping.index('2'), 7);
//! ```
//!
//! This direct mapping is inefficient for mappings that map consecutive ranges of characters to
//! consecutive index ranges. To define a range of characters a `\0` character followed by the
//! start and end characters of the inclusive range can be used. This way the mapping in the previous
//! example can be abbreviated to:
//!
//! ```
//! use multi_mono_font::mapping::StrGlyphMapping;
//!
//! let mapping = StrGlyphMapping::new("\0af\014", 0);
//! assert_eq!(mapping.index('a'), 0);
//! assert_eq!(mapping.index('b'), 1);
//! assert_eq!(mapping.index('1'), 6);
//! assert_eq!(mapping.index('2'), 7);
//! ```
//!
//! [`MultiMonoFont`]: super::MultiMonoFont

/// Glyph mapping stored as a UTF-8 string.
///
/// See the [module-level documentation] for more details.
///
/// [module-level documentation]: self
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StrGlyphMapping<'a> {
    data: &'a str,
    replacement_index: usize,
}

impl<'a> StrGlyphMapping<'a> {
    /// Creates a new glyph mapping.
    pub const fn new(data: &'a str, replacement_index: usize) -> Self {
        Self {
            data,
            replacement_index,
        }
    }

    /// Returns an iterator over the characters in this mapping.
    pub fn chars(&self) -> impl Iterator<Item = char> + '_ {
        let mut chars = self.data.chars();

        core::iter::from_fn(move || {
            let range = match chars.next()? {
                '\0' => {
                    let start = chars.next()?;
                    let end = chars.next()?;

                    start..=end
                }
                c => c..=c,
            };

            Some(range)
        })
        .flatten()
    }

    /// Returns if the mapping contains the given char.
    pub fn contains(&self, c: char) -> bool {
        self.chars().any(|v| v == c)
    }

    pub fn index(&self, c: char) -> usize {
        // PERF: use ranges instead of chars iter
        self.chars()
            .enumerate()
            .find(|(_, v)| c == *v)
            .map(|(index, _)| index)
            .unwrap_or(self.replacement_index)
    }
}

macro_rules! impl_mapping {
    ($( $(#[$meta:meta])* ($enum_variant:ident, $constant:ident, $mapping:expr), )*) => {
        /// Mapping.
        ///
        /// This enum lists all mappings that are included in embedded-graphics. It is used
        /// to automatically generate font data for all mappings and isn't normally used in
        /// applications.
        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub enum Mapping {
            $(
                $(#[$meta])*
                $enum_variant,
            )*
        }

        impl Mapping {
            /// Returns an iterator over all mappings.
            pub fn iter() -> impl Iterator<Item = Self> {
                const ALL: &[Mapping] = &[$(Mapping::$enum_variant),*];

                ALL.iter().copied()
            }

            /// Returns the MIME identifier for this mapping.
            pub const fn mime(self) -> &'static str {
                match self {
                    $(Mapping::$enum_variant => stringify!($constant)),*
                }
            }

            /// Returns a glyph mapping for this mapping.
            pub const fn glyph_mapping(self) -> &'static StrGlyphMapping<'static> {
                match self {
                    $(Self::$enum_variant => &$constant),*
                }
            }
        }

        $(
            $(#[$meta])*
            pub const $constant: StrGlyphMapping = StrGlyphMapping::new($mapping, '?' as usize - ' ' as usize);
        )*
    };
}

impl_mapping!(
    /// ASCII.
    (Ascii, ASCII, "\0\u{20}\u{7f}"),

    /// ISO/IEC 8859 Part 10: Latin-6, Nordic.
    (Iso8859_10, ISO_8859_10, "\0\u{20}\u{7f}\u{a0}\u{104}\u{112}\u{122}\u{12a}\u{128}\u{136}\u{a7}\u{13b}\u{110}\u{160}\u{166}\u{17d}\u{ad}\u{16a}\u{14a}\u{b0}\u{105}\u{113}\u{123}\u{12b}\u{129}\u{137}\u{b7}\u{13c}\u{111}\u{161}\u{167}\u{17e}\u{2015}\u{16b}\u{14b}\u{100}\0\u{c1}\u{c6}\u{12e}\u{10c}\u{c9}\u{118}\u{cb}\u{116}\0\u{cd}\u{d0}\u{145}\u{14c}\0\u{d3}\u{d6}\u{168}\u{d8}\u{172}\0\u{da}\u{df}\u{101}\0\u{e1}\u{e6}\u{12f}\u{10d}\u{e9}\u{119}\u{eb}\u{117}\0\u{ed}\u{f0}\u{146}\u{14d}\0\u{f3}\u{f6}\u{169}\u{f8}\u{173}\0\u{fa}\u{fe}\u{138}"),
);