aldrin_parser/resolver/
fs.rs1use super::{Resolver, SchemaFile};
2use std::borrow::Cow;
3use std::collections::hash_map::{Entry, HashMap};
4use std::fs;
5use std::io::Error;
6use std::path::{Path, PathBuf};
7
8#[derive(Debug)]
9pub struct FilesystemResolver {
10 include_paths: Vec<PathBuf>,
11 main_schema: Schema,
12 schemas: HashMap<String, Schema>,
13}
14
15impl FilesystemResolver {
16 pub fn new(main_schema: impl AsRef<Path>) -> Self {
17 Self {
18 include_paths: Vec::new(),
19 main_schema: Schema::open(main_schema.as_ref()),
20 schemas: HashMap::new(),
21 }
22 }
23
24 pub fn with_include_paths<T>(main_schema: impl AsRef<Path>, include_paths: T) -> Self
25 where
26 T: IntoIterator,
27 T::Item: Into<PathBuf>,
28 {
29 let mut this = Self::new(main_schema);
30 this.add_include_paths(include_paths);
31 this
32 }
33
34 pub fn add_include_path(&mut self, include_path: impl Into<PathBuf>) -> &mut Self {
35 self.include_paths.push(include_path.into());
36 self
37 }
38
39 pub fn add_include_paths<T>(&mut self, include_paths: T) -> &mut Self
40 where
41 T: IntoIterator,
42 T::Item: Into<PathBuf>,
43 {
44 self.include_paths
45 .extend(include_paths.into_iter().map(Into::into));
46 self
47 }
48}
49
50impl Resolver for FilesystemResolver {
51 fn main_schema(&self) -> SchemaFile<'_> {
52 self.main_schema.as_schema_file()
53 }
54
55 fn resolve(&mut self, name: &str) -> Option<SchemaFile<'_>> {
56 if name == self.main_schema.name {
57 return Some(self.main_schema.as_schema_file());
58 }
59
60 let entry = match self.schemas.entry(name.to_owned()) {
61 Entry::Occupied(entry) => return Some(entry.into_mut().as_schema_file()),
62 Entry::Vacant(entry) => entry,
63 };
64
65 let path = self
66 .include_paths
67 .iter()
68 .rev()
69 .cloned()
70 .find_map(|mut path| {
71 path.push(name);
72 path.set_extension("aldrin");
73
74 if path.is_file() { Some(path) } else { None }
75 })?;
76
77 let schema = Schema::open_with_name(name.to_owned(), &path);
78 let schema = entry.insert(schema);
79 Some(schema.as_schema_file())
80 }
81}
82
83#[derive(Debug)]
84struct Schema {
85 name: String,
86 path: String,
87 source: Result<String, Error>,
88}
89
90impl Schema {
91 fn open(path: &Path) -> Self {
92 let name = Self::schema_name_from_path(path).into_owned();
93 Self::open_with_name(name, path)
94 }
95
96 fn open_with_name(name: String, path: &Path) -> Self {
97 Self {
98 name,
99 path: path.to_string_lossy().into_owned(),
100 source: fs::read_to_string(path),
101 }
102 }
103
104 fn schema_name_from_path(path: &Path) -> Cow<'_, str> {
105 match path.file_stem() {
106 Some(stem) => stem.to_string_lossy(),
107 None => Cow::Borrowed(""),
108 }
109 }
110
111 fn as_schema_file(&self) -> SchemaFile<'_> {
112 SchemaFile::new(&self.name, &self.path, self.source.as_deref())
113 }
114}