Skip to main content

devpage_design/ids/
remembering.rs

1//! Files read with each design file's last parse remembered: a new parse is
2//! matched against the last ([`super::matched`]), so a save's elements keep
3//! their ids — and the nodes they make theirs. What a store that keeps
4//! designs between saves reads through; the parses outlive any one read.
5
6use std::collections::HashMap;
7use std::sync::{Arc, Mutex, MutexGuard};
8
9use crate::Problem;
10use crate::fonts::FontFile;
11use crate::parse::{self, File};
12use crate::scene::{Files, ImageFile};
13
14/// Each design file's last parse, by path. A clone shares them: a store
15/// keeps one and reads through it with whichever files each resolve uses.
16#[derive(Clone, Default)]
17pub struct Parses(Arc<Mutex<HashMap<String, Arc<File>>>>);
18
19impl Parses {
20    fn lock(&self) -> MutexGuard<'_, HashMap<String, Arc<File>>> {
21        self.0
22            .lock()
23            .unwrap_or_else(|poisoned| poisoned.into_inner())
24    }
25
26    /// Whether `path`'s last parse is held.
27    pub fn holds(&self, path: &str) -> bool {
28        self.lock().contains_key(path)
29    }
30
31    /// Lets `path`'s last parse go: its next parse starts its ids afresh.
32    pub fn forget(&self, path: &str) {
33        self.lock().remove(path);
34    }
35}
36
37/// `files`, with each design file parsed matched against its last parse in
38/// [`Parses`] — and remembered there as its last.
39pub struct Remembering<F> {
40    pub files: F,
41    parses: Parses,
42}
43
44impl<F> Remembering<F> {
45    /// `files`, remembering their parses from none.
46    pub fn new(files: F) -> Remembering<F> {
47        Remembering::with(files, &Parses::default())
48    }
49
50    /// `files`, remembering their parses in `parses`, shared.
51    pub fn with(files: F, parses: &Parses) -> Remembering<F> {
52        Remembering {
53            files,
54            parses: parses.clone(),
55        }
56    }
57}
58
59impl<F: Files> Files for Remembering<F> {
60    fn bytes(&self, path: &str) -> Option<Vec<u8>> {
61        self.files.bytes(path)
62    }
63
64    fn list(&self, path: &str) -> Option<Vec<String>> {
65        self.files.list(path)
66    }
67
68    fn read(&self, path: &str) -> Option<String> {
69        self.files.read(path)
70    }
71
72    /// `source` parsed and matched against `path`'s last parse, which it
73    /// then is.
74    fn parse(&self, path: &str, source: &str) -> Result<Arc<File>, Problem> {
75        let fresh = parse::parse(source)?;
76        let mut last = self.parses.lock();
77        let file = Arc::new(match last.get(path) {
78            Some(last) => super::matched(fresh, last),
79            None => fresh,
80        });
81        last.insert(path.to_string(), file.clone());
82        Ok(file)
83    }
84
85    fn image(&self, path: &str) -> Option<Result<Arc<ImageFile>, String>> {
86        self.files.image(path)
87    }
88
89    fn font(&self, path: &str) -> Option<Result<Arc<FontFile>, String>> {
90        self.files.font(path)
91    }
92}