tinymist_world/font/
profile.rs1use serde::{Deserialize, Serialize};
2use sha2::Digest;
3use std::{collections::HashMap, time::SystemTime};
4use typst::text::{Coverage, FontInfo};
5
6type FontMetaDict = HashMap<String, String>;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct FontInfoItem {
10 pub meta: FontMetaDict,
12 pub info: FontInfo,
14}
15
16impl FontInfoItem {
17 pub fn new(info: FontInfo) -> Self {
18 Self {
19 meta: Default::default(),
20 info,
21 }
22 }
23
24 pub fn index(&self) -> Option<u32> {
25 self.meta.get("index").and_then(|v| v.parse::<u32>().ok())
26 }
27
28 pub fn set_index(&mut self, v: u32) {
29 self.meta.insert("index".to_owned(), v.to_string());
30 }
31
32 pub fn coverage_hash(&self) -> Option<&String> {
33 self.meta.get("coverage_hash")
34 }
35
36 pub fn set_coverage_hash(&mut self, v: String) {
37 self.meta.insert("coverage_hash".to_owned(), v);
38 }
39
40 pub fn meta(&self) -> &FontMetaDict {
41 &self.meta
42 }
43
44 pub fn info(&self) -> &FontInfo {
45 &self.info
46 }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct FontProfileItem {
51 pub hash: String,
53 pub meta: FontMetaDict,
55 pub info: Vec<FontInfoItem>,
57}
58
59fn to_micro_lossy(t: SystemTime) -> u128 {
60 t.duration_since(SystemTime::UNIX_EPOCH)
61 .unwrap()
62 .as_micros()
63}
64
65impl FontProfileItem {
66 pub fn new(kind: &str, hash: String) -> Self {
67 let mut meta: FontMetaDict = Default::default();
68 meta.insert("kind".to_owned(), kind.to_string());
69
70 Self {
71 hash,
72 meta,
73 info: Default::default(),
74 }
75 }
76
77 pub fn path(&self) -> Option<&String> {
78 self.meta.get("path")
79 }
80
81 pub fn mtime(&self) -> Option<SystemTime> {
82 self.meta.get("mtime").and_then(|v| {
83 let v = v.parse::<u64>().ok();
84 v.map(|v| SystemTime::UNIX_EPOCH + std::time::Duration::from_micros(v))
85 })
86 }
87
88 pub fn mtime_is_exact(&self, t: SystemTime) -> bool {
89 self.mtime()
90 .map(|s| {
91 let s = to_micro_lossy(s);
92 let t = to_micro_lossy(t);
93 s == t
94 })
95 .unwrap_or_default()
96 }
97
98 pub fn set_path(&mut self, v: String) {
99 self.meta.insert("path".to_owned(), v);
100 }
101
102 pub fn set_mtime(&mut self, v: SystemTime) {
103 self.meta
104 .insert("mtime".to_owned(), to_micro_lossy(v).to_string());
105 }
106
107 pub fn hash(&self) -> &str {
108 &self.hash
109 }
110
111 pub fn meta(&self) -> &FontMetaDict {
112 &self.meta
113 }
114
115 pub fn info(&self) -> &[FontInfoItem] {
116 &self.info
117 }
118
119 pub fn add_info(&mut self, info: FontInfoItem) {
120 self.info.push(info);
121 }
122}
123
124#[derive(Default, Debug, Clone, Serialize, Deserialize)]
125pub struct FontProfile {
126 pub version: String,
127 pub build_info: String,
128 pub items: Vec<FontProfileItem>,
129}
130
131pub fn get_font_coverage_hash(coverage: &Coverage) -> String {
132 let mut coverage_hash = sha2::Sha256::new();
133 coverage
134 .iter()
135 .for_each(|c| coverage_hash.update(c.to_le_bytes()));
136 let coverage_hash = coverage_hash.finalize();
137 format!("sha256:{coverage_hash:x}")
138}