font_map_macros/
lib.rs

1use font_map_core::{codegen::FontDesc, font::Font};
2use proc_macro::TokenStream;
3use syn::{parse::Parse, parse_macro_input, Ident, Lit, LitStr};
4
5struct FontParameters {
6    identifier: Ident,
7    path: LitStr,
8    skip_categories: bool,
9}
10impl Parse for FontParameters {
11    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
12        let identifier = input.parse()?;
13        input.parse::<syn::Token![,]>()?;
14        let path = input.parse()?;
15
16        let mut skip_categories = false;
17
18        while input.parse::<syn::Token![,]>().is_ok() {
19            let name = input.parse::<Ident>()?;
20            input.parse::<syn::Token![=]>()?;
21            let value = input.parse::<Lit>()?;
22
23            match name {
24                n if n == "skip_categories" => match value {
25                    Lit::Bool(b) => skip_categories = b.value,
26                    _ => {
27                        return Err(syn::Error::new_spanned(
28                            value,
29                            "Expected a boolean value for `skip_categories`",
30                        ))
31                    }
32                },
33
34                _ => {
35                    return Err(syn::Error::new_spanned(
36                        name,
37                        "Unknown parameter, expected `skip_categories`",
38                    ))
39                }
40            }
41        }
42
43        Ok(Self {
44            identifier,
45            path,
46            skip_categories,
47        })
48    }
49}
50
51#[proc_macro]
52pub fn font(input: TokenStream) -> TokenStream {
53    //
54    // Parse input as an ident, then a string literal - like:
55    // font!(Icon, "path/to/font.ttf");
56    let input = parse_macro_input!(input as FontParameters);
57
58    let identifier = input.identifier.to_string();
59    let path = input.path.value();
60
61    let font_bytes =
62        std::fs::read(&path).unwrap_or_else(|_| panic!("Failed to read font at `{path}`"));
63    let font = Font::new(&font_bytes).unwrap_or_else(|_| panic!("Invalid font file: `{path}`"));
64
65    let generator = FontDesc::from_font(&identifier, &font, input.skip_categories);
66    generator.codegen(None).into()
67}