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
use std::io::Result;

use crate::metrics::Metrics;
use crate::{Axes, Characters, Features, Glyph, Names, Palettes, Tables};

/// A font.
pub struct Font {
    case: Box<dyn Case>,
}

macro_rules! implement {
    (
        $(
            $(#[$attribute:meta])*
            fn $function:ident($($argument_name:ident: $argument_type:ty),*) -> $type:ty;
        )+
    ) => (
        /// A type that represents a font in a specific format.
        pub trait Case {
            $(
                $(#[$attribute])*
                fn $function(&mut self $(, $argument_name: $argument_type)*) -> Result<$type>;
            )+
        }

        impl Font {
            $(
                $(#[$attribute])*
                #[inline]
                pub fn $function(&mut self $(, $argument_name: $argument_type)*) -> Result<$type> {
                    self.case.$function($($argument_name),*)
                }
            )+
        }
    );
}

implement! {
    /// Return the axes.
    fn axes() -> Axes;
    /// Return the characters.
    fn characters() -> Characters;
    /// Return the features.
    fn features() -> Features;
    /// Return the metrics.
    fn metrics() -> Metrics;
    /// Return the names.
    fn names() -> Names;
    /// Return the palettes.
    fn palettes() -> Palettes;
    /// Return the tables.
    fn tables() -> Tables;
    /// Return the glyph of a character.
    fn glyph(character: char) -> Option<Glyph>;
}

pub fn read<T: typeface::tape::Read + 'static>(mut tape: T) -> Result<Vec<Font>> {
    use opentype::truetype::Tag;

    let tag = tape.peek::<Tag>()?;
    if opentype::accept(&tag) {
        Ok(crate::formats::opentype::read(tape)?
            .into_iter()
            .map(|font| Font {
                case: Box::new(font),
            })
            .collect())
    } else if webtype::accept(&tag) {
        Ok(crate::formats::webtype::read(tape)?
            .into_iter()
            .map(|font| Font {
                case: Box::new(font),
            })
            .collect())
    } else {
        error!("found an unknown file format")
    }
}