ori_macro/
font.rs

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
use std::{
    env, fs,
    hash::{DefaultHasher, Hasher},
    io,
    path::{Path, PathBuf},
};

use quote::quote;
use syn::LitStr;

use crate::find_core;

fn load_dir(path: &Path) -> io::Result<Vec<PathBuf>> {
    let mut fonts = Vec::new();

    for entry in path.read_dir()? {
        let entry = entry?;
        let input = load_font(&entry.path())?;
        fonts.extend(input);
    }

    Ok(fonts)
}

fn load_file(path: &Path) -> io::Result<Vec<PathBuf>> {
    Ok(vec![path.to_owned()])
}

fn load_font(path: &Path) -> io::Result<Vec<PathBuf>> {
    if path.is_dir() {
        load_dir(path)
    } else {
        load_file(path)
    }
}

pub fn include_font(input: proc_macro::TokenStream) -> manyhow::Result<proc_macro::TokenStream> {
    let input: LitStr = syn::parse(input)?;

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let manifest_dir = Path::new(&manifest_dir);
    let path = manifest_dir.join(input.value());

    let fonts = match load_font(&path) {
        Ok(style) => style,
        Err(err) => manyhow::bail!(input, "io error: {}", err),
    };

    let mut compressed = Vec::new();

    compressed.extend_from_slice(&u32::to_le_bytes(fonts.len() as u32));

    for font in fonts {
        let data = fs::read(&font).unwrap();

        compressed.extend_from_slice(&u32::to_le_bytes(data.len() as u32));
        compressed.extend_from_slice(&data);
    }

    let compressed = miniz_oxide::deflate::compress_to_vec(&compressed, 10);

    let mut hasher = DefaultHasher::new();

    hasher.write(&compressed);

    let file_name = format!("font-{}.bin", hasher.finish());

    let out_dir = env!("OUT_DIR");
    let bin_path = Path::new(&out_dir).join(&file_name);

    if !bin_path.exists() {
        fs::write(&bin_path, &compressed).unwrap();
    }

    let bin_path_str = bin_path.to_string_lossy();

    let ori_core = find_core();

    let expanded = quote! {
        #ori_core::text::FontSource::Bundle(
            ::std::borrow::Cow::Borrowed(::std::include_bytes!(#bin_path_str))
        )
    };

    Ok(expanded.into())
}