summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-05-05 22:18:33 +0200
committerLaurenz <laurmaedje@gmail.com>2021-05-05 22:18:33 +0200
commit3e03667c37b86f0dfe9111c09e3bc2ea0ae70291 (patch)
tree591194872665db6fb26cd1103057fd8883c28f8b /src
parent6292d25afb3080f606844d7e03fec5c80f0140ff (diff)
Make file system loader serializable 📚
Diffstat (limited to 'src')
-rw-r--r--src/env/fs.rs39
-rw-r--r--src/font.rs9
-rw-r--r--src/main.rs2
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);