sdml_core/
store.rs

1/*!
2This module provides a trait for module *stores*, and an implementation for in-memory caches.
3
4# Example
5
6```
7use sdml_core::model::identifiers::Identifier;
8use sdml_core::store::{InMemoryModuleCache, ModuleStore};
9use std::str::FromStr;
10
11let store = InMemoryModuleCache::with_stdlib();
12
13let xml_schema_module = Identifier::from_str("xsd").unwrap();
14
15assert!(store.contains(&xml_schema_module));
16```
17
18*/
19
20use crate::config::{builtin_library_cache, is_library_module};
21use crate::model::definitions::Definition;
22use crate::model::identifiers::{Identifier, IdentifierReference, QualifiedIdentifier};
23use crate::model::modules::Module;
24use crate::model::HasName;
25use crate::stdlib::get_library_module_implementation;
26use std::collections::HashMap;
27use url::Url;
28
29// ------------------------------------------------------------------------------------------------
30// Public Types
31// ------------------------------------------------------------------------------------------------
32
33///
34/// A trait for any type that /stores/ modules and can retrieve them by name and by URI.
35///
36pub trait ModuleStore {
37    ///
38    /// Return the number of modules in the store.
39    ///
40    fn len(&self) -> usize;
41
42    ///
43    /// Return `true` if there are no modules in this store, else `false`.
44    ///
45    fn is_empty(&self) -> bool {
46        self.len() == 0
47    }
48
49    ///
50    /// Returns `true` if the loader's cache contains a module with the name `name`, else `false`.
51    ///
52    fn contains(&self, name: &Identifier) -> bool;
53
54    ///
55    /// Returns `true` if the loader's cache contains a module with the base URI `uri`, else `false`.
56    ///
57    fn contains_by_uri(&self, uri: &Url) -> bool {
58        let name = self.uri_to_module_name(uri).cloned();
59        if let Some(name) = name {
60            self.contains(&name)
61        } else {
62            false
63        }
64    }
65
66    ///
67    /// Returns a reference to the `Module` identified by `name` if the store contains it;
68    /// else `None`.
69    ///
70    fn get(&self, name: &Identifier) -> Option<&Module>;
71
72    ///
73    /// Returns a mutable reference to the `Module` identified by `name` if the store contains it;
74    /// else `None`.
75    ///
76    fn get_mut(&mut self, name: &Identifier) -> Option<&mut Module>;
77
78    ///
79    /// Returns a reference to the `Module` identified by `uri` if the store contains it;
80    /// else `None`.
81    ///
82    fn get_by_uri(&self, uri: &Url) -> Option<&Module> {
83        self.uri_to_module_name(uri).and_then(|name| self.get(name))
84    }
85
86    ///
87    /// Returns a mutable reference to the `Module` identified by `uri` if the store contains it;
88    /// else `None`.
89    ///
90    fn get_by_uri_mut(&mut self, uri: &Url) -> Option<&mut Module> {
91        let name = self.uri_to_module_name(uri).cloned();
92        if let Some(name) = name {
93            self.get_mut(&name)
94        } else {
95            None
96        }
97    }
98
99    ///
100    /// Return an iterator over all modules in this store. This may be an expensive operation if
101    /// modules only exist in some backing store.
102    ///
103    fn modules(&self) -> impl Iterator<Item = &Module>;
104
105    ///
106    /// Return an iterator over the names of the modules in this store.
107    ///
108    fn module_names(&self) -> impl Iterator<Item = &Identifier>;
109
110    ///
111    /// Insert `module` into the store.
112    ///
113    fn insert(&mut self, module: Module);
114
115    ///
116    /// Remove any module identified by `name`.
117    ///
118    fn remove(&mut self, name: &Identifier) -> bool;
119
120    ///
121    /// Remove any module identified by `uri`.
122    ///
123    fn remove_by_uri(&mut self, uri: &Url) -> bool {
124        let name = self.uri_to_module_name(uri).cloned();
125        if let Some(name) = name {
126            self.remove(&name)
127        } else {
128            false
129        }
130    }
131
132    ///
133    /// Return the module name corresponding to the provided `url` if it exists, or else `None`.
134    ///
135    fn uri_to_module_name(&self, url: &Url) -> Option<&Identifier>;
136
137    ///
138    /// Return the module URI corresponding to the provided `name` if it exists, or else `None`.
139    ///
140    fn module_name_to_uri(&self, name: &Identifier) -> Option<&Url>;
141
142    ///
143    /// Given a qualified identifier, find the named module or return `None`, then find the named
144    /// member in the found module or return `None`.
145    ///
146    /// # Example
147    ///
148    /// ```
149    /// use sdml_core::model::identifiers::QualifiedIdentifier;
150    /// use sdml_core::store::{InMemoryModuleCache, ModuleStore};
151    /// use std::str::FromStr;
152    ///
153    /// let cache = InMemoryModuleCache::with_stdlib();
154    /// let name = QualifiedIdentifier::from_str("xsd:integer").unwrap();
155    /// let integer = cache.resolve(&name).unwrap();
156    /// println!("{integer:?}");
157    /// ```
158    ///
159    fn resolve(&self, definition: &QualifiedIdentifier) -> Option<&Definition> {
160        if let Some(module) = self.get(definition.module()) {
161            module.resolve_local(definition.member())
162        } else {
163            None
164        }
165    }
166
167    ///
168    /// If `definition` is a `QualifiedIdentifier` this is the same as `resolve`; however, if
169    /// `definition` is an `Identifier` then look for definition in the module named
170    /// `in_module`.
171    ///
172    /// # Example
173    ///
174    /// ```
175    /// use sdml_core::model::identifiers::{Identifier, IdentifierReference};
176    /// use sdml_core::store::{InMemoryModuleCache, ModuleStore};
177    /// use std::str::FromStr;
178    ///
179    /// let cache = InMemoryModuleCache::with_stdlib();
180    /// let default_module = Identifier::from_str("xsd").unwrap();
181    /// let name = IdentifierReference::from_str("integer").unwrap();
182    /// let integer = cache.resolve_or_in(&name, &default_module).unwrap();
183    /// println!("{integer:?}");
184    /// ```
185    ///
186    fn resolve_or_in(
187        &self,
188        definition: &IdentifierReference,
189        in_module: &Identifier,
190    ) -> Option<&Definition> {
191        match definition {
192            IdentifierReference::Identifier(v) => self.resolve(&v.with_module(in_module.clone())),
193            IdentifierReference::QualifiedIdentifier(v) => self.resolve(v),
194        }
195    }
196}
197
198///
199/// An implementation of [`ModuleStore`] that has no persistence it simply acts as an in-process
200/// cache.
201///
202#[derive(Clone, Debug)]
203pub struct InMemoryModuleCache {
204    uri_map: HashMap<Url, Identifier>,
205    modules: HashMap<Identifier, Module>,
206}
207
208// ------------------------------------------------------------------------------------------------
209// Implementations
210// ------------------------------------------------------------------------------------------------
211
212impl ModuleStore for InMemoryModuleCache {
213    fn len(&self) -> usize {
214        self.modules.len()
215    }
216
217    fn contains(&self, name: &Identifier) -> bool {
218        self.modules.contains_key(name) || is_library_module(name)
219    }
220
221    fn contains_by_uri(&self, uri: &Url) -> bool {
222        self.uri_map.contains_key(uri)
223    }
224
225    fn get(&self, name: &Identifier) -> Option<&Module> {
226        if let Some(module) = get_library_module_implementation(name) {
227            Some(module)
228        } else {
229            self.modules.get(name)
230        }
231    }
232
233    fn get_mut(&mut self, name: &Identifier) -> Option<&mut Module> {
234        self.modules.get_mut(name)
235    }
236
237    fn get_by_uri(&self, uri: &Url) -> Option<&Module> {
238        match self.uri_map.get(uri) {
239            Some(name) => self.get(name),
240            _ => None,
241        }
242    }
243
244    fn get_by_uri_mut(&mut self, uri: &Url) -> Option<&mut Module> {
245        let name = self.uri_map.get_mut(uri).map(|n| n.clone());
246        match name {
247            Some(name) => self.get_mut(&name),
248            _ => None,
249        }
250    }
251
252    fn modules(&self) -> impl Iterator<Item = &Module> {
253        self.modules.values()
254    }
255
256    fn module_names(&self) -> impl Iterator<Item = &Identifier> {
257        self.modules.keys()
258    }
259
260    fn insert(&mut self, module: Module) {
261        if let Some(base_uri) = module.base_uri() {
262            self.uri_map
263                .insert(base_uri.value().clone(), module.name().clone());
264        }
265        self.modules.insert(module.name().clone(), module);
266    }
267
268    fn remove(&mut self, name: &Identifier) -> bool {
269        if self.modules.remove(name).is_some() {
270            self.uri_map.retain(|_, v| v == name);
271            true
272        } else {
273            false
274        }
275    }
276
277    fn remove_by_uri(&mut self, uri: &Url) -> bool {
278        if let Some(name) = self.uri_map.remove(uri) {
279            self.modules.remove(&name);
280            true
281        } else {
282            false
283        }
284    }
285
286    fn uri_to_module_name(&self, url: &Url) -> Option<&Identifier> {
287        self.uri_map.get(url)
288    }
289
290    fn module_name_to_uri(&self, id: &Identifier) -> Option<&Url> {
291        self.modules
292            .get(id)
293            .map(|module| module.base_uri().map(|hv| hv.value()))
294            .unwrap_or_default()
295    }
296}
297
298impl InMemoryModuleCache {
299    pub fn empty() -> Self {
300        Self {
301            uri_map: Default::default(),
302            modules: Default::default(),
303        }
304    }
305
306    pub fn with_stdlib() -> Self {
307        builtin_library_cache()
308    }
309
310    ///
311    /// Builder-like function to add a module to a newly constructed cache.
312    ///
313    pub fn with(self, module: Module) -> Self {
314        let mut self_mut = self;
315        self_mut.insert(module);
316        self_mut
317    }
318}