Skip to main content

sdml_core/config/
mod.rs

1/*!
2One-line description.
3
4TBD
5
6# Example
7
8TBD
9
10 */
11
12use crate::{
13    model::{identifiers::Identifier, modules::ModulePath},
14    stdlib::{self, owl, rdf, rdfs, sdml, skos, xsd},
15    store::InMemoryModuleCache,
16};
17use std::{
18    collections::{BTreeSet, HashMap},
19    sync::LazyLock,
20};
21
22// ------------------------------------------------------------------------------------------------
23// Public Types
24// ------------------------------------------------------------------------------------------------
25
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct LibraryModule {
28    name: Identifier,
29    compatibility_alias: Option<Identifier>,
30    builtin: bool,
31    base_datatypes: BTreeSet<Identifier>,
32}
33
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct LibraryConfiguration {
36    modules: HashMap<ModulePath, Vec<LibraryModule>>,
37    rdf_definition_allow: BTreeSet<Identifier>,
38    typeclass_definition_allow: BTreeSet<Identifier>,
39}
40
41// ------------------------------------------------------------------------------------------------
42// Public Functions
43// ------------------------------------------------------------------------------------------------
44
45fn library_configuration() -> &'static LibraryConfiguration {
46    static CONFIG: LazyLock<LibraryConfiguration> = LazyLock::new(load_library_configuration);
47    &CONFIG
48}
49
50#[inline(always)]
51pub fn library_module_configuration() -> &'static HashMap<ModulePath, Vec<LibraryModule>> {
52    &library_configuration().modules
53}
54
55pub fn is_library_module(name: &Identifier) -> bool {
56    is_library_module_str(name.as_ref())
57}
58
59pub fn is_library_module_str(name: &str) -> bool {
60    static MODULE_NAMES: LazyLock<BTreeSet<&'static str>> = LazyLock::new(config_to_library_names);
61    MODULE_NAMES.contains(name)
62}
63
64pub fn is_builtin_type_name(name: &Identifier) -> bool {
65    is_builtin_type_name_str(name.as_ref())
66}
67
68pub fn is_builtin_type_name_str(name: &str) -> bool {
69    static BUILTIN_TYPE_NAMES: LazyLock<BTreeSet<&'static str>> =
70        LazyLock::new(config_to_type_names);
71    BUILTIN_TYPE_NAMES.contains(name)
72}
73
74pub fn is_rdf_definition_allowed_in_module(name: &Identifier) -> bool {
75    is_rdf_definition_allowed_in_module_str(name.as_ref())
76}
77
78pub fn is_rdf_definition_allowed_in_module_str(name: &str) -> bool {
79    static MODULE_NAMES: LazyLock<BTreeSet<&'static str>> = LazyLock::new(config_to_rdf_allow_list);
80    MODULE_NAMES.contains(name) || is_library_module_str(name)
81}
82
83pub fn is_typeclass_definition_allowed_in_module(name: &Identifier) -> bool {
84    is_typeclass_definition_allowed_in_module_str(name.as_ref())
85}
86
87pub fn is_typeclass_definition_allowed_in_module_str(name: &str) -> bool {
88    static MODULE_NAMES: LazyLock<BTreeSet<&'static str>> =
89        LazyLock::new(config_to_typeclass_allow_list);
90    MODULE_NAMES.contains(name) || is_library_module_str(name)
91}
92
93// ------------------------------------------------------------------------------------------------
94// Implementations
95// ------------------------------------------------------------------------------------------------
96
97impl LibraryModule {
98    fn named(name: &str) -> Self {
99        Self {
100            name: Identifier::new_unchecked(name),
101            compatibility_alias: None,
102            builtin: false,
103            base_datatypes: BTreeSet::default(),
104        }
105    }
106    fn builtin(self) -> Self {
107        let mut self_mut = self;
108        self_mut.builtin = true;
109        self_mut
110    }
111    fn aliased_as_is(self) -> Self {
112        let mut self_mut = self;
113        self_mut.compatibility_alias = Some(self_mut.name.clone());
114        self_mut
115    }
116    fn alias(self, alias: &str) -> Self {
117        let mut self_mut = self;
118        self_mut.compatibility_alias = Some(Identifier::new_unchecked(alias));
119        self_mut
120    }
121    fn with_datatypes(self, datatypes: &[&str]) -> Self {
122        let mut self_mut = self;
123        self_mut.base_datatypes =
124            BTreeSet::from_iter(datatypes.iter().map(|id| Identifier::new_unchecked(id)));
125        self_mut
126    }
127}
128
129// ------------------------------------------------------------------------------------------------
130
131pub fn builtin_library_cache() -> InMemoryModuleCache {
132    // TODO: read from metadata...
133    InMemoryModuleCache::empty()
134        .with(sdml::module().clone())
135        .with(stdlib::dc::module().clone())
136        .with(stdlib::dcterms::module().clone())
137        .with(owl::module().clone())
138        .with(rdf::module().clone())
139        .with(rdfs::module().clone())
140        .with(skos::module().clone())
141        .with(xsd::module().clone())
142}
143
144impl Default for LibraryConfiguration {
145    fn default() -> Self {
146        Self {
147            modules: HashMap::from_iter(vec![
148                (
149                    ModulePath::new_unchecked(true, &[stdlib::PATH_ROOT_SEGMENT_IO]),
150                    vec![LibraryModule::named(sdml::MODULE_NAME)
151                        .aliased_as_is()
152                        .builtin()
153                        .with_datatypes(&[sdml::BINARY, sdml::IRI, sdml::UNSIGNED])],
154                ),
155                (
156                    ModulePath::new_unchecked(
157                        true,
158                        &[
159                            stdlib::PATH_ROOT_SEGMENT_ORG,
160                            stdlib::PATH_STDORG_SEGMENT_GS1,
161                        ],
162                    ),
163                    vec![LibraryModule::named("gln"), LibraryModule::named("gtin")],
164                ),
165                (
166                    ModulePath::new_unchecked(
167                        true,
168                        &[
169                            stdlib::PATH_ROOT_SEGMENT_ORG,
170                            stdlib::PATH_STDORG_SEGMENT_ISO,
171                        ],
172                    ),
173                    vec![
174                        LibraryModule::named("iso_17442"),
175                        LibraryModule::named("iso_3166"),
176                        LibraryModule::named("iso_4217"),
177                        LibraryModule::named("iso_639_1"),
178                        LibraryModule::named("iso_9362"),
179                    ],
180                ),
181                (
182                    ModulePath::new_unchecked(
183                        true,
184                        &[
185                            stdlib::PATH_ROOT_SEGMENT_ORG,
186                            stdlib::PATH_ORG_SEGMENT_PURL,
187                            stdlib::PATH_STDORG_SEGMENT_DC,
188                        ],
189                    ),
190                    vec![
191                        LibraryModule::named("elements").alias("dc").builtin(),
192                        LibraryModule::named("terms").alias("dcterms").builtin(),
193                        LibraryModule::named("dcam").aliased_as_is(),
194                        LibraryModule::named("dcmitype").aliased_as_is(),
195                    ],
196                ),
197                (
198                    ModulePath::new_unchecked(
199                        true,
200                        &[
201                            stdlib::PATH_ROOT_SEGMENT_ORG,
202                            stdlib::PATH_STDORG_SEGMENT_W3C,
203                        ],
204                    ),
205                    vec![
206                        LibraryModule::named(stdlib::owl::MODULE_NAME)
207                            .aliased_as_is()
208                            .builtin()
209                            .with_datatypes(&[owl::RATIONAL, owl::REAL]),
210                        LibraryModule::named(rdf::MODULE_NAME)
211                            .aliased_as_is()
212                            .builtin(),
213                        LibraryModule::named(rdfs::MODULE_NAME)
214                            .aliased_as_is()
215                            .builtin(),
216                        LibraryModule::named(skos::MODULE_NAME)
217                            .aliased_as_is()
218                            .builtin(),
219                        LibraryModule::named(xsd::MODULE_NAME)
220                            .aliased_as_is()
221                            .builtin()
222                            .with_datatypes(&[
223                                xsd::ANY_URI,
224                                xsd::BASE64_BINARY,
225                                xsd::BOOLEAN,
226                                xsd::DATE,
227                                xsd::DATETIME,
228                                xsd::DECIMAL,
229                                xsd::DOUBLE,
230                                xsd::DURATION,
231                                xsd::FLOAT,
232                                xsd::GDAY,
233                                xsd::GMONTH,
234                                xsd::GMONTH_DAY,
235                                xsd::GYEAR_MONTH,
236                                xsd::GYEAR,
237                                xsd::HEX_BINARY,
238                                xsd::STRING,
239                                xsd::TIME,
240                                xsd::DATETIME_STAMP,
241                                xsd::DAYTIME_DURATION,
242                                xsd::YEARMONTH_DURATION,
243                                xsd::INTEGER,
244                                xsd::LONG,
245                                xsd::INT,
246                                xsd::SHORT,
247                                xsd::BYTE,
248                                xsd::NONNEGATIVE_INTEGER,
249                                xsd::POSITIVE_INTEGER,
250                                xsd::UNSIGNED_LONG,
251                                xsd::UNSIGNED_INT,
252                                xsd::UNSIGNED_SHORT,
253                                xsd::UNSIGNED_BYTE,
254                                xsd::NONPOSITIVE_INTEGER,
255                                xsd::NEGATIVE_INTEGER,
256                                xsd::NORMALIZED_STRING,
257                                xsd::TOKEN,
258                                xsd::LANGUAGE,
259                            ]),
260                    ],
261                ),
262            ]),
263            rdf_definition_allow: BTreeSet::from_iter(vec![Identifier::new_unchecked(
264                "example_rdf_defs",
265            )]),
266            typeclass_definition_allow: BTreeSet::from_iter(vec![Identifier::new_unchecked(
267                "example_typeclass_defs",
268            )]),
269        }
270    }
271}
272
273// ------------------------------------------------------------------------------------------------
274// Private Functions
275// ------------------------------------------------------------------------------------------------
276
277fn config_to_library_names() -> BTreeSet<&'static str> {
278    library_module_configuration()
279        .values()
280        .flat_map(|vs| vs.iter().map(|v| v.name.as_ref()))
281        .chain(library_module_configuration().values().flat_map(|vs| {
282            vs.iter()
283                .filter_map(|v| v.compatibility_alias.as_ref().map(|name| name.as_ref()))
284        }))
285        .collect()
286}
287
288#[allow(clippy::map_flatten)]
289fn config_to_type_names() -> BTreeSet<&'static str> {
290    library_module_configuration()
291        .values()
292        .map(|vs| {
293            vs.iter()
294                .map(|v| v.base_datatypes.iter().map(|name| name.as_ref()))
295        })
296        .flatten()
297        .flatten()
298        .collect()
299}
300
301fn config_to_rdf_allow_list() -> BTreeSet<&'static str> {
302    library_configuration()
303        .rdf_definition_allow
304        .iter()
305        .map(|s| s.as_ref())
306        .collect()
307}
308
309fn config_to_typeclass_allow_list() -> BTreeSet<&'static str> {
310    library_configuration()
311        .typeclass_definition_allow
312        .iter()
313        .map(|s| s.as_ref())
314        .collect()
315}
316
317#[cfg(not(feature = "stdlib-ext-config"))]
318pub fn load_library_configuration() -> LibraryConfiguration {
319    LibraryConfiguration::default()
320}
321
322#[cfg(feature = "stdlib-ext-config")]
323mod external;
324#[cfg(feature = "stdlib-ext-config")]
325use external::load_library_configuration;
326
327// ------------------------------------------------------------------------------------------------
328// Unit Tests
329// ------------------------------------------------------------------------------------------------
330
331#[cfg(test)]
332mod tests {
333    use super::*;
334
335    #[test]
336    fn test_library_config_file_loads() {
337        let library_modules = library_module_configuration();
338        assert_eq!(library_modules.len(), 6);
339    }
340
341    #[test]
342    fn test_is_library_module() {
343        assert!(is_library_module_str("dc"));
344        assert!(is_library_module_str("dcam"));
345        assert!(is_library_module_str("dcmitype"));
346        assert!(is_library_module_str("dcterms"));
347        assert!(is_library_module_str("elements"));
348        assert!(is_library_module_str("terms"));
349        assert!(is_library_module_str("iso_17442"));
350        assert!(is_library_module_str("iso_3166"));
351        assert!(is_library_module_str("iso_4217"));
352        assert!(is_library_module_str("iso_639_1"));
353        assert!(is_library_module_str("iso_9362"));
354        assert!(is_library_module_str("owl"));
355        assert!(is_library_module_str("rdf"));
356        assert!(is_library_module_str("rdfs"));
357        assert!(is_library_module_str("skos"));
358        assert!(is_library_module_str("sdml"));
359        assert!(is_library_module_str("xsd"));
360    }
361
362    #[test]
363    fn test_is_builtin_type_name() {
364        // SDML
365        assert!(is_builtin_type_name_str("binary"));
366        assert!(is_builtin_type_name_str("iri"));
367        assert!(is_builtin_type_name_str("unsigned"));
368        // OWL
369        assert!(is_builtin_type_name_str("rational"));
370        assert!(is_builtin_type_name_str("real"));
371        // XSD
372        assert!(is_builtin_type_name_str("anyURI"));
373        assert!(is_builtin_type_name_str("base64Binary"));
374        assert!(is_builtin_type_name_str("boolean"));
375        assert!(is_builtin_type_name_str("date"));
376        assert!(is_builtin_type_name_str("dateTime"));
377        assert!(is_builtin_type_name_str("decimal"));
378        assert!(is_builtin_type_name_str("double"));
379        assert!(is_builtin_type_name_str("duration"));
380        assert!(is_builtin_type_name_str("float"));
381        assert!(is_builtin_type_name_str("gDay"));
382        assert!(is_builtin_type_name_str("gMonth"));
383        assert!(is_builtin_type_name_str("gMonthDay"));
384        assert!(is_builtin_type_name_str("gYearMonth"));
385        assert!(is_builtin_type_name_str("gYear"));
386        assert!(is_builtin_type_name_str("hexBinary"));
387        assert!(is_builtin_type_name_str("string"));
388        assert!(is_builtin_type_name_str("time"));
389        assert!(is_builtin_type_name_str("dateTimeStamp"));
390        assert!(is_builtin_type_name_str("dayTimeDuration"));
391        assert!(is_builtin_type_name_str("yearMonthDuration"));
392        assert!(is_builtin_type_name_str("integer"));
393        assert!(is_builtin_type_name_str("long"));
394        assert!(is_builtin_type_name_str("int"));
395        assert!(is_builtin_type_name_str("short"));
396        assert!(is_builtin_type_name_str("byte"));
397        assert!(is_builtin_type_name_str("nonNegativeInteger"));
398        assert!(is_builtin_type_name_str("positiveInteger"));
399        assert!(is_builtin_type_name_str("unsignedLong"));
400        assert!(is_builtin_type_name_str("unsignedInt"));
401        assert!(is_builtin_type_name_str("unsignedShort"));
402        assert!(is_builtin_type_name_str("unsignedByte"));
403        assert!(is_builtin_type_name_str("nonPositiveInteger"));
404        assert!(is_builtin_type_name_str("negativeInteger"));
405        assert!(is_builtin_type_name_str("normalizedString"));
406        assert!(is_builtin_type_name_str("token"));
407        assert!(is_builtin_type_name_str("language"));
408    }
409
410    #[test]
411    fn test_is_rdf_definition_allowed_in_module() {
412        assert!(is_rdf_definition_allowed_in_module_str("dc"));
413        assert!(is_rdf_definition_allowed_in_module_str("dcam"));
414        assert!(is_rdf_definition_allowed_in_module_str("dcmitype"));
415        assert!(is_rdf_definition_allowed_in_module_str("dcterms"));
416        assert!(is_rdf_definition_allowed_in_module_str("elements"));
417        assert!(is_rdf_definition_allowed_in_module_str("terms"));
418        assert!(is_rdf_definition_allowed_in_module_str("iso_17442"));
419        assert!(is_rdf_definition_allowed_in_module_str("iso_3166"));
420        assert!(is_rdf_definition_allowed_in_module_str("iso_4217"));
421        assert!(is_rdf_definition_allowed_in_module_str("iso_639_1"));
422        assert!(is_rdf_definition_allowed_in_module_str("iso_9362"));
423        assert!(is_rdf_definition_allowed_in_module_str("owl"));
424        assert!(is_rdf_definition_allowed_in_module_str("rdf"));
425        assert!(is_rdf_definition_allowed_in_module_str("rdfs"));
426        assert!(is_rdf_definition_allowed_in_module_str("skos"));
427        assert!(is_rdf_definition_allowed_in_module_str("sdml"));
428        assert!(is_rdf_definition_allowed_in_module_str("xsd"));
429
430        assert!(is_rdf_definition_allowed_in_module_str("example_rdf_defs"));
431        assert!(!is_rdf_definition_allowed_in_module_str(
432            "example_typeclass_defs"
433        ));
434    }
435
436    #[test]
437    fn test_is_typeclass_definition_allowed_in_module() {
438        assert!(is_typeclass_definition_allowed_in_module_str("dc"));
439        assert!(is_typeclass_definition_allowed_in_module_str("dcam"));
440        assert!(is_typeclass_definition_allowed_in_module_str("dcmitype"));
441        assert!(is_typeclass_definition_allowed_in_module_str("dcterms"));
442        assert!(is_typeclass_definition_allowed_in_module_str("elements"));
443        assert!(is_typeclass_definition_allowed_in_module_str("terms"));
444        assert!(is_typeclass_definition_allowed_in_module_str("iso_17442"));
445        assert!(is_typeclass_definition_allowed_in_module_str("iso_3166"));
446        assert!(is_typeclass_definition_allowed_in_module_str("iso_4217"));
447        assert!(is_typeclass_definition_allowed_in_module_str("iso_639_1"));
448        assert!(is_typeclass_definition_allowed_in_module_str("iso_9362"));
449        assert!(is_typeclass_definition_allowed_in_module_str("owl"));
450        assert!(is_typeclass_definition_allowed_in_module_str("rdf"));
451        assert!(is_typeclass_definition_allowed_in_module_str("rdfs"));
452        assert!(is_typeclass_definition_allowed_in_module_str("skos"));
453        assert!(is_typeclass_definition_allowed_in_module_str("sdml"));
454        assert!(is_typeclass_definition_allowed_in_module_str("xsd"));
455
456        assert!(is_typeclass_definition_allowed_in_module_str(
457            "example_typeclass_defs"
458        ));
459        assert!(!is_typeclass_definition_allowed_in_module_str(
460            "example_rdf_defs"
461        ));
462    }
463}