1use crate::prelude::*;
2
3#[derive(Clone, Debug, Serialize)]
11pub struct Type {
12 #[serde(skip_serializing_if = "<[_]>::is_empty")]
13 normalizers: &'static [TypeNormalizer],
14
15 #[serde(skip_serializing_if = "<[_]>::is_empty")]
16 validators: &'static [TypeValidator],
17
18 #[serde(skip_serializing_if = "<[_]>::is_empty")]
19 rules: &'static [SourceRule],
20}
21
22impl Type {
23 #[must_use]
24 pub const fn new(
25 normalizers: &'static [TypeNormalizer],
26 validators: &'static [TypeValidator],
27 rules: &'static [SourceRule],
28 ) -> Self {
29 Self {
30 normalizers,
31 validators,
32 rules,
33 }
34 }
35
36 #[must_use]
37 pub const fn normalizers(&self) -> &'static [TypeNormalizer] {
38 self.normalizers
39 }
40
41 #[must_use]
42 pub const fn validators(&self) -> &'static [TypeValidator] {
43 self.validators
44 }
45
46 #[must_use]
48 pub const fn rules(&self) -> &'static [SourceRule] {
49 self.rules
50 }
51}
52
53impl ValidateNode for Type {}
54
55impl VisitableNode for Type {
56 fn drive<V: Visitor>(&self, v: &mut V) {
57 for node in self.normalizers() {
58 node.accept(v);
59 }
60 for node in self.validators() {
61 node.accept(v);
62 }
63 for node in self.rules() {
64 node.accept(v);
65 }
66 }
67}
68
69#[derive(Clone, Debug, Serialize)]
78pub struct SourceRule {
79 source_key: &'static str,
80 kind: SourceRuleKind,
81 args: Args,
82}
83
84impl SourceRule {
85 #[must_use]
87 pub const fn new(source_key: &'static str, kind: SourceRuleKind, args: Args) -> Self {
88 Self {
89 source_key,
90 kind,
91 args,
92 }
93 }
94
95 #[must_use]
97 pub const fn source_key(&self) -> &'static str {
98 self.source_key
99 }
100
101 #[must_use]
103 pub const fn kind(&self) -> SourceRuleKind {
104 self.kind
105 }
106
107 #[must_use]
109 pub const fn args(&self) -> &Args {
110 &self.args
111 }
112}
113
114impl ValidateNode for SourceRule {
115 fn validate(&self) -> Result<(), ErrorTree> {
116 let mut errs = ErrorTree::new();
117 validate_source_key(
118 &mut errs,
119 "rule",
120 self.source_key(),
121 icydb_schema::RuleSourceKey::try_new,
122 );
123 let expected_args = match self.kind() {
124 SourceRuleKind::NumericMinimum => 1,
125 SourceRuleKind::LengthRange | SourceRuleKind::NumericRange => 2,
126 };
127 if self.args().0.len() != expected_args
128 || self
129 .args()
130 .0
131 .iter()
132 .any(|arg| !matches!(arg, Arg::Number(_)))
133 {
134 err!(
135 errs,
136 "rule '{}' requires {expected_args} numeric argument(s)",
137 self.source_key(),
138 );
139 }
140 errs.result()
141 }
142}
143
144impl VisitableNode for SourceRule {}
145
146#[derive(Clone, Copy, Debug, Serialize)]
155pub enum SourceRuleKind {
156 LengthRange,
158 NumericMinimum,
160 NumericRange,
162}
163
164#[derive(Clone, Debug, Serialize)]
171pub struct TypeNormalizer {
172 path: &'static str,
173 args: Args,
174}
175
176impl TypeNormalizer {
177 #[must_use]
178 pub const fn new(path: &'static str, args: Args) -> Self {
179 Self { path, args }
180 }
181
182 #[must_use]
183 pub const fn path(&self) -> &'static str {
184 self.path
185 }
186
187 #[must_use]
188 pub const fn args(&self) -> &Args {
189 &self.args
190 }
191}
192
193impl ValidateNode for TypeNormalizer {
194 fn validate(&self) -> Result<(), ErrorTree> {
195 let mut errs = ErrorTree::new();
196
197 let res = schema_read().check_node_as::<Normalizer>(self.path());
199 if let Err(e) = res {
200 errs.add(e.to_string());
201 }
202
203 errs.result()
204 }
205}
206
207impl VisitableNode for TypeNormalizer {}
208
209#[derive(Clone, Debug, Serialize)]
216pub struct TypeValidator {
217 path: &'static str,
218 args: Args,
219}
220
221impl TypeValidator {
222 #[must_use]
223 pub const fn new(path: &'static str, args: Args) -> Self {
224 Self { path, args }
225 }
226
227 #[must_use]
228 pub const fn path(&self) -> &'static str {
229 self.path
230 }
231
232 #[must_use]
233 pub const fn args(&self) -> &Args {
234 &self.args
235 }
236}
237
238impl ValidateNode for TypeValidator {
239 fn validate(&self) -> Result<(), ErrorTree> {
240 let mut errs = ErrorTree::new();
241
242 let res = schema_read().check_node_as::<Validator>(self.path());
244 if let Err(e) = res {
245 errs.add(e.to_string());
246 }
247
248 errs.result()
249 }
250}
251
252impl VisitableNode for TypeValidator {}