1#[macro_use]
8pub mod serde_ext;
9mod v1_to_v2;
10pub mod v2;
11
12use crate::serde_ext::*;
13use crate::v2::FontsManifest as FontsManifestV2;
14use anyhow::Error;
15use char_set::CharSet;
16use clonable_error::ClonableError;
17use fidl_fuchsia_fonts::{GenericFontFamily, Slant, Width, WEIGHT_NORMAL};
18use fuchsia_url::AbsolutePackageUrl;
19use offset_string::OffsetString;
20use serde::de::{self, Deserializer, Error as DeError};
21use serde::ser::Serializer;
22use serde::{Deserialize, Serialize};
23use std::fmt;
24use std::fs::{self, File};
25use std::io::BufReader;
26use std::path::{Path, PathBuf};
27use thiserror::Error;
28
29#[derive(Debug, Deserialize, Serialize)]
31#[serde(tag = "version")]
32#[serde(remote = "Self")]
36pub enum FontManifestWrapper {
37 #[serde(rename = "1")]
39 Version1(FontsManifest),
40
41 #[serde(rename = "2")]
44 Version2(FontsManifestV2),
45}
46
47impl<'de> Deserialize<'de> for FontManifestWrapper {
48 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
49 where
50 D: Deserializer<'de>,
51 {
52 let mut map = serde_json::value::Map::deserialize(deserializer)?;
54 if map.get("version").is_none() {
55 map.insert("version".to_string(), serde_json::Value::String("1".to_string()));
56 }
57
58 Ok(FontManifestWrapper::deserialize(serde_json::Value::Object(map))
60 .map_err(de::Error::custom)?)
61 }
62}
63
64impl Serialize for FontManifestWrapper {
65 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
66 where
67 S: Serializer,
68 {
69 FontManifestWrapper::serialize(self, serializer)
71 }
72}
73
74#[derive(Debug, Deserialize, Serialize)]
76pub struct FontsManifest {
77 pub families: Vec<Family>,
79}
80
81#[derive(Debug, Deserialize, Serialize)]
83pub struct Family {
84 pub family: String,
86
87 pub aliases: Option<Vec<String>>,
89
90 pub fonts: Vec<Font>,
92
93 #[serde(default = "default_fallback")]
95 pub fallback: bool,
96
97 #[serde(
99 alias = "fallback_group",
100 default = "default_generic_family",
101 with = "OptGenericFontFamily"
102 )]
103 pub generic_family: Option<GenericFontFamily>,
104}
105
106pub type LanguageSet = Vec<String>;
108
109#[derive(Debug, Deserialize, Serialize)]
112pub struct Font {
113 pub asset: PathBuf,
115
116 #[serde(default = "default_index")]
118 pub index: u32,
119
120 #[serde(default = "default_slant", with = "SlantDef")]
122 pub slant: Slant,
123
124 #[serde(default = "default_weight")]
126 pub weight: u16,
127
128 #[serde(default = "default_width", with = "WidthDef")]
130 pub width: Width,
131
132 #[serde(
134 alias = "language",
135 default = "default_languages",
136 deserialize_with = "deserialize_languages"
137 )]
138 pub languages: LanguageSet,
139
140 #[serde(default = "default_package")]
142 pub package: Option<AbsolutePackageUrl>,
143
144 #[serde(
146 default,
147 deserialize_with = "deserialize_code_points",
148 serialize_with = "serialize_code_points"
149 )]
150 pub code_points: CharSet,
151}
152
153fn default_fallback() -> bool {
154 false
155}
156
157fn default_generic_family() -> Option<GenericFontFamily> {
158 None
159}
160
161fn default_index() -> u32 {
162 0
163}
164
165fn default_slant() -> Slant {
166 Slant::Upright
167}
168
169fn default_weight() -> u16 {
170 WEIGHT_NORMAL
171}
172
173fn default_width() -> Width {
174 Width::Normal
175}
176
177fn default_languages() -> LanguageSet {
178 LanguageSet::new()
179}
180
181fn default_package() -> Option<AbsolutePackageUrl> {
182 None
183}
184
185fn deserialize_languages<'d, D>(deserializer: D) -> Result<LanguageSet, D::Error>
188where
189 D: Deserializer<'d>,
190{
191 struct LanguageSetVisitor;
192
193 impl<'de> de::Visitor<'de> for LanguageSetVisitor {
194 type Value = Vec<String>;
195
196 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
197 formatter.write_str("string or list of strings")
198 }
199
200 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
201 where
202 E: de::Error,
203 {
204 Ok(vec![s.to_string()])
205 }
206
207 fn visit_seq<S>(self, seq: S) -> Result<Self::Value, S::Error>
208 where
209 S: de::SeqAccess<'de>,
210 {
211 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))
212 }
213 }
214
215 deserializer.deserialize_any(LanguageSetVisitor)
216}
217
218fn deserialize_code_points<'d, D>(deserializer: D) -> Result<CharSet, D::Error>
219where
220 D: Deserializer<'d>,
221{
222 let offset_string = OffsetString::deserialize(deserializer)?;
223 CharSet::try_from(offset_string).map_err(|e| D::Error::custom(format!("{:?}", e)))
224}
225
226fn serialize_code_points<S>(code_points: &CharSet, serializer: S) -> Result<S::Ok, S::Error>
227where
228 S: Serializer,
229{
230 let offset_string: OffsetString = code_points.into();
231 offset_string.serialize(serializer)
232}
233
234impl FontsManifest {
235 pub fn load_from_file(path: &Path) -> Result<FontManifestWrapper, anyhow::Error> {
239 let path = fs::canonicalize(path)?;
240 let base_dir =
241 path.parent().ok_or_else(|| ManifestLoadError::InvalidPath { path: path.clone() })?;
242
243 let file = File::open(&path)
244 .map_err(|e| ManifestLoadError::ReadError { path: path.clone(), cause: e })?;
245
246 let mut wrapper: FontManifestWrapper =
247 serde_json::from_reader(BufReader::new(file)).map_err(|e| {
248 ManifestLoadError::ParseError { path: path.clone(), cause: Error::from(e).into() }
249 })?;
250
251 if let FontManifestWrapper::Version1(v1) = &mut wrapper {
254 for family in v1.families.iter_mut() {
255 for font in family.fonts.iter_mut() {
256 if font.asset.is_relative() {
257 font.asset = base_dir.join(font.asset.clone());
258 }
259 }
260 }
261 }
262
263 Ok(wrapper)
264 }
265}
266
267#[derive(Debug, Error)]
269pub enum ManifestLoadError {
270 #[error("Invalid manifest path: {:?}", path)]
272 InvalidPath {
273 path: PathBuf,
275 },
276
277 #[error("Failed to read {:?}: {:?}", path, cause)]
279 ReadError {
280 path: PathBuf,
282 #[source]
284 cause: std::io::Error,
285 },
286
287 #[error("Failed to parse {:?}: {:?}", path, cause)]
289 ParseError {
290 path: PathBuf,
292 #[source]
294 cause: ClonableError,
295 },
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301 use assert_matches::assert_matches;
302
303 #[test]
304 fn test_deserialize_manifest_version_v1_implicit() -> Result<(), Error> {
305 let json = r#"
306 {
307 "families": []
308 }
309 "#;
310
311 let wrapper: FontManifestWrapper = serde_json::from_str(json)?;
312 assert_matches!(wrapper, FontManifestWrapper::Version1(_));
313 Ok(())
314 }
315
316 #[test]
317 fn test_deserialize_manifest_version_v2() -> Result<(), Error> {
318 let json = r#"
319 {
320 "version": "2",
321 "families": [],
322 "fallback_chain": []
323 }
324 "#;
325
326 let wrapper: FontManifestWrapper = serde_json::from_str(json)?;
327 assert_matches!(wrapper, FontManifestWrapper::Version2(_));
328 Ok(())
329 }
330}