json_ld_syntax/context/
try_from_json.rs

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}