1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::{collections::HashMap, sync::Arc};
use crate::{
XMLVersion,
uri::{URIStr, URIString},
};
pub trait RelaxNGDatatypeLibrary: Send + Sync {
/// If a type named `type_name` exists in the library, return `true`,
/// otherwise return `false`.
fn contains(&self, type_name: &str) -> bool;
/// If a type named `type_name` exists in the library, return [`Some`] wrapped around
/// [`true`] if `value` is a valid representation of that type, or [`false`] otherwise.
///
/// Even if a type exists, if the arguments sufficient for determination are not included
/// in `params`, [`None`] is returned.
///
/// If a type named `type_name` does not exist in the library, return [`None`].
///
/// # Reference
/// ISO/IEC 19757-2:2008 9.3.8 data and value pattern
fn validate(
&self,
type_name: &str,
params: &HashMap<String, String>,
value: &str,
) -> Option<bool>;
/// If a type named `type_name` exists in the library, return [`Some`] wrapped around
/// [`true`] if `params` is a valid parameter list of that type, or [`false`] otherwise.
///
/// If a type named `type_name` does not exist in the library, return [`None`].
fn validate_params(&self, type_name: &str, params: &HashMap<String, String>) -> Option<bool>;
/// If a type named `type_name` exists in the library, return [`Some`] wrapped around
/// [`true`] if `lhs` and `rhs` are equal as representations of that type,
/// or [`false`] if they are not equal.
///
/// If a type named `type_name` does not exist in the library, returns [`None`].
///
/// # Reference
/// ISO/IEC 19757-2:2008 9.3.8 data and value pattern
fn eq(&self, type_name: &str, lhs: &str, rhs: &str) -> Option<bool>;
}
pub struct RelaxNGBuiltinDatatypeLibrary;
impl RelaxNGDatatypeLibrary for RelaxNGBuiltinDatatypeLibrary {
fn contains(&self, type_name: &str) -> bool {
matches!(type_name, "string" | "token")
}
fn validate(
&self,
type_name: &str,
_params: &HashMap<String, String>,
_value: &str,
) -> Option<bool> {
match type_name {
"string" | "token" => Some(true),
_ => None,
}
}
fn validate_params(&self, type_name: &str, params: &HashMap<String, String>) -> Option<bool> {
self.contains(type_name).then_some(params.is_empty())
}
fn eq(&self, type_name: &str, lhs: &str, rhs: &str) -> Option<bool> {
match type_name {
"string" => Some(lhs == rhs),
"token" => {
let lhs = lhs
.split(|c: char| XMLVersion::default().is_whitespace(c))
.filter(|s| !s.is_empty())
.collect::<Vec<_>>();
let rhs = rhs
.split(|c: char| XMLVersion::default().is_whitespace(c))
.filter(|s| !s.is_empty())
.collect::<Vec<_>>();
Some(lhs == rhs)
}
_ => None,
}
}
}
#[derive(Clone)]
pub struct RelaxNGDatatypeLibraries {
map: HashMap<URIString, Arc<dyn RelaxNGDatatypeLibrary>>,
}
impl RelaxNGDatatypeLibraries {
pub(super) fn get(&self, namespace_name: &URIStr) -> Option<&dyn RelaxNGDatatypeLibrary> {
self.map.get(namespace_name).map(|library| &**library)
}
fn insert(
&mut self,
namespace_name: URIString,
library: Arc<dyn RelaxNGDatatypeLibrary>,
) -> Option<Arc<dyn RelaxNGDatatypeLibrary>> {
self.map.insert(namespace_name, library)
}
}
impl Default for RelaxNGDatatypeLibraries {
fn default() -> Self {
let mut libraries = Self {
map: HashMap::new(),
};
libraries.insert(
URIString::parse("").unwrap(),
Arc::new(RelaxNGBuiltinDatatypeLibrary),
);
libraries
}
}