1use super::{
2 definition,
3 term_definition::{self, InvalidNest},
4 Context, ContextEntry, Definition, TermDefinition,
5};
6use crate::{Container, ErrorCode, Keyword, Nullable, TryFromJson};
7use iref::IriRefBuf;
8
9#[derive(Debug, Clone, thiserror::Error)]
10pub enum InvalidContext {
11 #[error("Invalid IRI reference: {0}")]
12 InvalidIriRef(String),
13
14 #[error("Unexpected {0}")]
15 Unexpected(json_syntax::Kind, &'static [json_syntax::Kind]),
16
17 #[error("Invalid `@direction`")]
18 InvalidDirection,
19
20 #[error("Duplicate key")]
21 DuplicateKey,
22
23 #[error("Invalid term definition")]
24 InvalidTermDefinition,
25
26 #[error("Invalid `@nest` value `{0}`")]
27 InvalidNestValue(String),
28}
29
30impl InvalidContext {
31 pub fn code(&self) -> ErrorCode {
32 match self {
33 Self::InvalidIriRef(_) => ErrorCode::InvalidIriMapping,
34 Self::Unexpected(_, _) => ErrorCode::InvalidContextEntry,
35 Self::InvalidDirection => ErrorCode::InvalidBaseDirection,
36 Self::DuplicateKey => ErrorCode::DuplicateKey,
37 Self::InvalidTermDefinition => ErrorCode::InvalidTermDefinition,
38 Self::InvalidNestValue(_) => ErrorCode::InvalidNestValue,
39 }
40 }
41}
42
43impl From<crate::Unexpected> for InvalidContext {
44 fn from(crate::Unexpected(u, e): crate::Unexpected) -> Self {
45 Self::Unexpected(u, e)
46 }
47}
48
49impl TryFromJson for TermDefinition {
50 type Error = InvalidContext;
51
52 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
53 match value {
54 json_syntax::Value::String(s) => {
55 Ok(Self::Simple(term_definition::Simple(s.to_string())))
56 }
57 json_syntax::Value::Object(o) => {
58 let mut def = term_definition::Expanded::new();
59
60 for json_syntax::object::Entry { key, value } in o {
61 match Keyword::try_from(key.as_str()) {
62 Ok(Keyword::Id) => def.id = Some(Nullable::try_from_json(value)?),
63 Ok(Keyword::Type) => def.type_ = Some(Nullable::try_from_json(value)?),
64 Ok(Keyword::Context) => {
65 def.context = Some(Box::new(Context::try_from_json(value)?))
66 }
67 Ok(Keyword::Reverse) => {
68 def.reverse = Some(definition::Key::try_from_json(value)?)
69 }
70 Ok(Keyword::Index) => {
71 def.index = Some(term_definition::Index::try_from_json(value)?)
72 }
73 Ok(Keyword::Language) => {
74 def.language = Some(Nullable::try_from_json(value)?)
75 }
76 Ok(Keyword::Direction) => {
77 def.direction = Some(Nullable::try_from_json(value)?)
78 }
79 Ok(Keyword::Container) => {
80 let container = match value {
81 json_syntax::Value::Null => Nullable::Null,
82 other => {
83 let container = Container::try_from_json(other)?;
84 Nullable::Some(container)
85 }
86 };
87
88 def.container = Some(container)
89 }
90 Ok(Keyword::Nest) => {
91 def.nest = Some(term_definition::Nest::try_from_json(value)?)
92 }
93 Ok(Keyword::Prefix) => def.prefix = Some(bool::try_from_json(value)?),
94 Ok(Keyword::Propagate) => def.propagate = Some(bool::try_from_json(value)?),
95 Ok(Keyword::Protected) => def.protected = Some(bool::try_from_json(value)?),
96 _ => return Err(InvalidContext::InvalidTermDefinition),
97 }
98 }
99
100 Ok(Self::Expanded(Box::new(def)))
101 }
102 unexpected => Err(InvalidContext::Unexpected(
103 unexpected.kind(),
104 &[json_syntax::Kind::String, json_syntax::Kind::Object],
105 )),
106 }
107 }
108}
109
110impl TryFromJson for term_definition::Type {
111 type Error = InvalidContext;
112
113 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
114 match value {
115 json_syntax::Value::String(s) => Ok(Self::from(s.into_string())),
116 unexpected => Err(InvalidContext::Unexpected(
117 unexpected.kind(),
118 &[json_syntax::Kind::String],
119 )),
120 }
121 }
122}
123
124impl TryFromJson for definition::TypeContainer {
125 type Error = InvalidContext;
126
127 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
128 match value {
129 json_syntax::Value::String(s) => match Keyword::try_from(s.as_str()) {
130 Ok(Keyword::Set) => Ok(Self::Set),
131 _ => Err(InvalidContext::InvalidTermDefinition),
132 },
133 unexpected => Err(InvalidContext::Unexpected(
134 unexpected.kind(),
135 &[json_syntax::Kind::String],
136 )),
137 }
138 }
139}
140
141impl TryFromJson for definition::Type {
142 type Error = InvalidContext;
143
144 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
145 match value {
146 json_syntax::Value::Object(o) => {
147 let mut container = None;
148 let mut protected = None;
149
150 for json_syntax::object::Entry { key, value } in o {
151 match Keyword::try_from(key.as_str()) {
152 Ok(Keyword::Container) => {
153 if container
154 .replace(definition::TypeContainer::try_from_json(value)?)
155 .is_some()
156 {
157 return Err(InvalidContext::DuplicateKey);
158 }
159 }
160 Ok(Keyword::Protected) => {
161 if protected.replace(bool::try_from_json(value)?).is_some() {
162 return Err(InvalidContext::DuplicateKey);
163 }
164 }
165 _ => return Err(InvalidContext::InvalidTermDefinition),
166 }
167 }
168
169 match container {
170 Some(container) => Ok(Self {
171 container,
172 protected,
173 }),
174 None => Err(InvalidContext::InvalidTermDefinition),
175 }
176 }
177 unexpected => Err(InvalidContext::Unexpected(
178 unexpected.kind(),
179 &[json_syntax::Kind::Object],
180 )),
181 }
182 }
183}
184
185impl TryFromJson for definition::Version {
186 type Error = InvalidContext;
187
188 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
189 match value {
190 json_syntax::Value::Number(n) => match n.as_str() {
191 "1.1" => Ok(Self::V1_1),
192 _ => Err(InvalidContext::InvalidTermDefinition),
193 },
194 unexpected => Err(InvalidContext::Unexpected(
195 unexpected.kind(),
196 &[json_syntax::Kind::Number],
197 )),
198 }
199 }
200}
201
202impl TryFromJson for definition::Vocab {
203 type Error = InvalidContext;
204
205 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
206 match value {
207 json_syntax::Value::String(s) => Ok(Self::from(s.into_string())),
208 unexpected => Err(InvalidContext::Unexpected(
209 unexpected.kind(),
210 &[json_syntax::Kind::String],
211 )),
212 }
213 }
214}
215
216impl TryFromJson for term_definition::Id {
217 type Error = InvalidContext;
218
219 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
220 match value {
221 json_syntax::Value::String(s) => Ok(Self::from(s.into_string())),
222 unexpected => Err(InvalidContext::Unexpected(
223 unexpected.kind(),
224 &[json_syntax::Kind::String],
225 )),
226 }
227 }
228}
229
230impl TryFromJson for definition::Key {
231 type Error = InvalidContext;
232
233 fn try_from_json(value: json_syntax::Value) -> Result<Self, Self::Error> {
234 match value {
235 json_syntax::Value::String(s) => Ok(Self::from(s.into_string())),
236 unexpected => Err(InvalidContext::Unexpected(
237 unexpected.kind(),
238 &[json_syntax::Kind::String],
239 )),
240 }
241 }
242}
243
244impl TryFromJson for term_definition::Index {
245 type Error = InvalidContext;
246
247 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
248 match value {
249 json_syntax::Value::String(s) => Ok(Self::from(s.into_string())),
250 unexpected => Err(InvalidContext::Unexpected(
251 unexpected.kind(),
252 &[json_syntax::Kind::String],
253 )),
254 }
255 }
256}
257
258impl TryFromJson for term_definition::Nest {
259 type Error = InvalidContext;
260
261 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
262 match value {
263 json_syntax::Value::String(s) => match Self::try_from(s.into_string()) {
264 Ok(nest) => Ok(nest),
265 Err(InvalidNest(s)) => Err(InvalidContext::InvalidNestValue(s)),
266 },
267 unexpected => Err(InvalidContext::Unexpected(
268 unexpected.kind(),
269 &[json_syntax::Kind::String],
270 )),
271 }
272 }
273}
274
275impl TryFromJson for Context {
276 type Error = InvalidContext;
277
278 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
279 match value {
280 json_syntax::Value::Array(a) => {
281 let mut many = Vec::with_capacity(a.len());
282
283 for item in a {
284 many.push(ContextEntry::try_from_json(item)?)
285 }
286
287 Ok(Self::Many(many))
288 }
289 context => Ok(Self::One(ContextEntry::try_from_json(context)?)),
290 }
291 }
292}
293
294impl TryFromJson for ContextEntry {
295 type Error = InvalidContext;
296
297 fn try_from_json(value: json_syntax::Value) -> Result<Self, InvalidContext> {
298 match value {
299 json_syntax::Value::Null => Ok(Self::Null),
300 json_syntax::Value::String(s) => match IriRefBuf::new(s.into_string()) {
301 Ok(iri_ref) => Ok(Self::IriRef(iri_ref)),
302 Err(e) => Err(InvalidContext::InvalidIriRef(e.0)),
303 },
304 json_syntax::Value::Object(o) => {
305 let mut def = Definition::new();
306
307 for json_syntax::object::Entry { key, value } in o {
308 match Keyword::try_from(key.as_str()) {
309 Ok(Keyword::Base) => def.base = Some(Nullable::try_from_json(value)?),
310 Ok(Keyword::Import) => def.import = Some(IriRefBuf::try_from_json(value)?),
311 Ok(Keyword::Language) => {
312 def.language = Some(Nullable::try_from_json(value)?)
313 }
314 Ok(Keyword::Direction) => {
315 def.direction = Some(Nullable::try_from_json(value)?)
316 }
317 Ok(Keyword::Propagate) => def.propagate = Some(bool::try_from_json(value)?),
318 Ok(Keyword::Protected) => def.protected = Some(bool::try_from_json(value)?),
319 Ok(Keyword::Type) => {
320 def.type_ = Some(definition::Type::try_from_json(value)?)
321 }
322 Ok(Keyword::Version) => {
323 def.version = Some(definition::Version::try_from_json(value)?)
324 }
325 Ok(Keyword::Vocab) => def.vocab = Some(Nullable::try_from_json(value)?),
326 _ => {
327 let term_def = match value {
328 json_syntax::Value::Null => Nullable::Null,
329 other => Nullable::Some(TermDefinition::try_from_json(other)?),
330 };
331
332 if def.bindings.insert_with(key.into(), term_def).is_some() {
333 return Err(InvalidContext::DuplicateKey);
334 }
335 }
336 }
337 }
338
339 Ok(Self::Definition(def))
340 }
341 unexpected => Err(InvalidContext::Unexpected(
342 unexpected.kind(),
343 &[
344 json_syntax::Kind::Null,
345 json_syntax::Kind::String,
346 json_syntax::Kind::Object,
347 ],
348 )),
349 }
350 }
351}