1use 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#[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
41fn 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
93impl 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
129pub fn builtin_library_cache() -> InMemoryModuleCache {
132 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
273fn 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#[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 assert!(is_builtin_type_name_str("binary"));
366 assert!(is_builtin_type_name_str("iri"));
367 assert!(is_builtin_type_name_str("unsigned"));
368 assert!(is_builtin_type_name_str("rational"));
370 assert!(is_builtin_type_name_str("real"));
371 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}