Skip to main content

webfont_generator/incremental/
helpers.rs

1use std::io::Result;
2
3use super::sources::{MembershipChange, change_membership};
4use crate::result::RegenerateError;
5use crate::{GenerateWebfontsResult, GlyphChange, RegenerationFiles, VariantFileSet};
6
7impl GenerateWebfontsResult {
8    fn membership_for_change(
9        &self,
10        path: &str,
11        change: MembershipChange<'_>,
12    ) -> Result<RegenerationFiles> {
13        let names = self.options.variants.as_ref().map(|family| {
14            family
15                .variants
16                .iter()
17                .map(|variant| variant.name.clone())
18                .collect::<Vec<_>>()
19        });
20        let mut sets = match &self.options.variants {
21            Some(family) => family
22                .variants
23                .iter()
24                .map(|variant| variant.source_ids.clone())
25                .collect(),
26            None => vec![
27                self.source_files
28                    .iter()
29                    .map(|source| source.id.clone())
30                    .collect(),
31            ],
32        };
33        change_membership(&mut sets, names.as_deref(), path, change)?;
34        Ok(match names {
35            Some(names) => RegenerationFiles::Variants(
36                names
37                    .into_iter()
38                    .zip(sets)
39                    .map(|(variant, files)| VariantFileSet { variant, files })
40                    .collect(),
41            ),
42            None => RegenerationFiles::Single(sets.remove(0)),
43        })
44    }
45
46    /// Append a new file and regenerate. Families require an existing target variant.
47    /// `name` overrides the file stem. Requires incremental generation and inherits
48    /// [`Self::regenerate`]'s validation, callback restrictions and write/failure semantics.
49    pub fn add(&mut self, path: String, name: Option<String>, variant: Option<&str>) -> Result<()> {
50        let files = self.membership_for_change(&path, MembershipChange::Add(variant))?;
51        self.regenerate(&files, &[(path, GlyphChange::Added { name })])
52    }
53
54    /// Re-read an existing file in every consuming design, preserving its position.
55    /// An absent `name` preserves the glyph name. Inherits [`Self::regenerate`]'s semantics.
56    pub fn update(&mut self, path: String, name: Option<String>) -> Result<()> {
57        let files = self.membership_for_change(&path, MembershipChange::Update)?;
58        self.regenerate(&files, &[(path, GlyphChange::Changed { name })])
59    }
60
61    /// Remove an existing file from every design without deleting it from disk.
62    /// Rejects empty designs. Inherits [`Self::regenerate`]'s semantics.
63    pub fn remove(&mut self, path: String) -> Result<()> {
64        let files = self.membership_for_change(&path, MembershipChange::Remove)?;
65        self.regenerate(&files, &[(path, GlyphChange::Removed)])
66    }
67
68    /// Consuming async equivalent of [`Self::add`], with [`Self::regenerate_async`]'s recovery semantics.
69    pub async fn add_async(
70        self,
71        path: String,
72        name: Option<String>,
73        variant: Option<String>,
74    ) -> std::result::Result<Self, RegenerateError> {
75        let files =
76            match self.membership_for_change(&path, MembershipChange::Add(variant.as_deref())) {
77                Ok(files) => files,
78                Err(error) => return Err(RegenerateError::new(Some(self), error)),
79            };
80        self.regenerate_async(files, vec![(path, GlyphChange::Added { name })])
81            .await
82    }
83
84    /// Consuming async equivalent of [`Self::update`], with [`Self::regenerate_async`]'s recovery semantics.
85    pub async fn update_async(
86        self,
87        path: String,
88        name: Option<String>,
89    ) -> std::result::Result<Self, RegenerateError> {
90        let files = match self.membership_for_change(&path, MembershipChange::Update) {
91            Ok(files) => files,
92            Err(error) => return Err(RegenerateError::new(Some(self), error)),
93        };
94        self.regenerate_async(files, vec![(path, GlyphChange::Changed { name })])
95            .await
96    }
97
98    /// Consuming async equivalent of [`Self::remove`], with [`Self::regenerate_async`]'s recovery semantics.
99    pub async fn remove_async(self, path: String) -> std::result::Result<Self, RegenerateError> {
100        let files = match self.membership_for_change(&path, MembershipChange::Remove) {
101            Ok(files) => files,
102            Err(error) => return Err(RegenerateError::new(Some(self), error)),
103        };
104        self.regenerate_async(files, vec![(path, GlyphChange::Removed)])
105            .await
106    }
107
108    /// Snapshot-preserving async addition for adapters; inherits [`Self::regenerate_snapshot_async`]'s lineage and cancellation rules.
109    pub async fn add_snapshot_async(
110        &self,
111        path: String,
112        name: Option<String>,
113        variant: Option<String>,
114    ) -> Result<Self> {
115        let files = self.membership_for_change(&path, MembershipChange::Add(variant.as_deref()))?;
116        self.regenerate_snapshot_async(files, Some(vec![(path, GlyphChange::Added { name })]))
117            .await
118    }
119
120    /// Snapshot-preserving async update for adapters; inherits [`Self::regenerate_snapshot_async`]'s lineage and cancellation rules.
121    pub async fn update_snapshot_async(&self, path: String, name: Option<String>) -> Result<Self> {
122        let files = self.membership_for_change(&path, MembershipChange::Update)?;
123        self.regenerate_snapshot_async(files, Some(vec![(path, GlyphChange::Changed { name })]))
124            .await
125    }
126
127    /// Snapshot-preserving async removal for adapters; inherits [`Self::regenerate_snapshot_async`]'s lineage and cancellation rules.
128    pub async fn remove_snapshot_async(&self, path: String) -> Result<Self> {
129        let files = self.membership_for_change(&path, MembershipChange::Remove)?;
130        self.regenerate_snapshot_async(files, Some(vec![(path, GlyphChange::Removed)]))
131            .await
132    }
133}