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 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}