tinymist_world/font/
profile.rs

1//! The profile of the font.
2
3use serde::{Deserialize, Serialize};
4use sha2::Digest;
5use std::{collections::HashMap, time::SystemTime};
6use typst::text::{Coverage, FontInfo};
7
8/// The metadata of the font.
9type FontMetaDict = HashMap<String, String>;
10
11/// The item of the font profile.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct FontInfoItem {
14    /// The metadata of the font.
15    pub meta: FontMetaDict,
16    /// The information of the font.
17    pub info: FontInfo,
18}
19
20impl FontInfoItem {
21    /// Creates a new font info item.
22    pub fn new(info: FontInfo) -> Self {
23        Self {
24            meta: Default::default(),
25            info,
26        }
27    }
28
29    /// Gets the index of the font.
30    pub fn index(&self) -> Option<u32> {
31        self.meta.get("index").and_then(|v| v.parse::<u32>().ok())
32    }
33
34    /// Sets the index of the font.
35    pub fn set_index(&mut self, v: u32) {
36        self.meta.insert("index".to_owned(), v.to_string());
37    }
38
39    /// Gets the coverage hash of the font.
40    pub fn coverage_hash(&self) -> Option<&String> {
41        self.meta.get("coverage_hash")
42    }
43
44    /// Sets the coverage hash of the font.
45    pub fn set_coverage_hash(&mut self, v: String) {
46        self.meta.insert("coverage_hash".to_owned(), v);
47    }
48
49    /// Gets the metadata of the font.
50    pub fn meta(&self) -> &FontMetaDict {
51        &self.meta
52    }
53
54    /// Gets the information of the font.
55    pub fn info(&self) -> &FontInfo {
56        &self.info
57    }
58}
59
60/// The item of the font profile.
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct FontProfileItem {
63    /// The hash of the file.
64    pub hash: String,
65    /// The metadata of the font.
66    pub meta: FontMetaDict,
67    /// The information of the font.
68    pub info: Vec<FontInfoItem>,
69}
70
71/// Converts a system time to a microsecond lossy value.
72fn to_micro_lossy(t: SystemTime) -> u128 {
73    t.duration_since(SystemTime::UNIX_EPOCH)
74        .unwrap()
75        .as_micros()
76}
77
78impl FontProfileItem {
79    /// Creates a new font profile item.
80    pub fn new(kind: &str, hash: String) -> Self {
81        let mut meta: FontMetaDict = Default::default();
82        meta.insert("kind".to_owned(), kind.to_string());
83
84        Self {
85            hash,
86            meta,
87            info: Default::default(),
88        }
89    }
90
91    /// Gets the path of the font.
92    pub fn path(&self) -> Option<&String> {
93        self.meta.get("path")
94    }
95
96    /// Gets the modification time of the font.
97    pub fn mtime(&self) -> Option<SystemTime> {
98        self.meta.get("mtime").and_then(|v| {
99            let v = v.parse::<u64>().ok();
100            v.map(|v| SystemTime::UNIX_EPOCH + tinymist_std::time::Duration::from_micros(v))
101        })
102    }
103
104    /// Checks if the modification time is exact.
105    pub fn mtime_is_exact(&self, t: SystemTime) -> bool {
106        self.mtime()
107            .map(|s| {
108                let s = to_micro_lossy(s);
109                let t = to_micro_lossy(t);
110                s == t
111            })
112            .unwrap_or_default()
113    }
114
115    /// Sets the path of the font.
116    pub fn set_path(&mut self, v: String) {
117        self.meta.insert("path".to_owned(), v);
118    }
119
120    /// Sets the modification time of the font.
121    pub fn set_mtime(&mut self, v: SystemTime) {
122        self.meta
123            .insert("mtime".to_owned(), to_micro_lossy(v).to_string());
124    }
125
126    /// Gets the hash of the font.
127    pub fn hash(&self) -> &str {
128        &self.hash
129    }
130
131    /// Gets the metadata of the font.
132    pub fn meta(&self) -> &FontMetaDict {
133        &self.meta
134    }
135
136    /// Gets the information of the font.
137    pub fn info(&self) -> &[FontInfoItem] {
138        &self.info
139    }
140
141    /// Adds an information of the font.
142    pub fn add_info(&mut self, info: FontInfoItem) {
143        self.info.push(info);
144    }
145}
146
147/// The profile of the font.
148#[derive(Default, Debug, Clone, Serialize, Deserialize)]
149pub struct FontProfile {
150    /// The version of the profile.
151    pub version: String,
152    /// The build information of the profile.
153    pub build_info: String,
154    /// The items of the profile.
155    pub items: Vec<FontProfileItem>,
156}
157
158/// Gets the coverage hash of the font.
159pub fn get_font_coverage_hash(coverage: &Coverage) -> String {
160    let mut coverage_hash = sha2::Sha256::new();
161    coverage
162        .iter()
163        .for_each(|c| coverage_hash.update(c.to_le_bytes()));
164    let coverage_hash = coverage_hash.finalize();
165    format!("sha256:{coverage_hash:x}")
166}