1use std::{collections::HashMap, sync::Mutex};
2
3use anyhow::{anyhow, Context, Result};
4use camino::{Utf8Path, Utf8PathBuf};
5
6use crate::SchemaNode;
7
8#[derive(Default)]
10pub struct SchemaCache<'a> {
11 mapped: Mutex<HashMap<Utf8PathBuf, usize>>,
12 texts: elsa::FrozenVec<String>,
13 schemas: elsa::FrozenVec<Box<SchemaNode<'a>>>,
14}
15
16impl<'a> SchemaCache<'a> {
17 pub fn new() -> Self {
19 Default::default()
20 }
21
22 pub fn load<'s, 'r>(&'s self, path: impl AsRef<Utf8Path>) -> Result<&'r SchemaNode<'a>>
24 where
25 's: 'a,
26 {
27 let mut locked = self.mapped.lock().expect("Lock poisoned");
28
29 if let Some(index) = locked.get(path.as_ref()) {
31 return Ok(&self.schemas[*index]);
32 }
33
34 let text = self.texts.push_get(
36 std::fs::read_to_string(path.as_ref())
37 .with_context(|| format!("Failed to load config from: {}", path.as_ref()))?,
38 );
39 let schema = diskplan_schema::parse_schema(text)
40 .map_err(|e| anyhow!("{}", e))?;
42 locked.insert(path.as_ref().to_owned(), self.schemas.len());
43 Ok(self.schemas.push_get(Box::new(schema)))
44 }
45
46 pub fn inject(&self, path: impl AsRef<Utf8Path>, schema: SchemaNode<'a>) {
50 let mut locked = self.mapped.lock().expect("Lock poisoned");
51 locked.insert(path.as_ref().to_owned(), self.schemas.len());
52 self.schemas.push(Box::new(schema));
53 }
54}