diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-05-05 22:18:33 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-05-05 22:18:33 +0200 |
| commit | 3e03667c37b86f0dfe9111c09e3bc2ea0ae70291 (patch) | |
| tree | 591194872665db6fb26cd1103057fd8883c28f8b /src | |
| parent | 6292d25afb3080f606844d7e03fec5c80f0140ff (diff) | |
Make file system loader serializable 📚
Diffstat (limited to 'src')
| -rw-r--r-- | src/env/fs.rs | 39 | ||||
| -rw-r--r-- | src/font.rs | 9 | ||||
| -rw-r--r-- | src/main.rs | 2 |
3 files changed, 32 insertions, 18 deletions
diff --git a/src/env/fs.rs b/src/env/fs.rs index 98378722..5f18191b 100644 --- a/src/env/fs.rs +++ b/src/env/fs.rs @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use memmap2::Mmap; +use serde::{Deserialize, Serialize}; use ttf_parser::{name_id, Face}; use walkdir::WalkDir; @@ -14,10 +15,11 @@ use crate::font::{FaceInfo, FontStretch, FontStyle, FontVariant, FontWeight}; /// Loads fonts and resources from the local file system. /// /// _This is only available when the `fs` feature is enabled._ -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct FsLoader { faces: Vec<FaceInfo>, - paths: Vec<PathBuf>, + files: Vec<PathBuf>, + #[serde(skip)] cache: FileCache, } @@ -30,7 +32,7 @@ impl FsLoader { pub fn new() -> Self { Self { faces: vec![], - paths: vec![], + files: vec![], cache: HashMap::new(), } } @@ -64,19 +66,22 @@ impl FsLoader { let windir = std::env::var("WINDIR").unwrap_or_else(|_| "C:\\Windows".to_string()); - self.search_dir(Path::new(&windir).join("Fonts")); + self.search_path(Path::new(&windir).join("Fonts")); if let Some(roaming) = dirs::config_dir() { - self.search_dir(roaming.join("Microsoft\\Windows\\Fonts")); + self.search_path(roaming.join("Microsoft\\Windows\\Fonts")); } if let Some(local) = dirs::cache_dir() { - self.search_dir(local.join("Microsoft\\Windows\\Fonts")); + self.search_path(local.join("Microsoft\\Windows\\Fonts")); } } - /// Search for all fonts in a directory. - pub fn search_dir(&mut self, dir: impl AsRef<Path>) { + /// Search for all fonts at a path. + /// + /// If the path is a directory, all contained fonts will be searched for + /// recursively. + pub fn search_path(&mut self, dir: impl AsRef<Path>) { let walk = WalkDir::new(dir) .follow_links(true) .sort_by(|a, b| a.file_name().cmp(b.file_name())) @@ -102,8 +107,9 @@ impl FsLoader { /// /// The file may form a font collection and contain multiple font faces, /// which will then all be indexed. - pub fn search_file(&mut self, path: impl AsRef<Path>) -> io::Result<()> { + fn search_file(&mut self, path: impl AsRef<Path>) -> io::Result<()> { let path = path.as_ref(); + let path = path.strip_prefix(".").unwrap_or(path); let file = File::open(path)?; let mmap = unsafe { Mmap::map(&file)? }; @@ -149,10 +155,15 @@ impl FsLoader { // Merge with an existing entry for the same family name. self.faces.push(FaceInfo { family, variant, index }); - self.paths.push(path.to_owned()); + self.files.push(path.to_owned()); Ok(()) } + + /// Paths to font files, parallel to [`faces()`](Self::faces). + pub fn files(&self) -> &[PathBuf] { + &self.files + } } impl Loader for FsLoader { @@ -161,7 +172,7 @@ impl Loader for FsLoader { } fn load_face(&mut self, idx: usize) -> Option<Buffer> { - load(&mut self.cache, &self.paths[idx]) + load(&mut self.cache, &self.files[idx]) } fn load_file(&mut self, url: &str) -> Option<Buffer> { @@ -169,6 +180,7 @@ impl Loader for FsLoader { } } +/// Load from the file system using a cache. fn load(cache: &mut FileCache, path: &Path) -> Option<Buffer> { match cache.entry(path.to_owned()) { Entry::Occupied(entry) => entry.get().clone(), @@ -186,10 +198,9 @@ mod tests { #[test] fn test_index_font_dir() { let mut loader = FsLoader::new(); - loader.search_dir("fonts"); - loader.paths.sort(); + loader.search_path("fonts"); - assert_eq!(loader.paths, &[ + assert_eq!(loader.files, &[ Path::new("fonts/EBGaramond-Bold.ttf"), Path::new("fonts/EBGaramond-BoldItalic.ttf"), Path::new("fonts/EBGaramond-Italic.ttf"), diff --git a/src/font.rs b/src/font.rs index 52912664..5a83f6c4 100644 --- a/src/font.rs +++ b/src/font.rs @@ -25,7 +25,7 @@ impl Face { // SAFETY: // - The slices's location is stable in memory: // - We don't move the underlying vector - // - Nobody else can move it since we haved a strong ref to the `Rc`. + // - Nobody else can move it since we have a strong ref to the `Rc`. // - The internal static lifetime is not leaked because its rewritten // to the self-lifetime in `ttf()`. let slice: &'static [u8] = @@ -151,19 +151,20 @@ impl Em { } /// Properties of a single font face. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct FaceInfo { /// The typographic font family this face is part of. pub family: String, /// Properties that distinguish this face from other faces in the same /// family. + #[serde(flatten)] pub variant: FontVariant, /// The collection index in the font file. pub index: u32, } /// Properties that distinguish a face from other faces in the same family. -#[derive(Default, Debug, Copy, Clone, PartialEq)] +#[derive(Default, Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub struct FontVariant { /// The style of the face (normal / italic / oblique). pub style: FontStyle, @@ -183,6 +184,7 @@ impl FontVariant { /// The style of a font face. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] pub enum FontStyle { /// The default style. Normal, @@ -347,6 +349,7 @@ impl Debug for FontWeight { /// The width of a font face. #[derive(Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] +#[serde(transparent)] pub struct FontStretch(f32); impl FontStretch { diff --git a/src/main.rs b/src/main.rs index 05827681..fa98d4c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,7 @@ fn main() -> anyhow::Result<()> { let src = fs::read_to_string(src_path).context("Failed to read from source file.")?; let mut loader = FsLoader::new(); - loader.search_dir("fonts"); + loader.search_path("fonts"); loader.search_system(); let mut env = Env::new(loader); |
