1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Types and helpers shared across modules

use std::fmt::{Display, Formatter};

use smol_str::SmolStr;
pub use write_fonts::types::GlyphId;

mod glyph_class;
mod glyph_map;

pub use glyph_class::GlyphClass;
pub use glyph_map::GlyphMap;

/// A glyph name
pub type GlyphName = SmolStr;

/// A glyph or glyph class.
///
/// Various places in the FEA spec accept either a single glyph or a glyph class.
#[derive(Debug, Clone)]
pub enum GlyphOrClass {
    /// A resolved GlyphId
    Glyph(GlyphId),
    /// A resolved glyph class
    Class(GlyphClass),
    /// An explicit `<NULL>` glyph
    Null,
}

/// Either a glyph name or a CID
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GlyphIdent {
    /// A glyph name
    Name(GlyphName),
    /// a CID
    Cid(u16),
}

impl<T: Into<GlyphName>> From<T> for GlyphIdent {
    fn from(src: T) -> Self {
        GlyphIdent::Name(src.into())
    }
}

impl Display for GlyphIdent {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            GlyphIdent::Name(name) => write!(f, "{}", name),
            GlyphIdent::Cid(cid) => write!(f, "Cid({})", cid),
        }
    }
}

impl GlyphOrClass {
    pub(crate) fn len(&self) -> usize {
        match self {
            GlyphOrClass::Class(cls) => cls.len(),
            _ => 1,
        }
    }

    pub(crate) fn is_class(&self) -> bool {
        matches!(self, GlyphOrClass::Class(_))
    }

    pub(crate) fn is_null(&self) -> bool {
        matches!(self, GlyphOrClass::Null)
    }

    pub(crate) fn to_class(&self) -> Option<GlyphClass> {
        match self {
            GlyphOrClass::Glyph(gid) => Some((*gid).into()),
            GlyphOrClass::Class(class) => Some(class.clone()),
            GlyphOrClass::Null => None,
        }
    }

    pub(crate) fn to_glyph(&self) -> Option<GlyphId> {
        match self {
            GlyphOrClass::Glyph(gid) => Some(*gid),
            _ => None,
        }
    }

    pub(crate) fn iter(&self) -> impl Iterator<Item = GlyphId> + '_ {
        let mut idx = 0;
        std::iter::from_fn(move || {
            let next = match &self {
                GlyphOrClass::Glyph(id) if idx == 0 => Some(*id),
                GlyphOrClass::Class(cls) => cls.items().get(idx).copied(),
                _ => None,
            };
            idx += 1;
            next
        })
    }

    /// an iterator that loops forever, and which returns NOTDEF for null.
    ///
    /// this is used to create the replacement targets for class -> glyph or
    /// class -> null substitutions.
    pub(crate) fn into_iter_for_target(self) -> impl Iterator<Item = GlyphId> {
        let mut idx = 0;
        std::iter::from_fn(move || {
            let next = match &self {
                GlyphOrClass::Glyph(id) if idx == 0 => Some(*id),
                GlyphOrClass::Null if idx == 0 => Some(GlyphId::NOTDEF),
                GlyphOrClass::Class(cls) => cls.items().get(idx).copied(),
                _ => None,
            };
            idx += 1;
            idx %= self.len();
            next
        })
    }
}