Skip to main content

json_ld/core/context/
definition.rs

1use super::JsonLdContainer;
2use crate::{
3	JsonLdBacktrace, JsonLdBacktraceBuf, JsonLdDirection, JsonLdNullable, JsonLdTerm, JsonLdType,
4};
5use crate::{
6	JsonLdLenient,
7	syntax::{
8		JsonLdContext, JsonLdKeywordType,
9		context::{
10			JsonLdContextTerm, JsonLdContextType, JsonLdContextTypeContainer, JsonLdIndex,
11			JsonLdNest,
12		},
13	},
14};
15use langtag::LangTagBuf;
16use rdf_syntax::{Iri, IriBuf};
17use std::collections::HashMap;
18use std::hash::Hash;
19use std::{borrow::Borrow, fmt};
20
21/// Term binding.
22pub enum JsonLdBinding {
23	/// Normal term definition.
24	Normal(JsonLdContextTerm, Box<JsonLdProcessedNormalTermDefinition>),
25
26	/// `@type` term definition.
27	Type(JsonLdProcessedTypeTermDefinition),
28}
29
30/// Term binding reference.
31pub enum JsonLdBindingRef<'a> {
32	/// Normal term definition.
33	Normal(
34		&'a JsonLdContextTerm,
35		&'a JsonLdProcessedNormalTermDefinition,
36	),
37
38	/// `@type` term definition.
39	Type(&'a JsonLdProcessedTypeTermDefinition),
40}
41
42pub enum JsonLdBindingTerm<'a> {
43	Normal(&'a JsonLdContextTerm),
44	Type,
45}
46
47impl<'a> JsonLdBindingTerm<'a> {
48	pub fn as_str(&self) -> &'a str {
49		match self {
50			Self::Normal(key) => key.as_str(),
51			Self::Type => "@type",
52		}
53	}
54}
55
56impl<'a> fmt::Display for JsonLdBindingTerm<'a> {
57	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58		self.as_str().fmt(f)
59	}
60}
61
62impl<'a> JsonLdBindingRef<'a> {
63	/// Returns a reference to the bound term.
64	pub fn term(&self) -> JsonLdBindingTerm<'a> {
65		match self {
66			Self::Normal(key, _) => JsonLdBindingTerm::Normal(key),
67			Self::Type(_) => JsonLdBindingTerm::Type,
68		}
69	}
70
71	/// Returns a reference to the bound term definition.
72	pub fn definition(&self) -> JsonLdProcessedTermDefinitionRef<'a> {
73		match self {
74			Self::Normal(_, d) => JsonLdProcessedTermDefinitionRef::Normal(d),
75			Self::Type(d) => JsonLdProcessedTermDefinitionRef::Type(d),
76		}
77	}
78}
79
80/// Context term definitions.
81#[derive(Clone, Default)]
82pub struct JsonLdDefinitions {
83	normal: HashMap<JsonLdContextTerm, JsonLdProcessedNormalTermDefinition>,
84	type_: Option<JsonLdProcessedTypeTermDefinition>,
85}
86
87impl JsonLdDefinitions {
88	#[allow(clippy::type_complexity)]
89	pub fn into_parts(
90		self,
91	) -> (
92		HashMap<JsonLdContextTerm, JsonLdProcessedNormalTermDefinition>,
93		Option<JsonLdProcessedTypeTermDefinition>,
94	) {
95		(self.normal, self.type_)
96	}
97
98	/// Returns the number of defined terms.
99	pub fn len(&self) -> usize {
100		if self.type_.is_some() {
101			self.normal.len() + 1
102		} else {
103			self.normal.len()
104		}
105	}
106
107	/// Checks if no terms are defined.
108	pub fn is_empty(&self) -> bool {
109		self.type_.is_none() && self.normal.is_empty()
110	}
111
112	/// Returns a reference to the definition of the given `term`, if any.
113	pub fn get<Q>(&self, term: &Q) -> Option<JsonLdProcessedTermDefinitionRef<'_>>
114	where
115		Q: ?Sized + Hash + Eq,
116		JsonLdContextTerm: Borrow<Q>,
117		JsonLdKeywordType: Borrow<Q>,
118	{
119		if JsonLdKeywordType.borrow() == term {
120			self.type_
121				.as_ref()
122				.map(JsonLdProcessedTermDefinitionRef::Type)
123		} else {
124			self.normal
125				.get(term)
126				.map(JsonLdProcessedTermDefinitionRef::Normal)
127		}
128	}
129
130	/// Returns a reference to the normal definition of the given `term`, if any.
131	pub fn get_normal<Q>(&self, term: &Q) -> Option<&JsonLdProcessedNormalTermDefinition>
132	where
133		Q: ?Sized + Hash + Eq,
134		JsonLdContextTerm: Borrow<Q>,
135	{
136		self.normal.get(term)
137	}
138
139	/// Returns a reference to the `@type` definition, if any.
140	pub fn get_type(&self) -> Option<&JsonLdProcessedTypeTermDefinition> {
141		self.type_.as_ref()
142	}
143
144	pub fn contains_term<Q>(&self, term: &Q) -> bool
145	where
146		Q: ?Sized + Hash + Eq,
147		JsonLdContextTerm: Borrow<Q>,
148		JsonLdKeywordType: Borrow<Q>,
149	{
150		if JsonLdKeywordType.borrow() == term {
151			self.type_.is_some()
152		} else {
153			self.normal.contains_key(term)
154		}
155	}
156
157	/// Inserts the given `binding`.
158	pub fn insert(&mut self, binding: JsonLdBinding) -> Option<JsonLdProcessedTermDefinition> {
159		match binding {
160			JsonLdBinding::Normal(key, definition) => self
161				.insert_normal(key, *definition)
162				.map(JsonLdProcessedTermDefinition::Normal),
163			JsonLdBinding::Type(definition) => self
164				.insert_type(definition)
165				.map(JsonLdProcessedTermDefinition::Type),
166		}
167	}
168
169	/// Defines the given normal term.
170	pub fn insert_normal(
171		&mut self,
172		term: JsonLdContextTerm,
173		definition: JsonLdProcessedNormalTermDefinition,
174	) -> Option<JsonLdProcessedNormalTermDefinition> {
175		self.normal.insert(term, definition)
176	}
177
178	/// Inserts the given `@type` definition.
179	pub fn insert_type(
180		&mut self,
181		definition: JsonLdProcessedTypeTermDefinition,
182	) -> Option<JsonLdProcessedTypeTermDefinition> {
183		self.type_.replace(definition)
184	}
185
186	/// Sets the given `term` normal definition.
187	pub fn set_normal(
188		&mut self,
189		term: JsonLdContextTerm,
190		definition: Option<JsonLdProcessedNormalTermDefinition>,
191	) -> Option<JsonLdProcessedNormalTermDefinition> {
192		match definition {
193			Some(d) => self.normal.insert(term, d),
194			None => self.normal.remove(&term),
195		}
196	}
197
198	/// Sets the given `@type` definition.
199	pub fn set_type(
200		&mut self,
201		definition: Option<JsonLdProcessedTypeTermDefinition>,
202	) -> Option<JsonLdProcessedTypeTermDefinition> {
203		std::mem::replace(&mut self.type_, definition)
204	}
205
206	/// Returns an iterator over the term definitions.
207	pub fn iter(&self) -> JsonLdDefinitionsIter<'_> {
208		JsonLdDefinitionsIter {
209			type_: self.type_.as_ref(),
210			normal: self.normal.iter(),
211		}
212	}
213}
214
215pub struct JsonLdDefinitionsIter<'a> {
216	type_: Option<&'a JsonLdProcessedTypeTermDefinition>,
217	normal: std::collections::hash_map::Iter<
218		'a,
219		JsonLdContextTerm,
220		JsonLdProcessedNormalTermDefinition,
221	>,
222}
223
224impl<'a> Iterator for JsonLdDefinitionsIter<'a> {
225	type Item = JsonLdBindingRef<'a>;
226
227	fn next(&mut self) -> Option<Self::Item> {
228		self.type_.take().map(JsonLdBindingRef::Type).or_else(|| {
229			self.normal
230				.next()
231				.map(|(k, d)| JsonLdBindingRef::Normal(k, d))
232		})
233	}
234}
235
236impl<'a> IntoIterator for &'a JsonLdDefinitions {
237	type Item = JsonLdBindingRef<'a>;
238	type IntoIter = JsonLdDefinitionsIter<'a>;
239
240	fn into_iter(self) -> Self::IntoIter {
241		self.iter()
242	}
243}
244
245pub struct JsonLdDefinitionsIntoIter {
246	type_: Option<JsonLdProcessedTypeTermDefinition>,
247	normal: std::collections::hash_map::IntoIter<
248		JsonLdContextTerm,
249		JsonLdProcessedNormalTermDefinition,
250	>,
251}
252
253impl Iterator for JsonLdDefinitionsIntoIter {
254	type Item = JsonLdBinding;
255
256	fn next(&mut self) -> Option<Self::Item> {
257		self.type_.take().map(JsonLdBinding::Type).or_else(|| {
258			self.normal
259				.next()
260				.map(|(k, d)| JsonLdBinding::Normal(k, Box::new(d)))
261		})
262	}
263}
264
265impl IntoIterator for JsonLdDefinitions {
266	type Item = JsonLdBinding;
267	type IntoIter = JsonLdDefinitionsIntoIter;
268
269	fn into_iter(self) -> Self::IntoIter {
270		JsonLdDefinitionsIntoIter {
271			type_: self.type_,
272			normal: self.normal.into_iter(),
273		}
274	}
275}
276
277/// `@type` term definition.
278///
279/// Such definition compared to a [`JsonLdProcessedNormalTermDefinition`] can only contain
280/// a `@container` and `@protected` value.
281#[derive(PartialEq, Eq, Clone)]
282pub struct JsonLdProcessedTypeTermDefinition {
283	/// Type container.
284	pub container: JsonLdContextTypeContainer,
285
286	/// Protection flag.
287	pub protected: bool,
288}
289
290impl Default for JsonLdProcessedTypeTermDefinition {
291	fn default() -> Self {
292		Self {
293			container: JsonLdContextTypeContainer::Set,
294			protected: false,
295		}
296	}
297}
298
299impl JsonLdProcessedTypeTermDefinition {
300	pub fn modulo_protected_field(&self) -> JsonLdModuloProtected<&Self> {
301		JsonLdModuloProtected(self)
302	}
303
304	pub fn into_syntax_definition(self) -> JsonLdContextType {
305		JsonLdContextType {
306			container: self.container,
307			protected: if self.protected { Some(true) } else { None },
308		}
309	}
310}
311
312/// Term definition.
313#[derive(PartialEq, Eq, Clone)]
314pub enum JsonLdProcessedTermDefinition {
315	/// `@type` term definition.
316	Type(JsonLdProcessedTypeTermDefinition),
317
318	/// Normal term definition.
319	Normal(JsonLdProcessedNormalTermDefinition),
320}
321
322impl JsonLdProcessedTermDefinition {
323	pub fn as_ref(&self) -> JsonLdProcessedTermDefinitionRef<'_> {
324		match self {
325			Self::Type(t) => JsonLdProcessedTermDefinitionRef::Type(t),
326			Self::Normal(n) => JsonLdProcessedTermDefinitionRef::Normal(n),
327		}
328	}
329
330	pub fn modulo_protected_field(
331		&self,
332	) -> JsonLdModuloProtected<JsonLdProcessedTermDefinitionRef<'_>> {
333		JsonLdModuloProtected(self.as_ref())
334	}
335
336	pub fn value(&self) -> Option<&JsonLdTerm> {
337		match self {
338			Self::Type(_) => None,
339			Self::Normal(d) => d.value.as_ref(),
340		}
341	}
342
343	pub fn prefix(&self) -> bool {
344		match self {
345			Self::Type(_) => false,
346			Self::Normal(d) => d.prefix,
347		}
348	}
349
350	pub fn protected(&self) -> bool {
351		match self {
352			Self::Type(d) => d.protected,
353			Self::Normal(d) => d.protected,
354		}
355	}
356
357	pub fn reverse_property(&self) -> bool {
358		match self {
359			Self::Type(_) => false,
360			Self::Normal(d) => d.reverse_property,
361		}
362	}
363
364	pub fn base_url(&self) -> Option<&IriBuf> {
365		match self {
366			Self::Type(_) => None,
367			Self::Normal(d) => d.base_url.as_ref(),
368		}
369	}
370
371	pub fn context(&self) -> Option<&JsonLdContext> {
372		match self {
373			Self::Type(_) => None,
374			Self::Normal(d) => d.context.as_deref(),
375		}
376	}
377
378	pub fn container(&self) -> JsonLdContainer {
379		match self {
380			Self::Type(d) => d.container.into(),
381			Self::Normal(d) => d.container,
382		}
383	}
384
385	pub fn direction(&self) -> Option<JsonLdNullable<JsonLdDirection>> {
386		match self {
387			Self::Type(_) => None,
388			Self::Normal(d) => d.direction,
389		}
390	}
391
392	pub fn index(&self) -> Option<&JsonLdIndex> {
393		match self {
394			Self::Type(_) => None,
395			Self::Normal(d) => d.index.as_ref(),
396		}
397	}
398
399	pub fn language(&self) -> Option<JsonLdNullable<&JsonLdLenient<LangTagBuf>>> {
400		match self {
401			Self::Type(_) => None,
402			Self::Normal(d) => d.language.as_ref().map(JsonLdNullable::as_ref),
403		}
404	}
405
406	pub fn nest(&self) -> Option<&JsonLdNest> {
407		match self {
408			Self::Type(_) => None,
409			Self::Normal(d) => d.nest.as_ref(),
410		}
411	}
412
413	pub fn typ(&self) -> Option<&JsonLdType> {
414		match self {
415			Self::Type(_) => None,
416			Self::Normal(d) => d.typ.as_ref(),
417		}
418	}
419}
420
421/// Term definition reference.
422#[derive(PartialEq, Eq)]
423pub enum JsonLdProcessedTermDefinitionRef<'a> {
424	/// `@type` definition.
425	Type(&'a JsonLdProcessedTypeTermDefinition),
426
427	/// Normal definition.
428	Normal(&'a JsonLdProcessedNormalTermDefinition),
429}
430
431impl<'a> JsonLdProcessedTermDefinitionRef<'a> {
432	pub fn modulo_protected_field(&self) -> JsonLdModuloProtected<Self> {
433		JsonLdModuloProtected(*self)
434	}
435
436	pub fn value(&self) -> Option<&'a JsonLdTerm> {
437		match self {
438			Self::Type(_) => None,
439			Self::Normal(d) => d.value.as_ref(),
440		}
441	}
442
443	pub fn prefix(&self) -> bool {
444		match self {
445			Self::Type(_) => false,
446			Self::Normal(d) => d.prefix,
447		}
448	}
449
450	pub fn protected(&self) -> bool {
451		match self {
452			Self::Type(d) => d.protected,
453			Self::Normal(d) => d.protected,
454		}
455	}
456
457	pub fn reverse_property(&self) -> bool {
458		match self {
459			Self::Type(_) => false,
460			Self::Normal(d) => d.reverse_property,
461		}
462	}
463
464	pub fn base_url(&self) -> Option<&'a Iri> {
465		match self {
466			Self::Type(_) => None,
467			Self::Normal(d) => d.base_url.as_deref(),
468		}
469	}
470
471	pub fn context(&self) -> Option<&'a JsonLdContext> {
472		match self {
473			Self::Type(_) => None,
474			Self::Normal(d) => d.context.as_deref(),
475		}
476	}
477
478	/// Location of the term definition itself, as recorded when it was
479	/// created by the Create Term Definition algorithm.
480	pub fn location(&self) -> Option<&'a JsonLdBacktrace> {
481		match self {
482			Self::Type(_) => None,
483			Self::Normal(d) => Some(&d.location),
484		}
485	}
486
487	pub fn container(&self) -> JsonLdContainer {
488		match self {
489			Self::Type(d) => d.container.into(),
490			Self::Normal(d) => d.container,
491		}
492	}
493
494	pub fn direction(&self) -> Option<JsonLdNullable<JsonLdDirection>> {
495		match self {
496			Self::Type(_) => None,
497			Self::Normal(d) => d.direction,
498		}
499	}
500
501	pub fn index(&self) -> Option<&'a JsonLdIndex> {
502		match self {
503			Self::Type(_) => None,
504			Self::Normal(d) => d.index.as_ref(),
505		}
506	}
507
508	pub fn language(&self) -> Option<JsonLdNullable<&'a JsonLdLenient<LangTagBuf>>> {
509		match self {
510			Self::Type(_) => None,
511			Self::Normal(d) => d.language.as_ref().map(JsonLdNullable::as_ref),
512		}
513	}
514
515	pub fn nest(&self) -> Option<&'a JsonLdNest> {
516		match self {
517			Self::Type(_) => None,
518			Self::Normal(d) => d.nest.as_ref(),
519		}
520	}
521
522	pub fn typ(&self) -> Option<&'a JsonLdType> {
523		match self {
524			Self::Type(_) => None,
525			Self::Normal(d) => d.typ.as_ref(),
526		}
527	}
528}
529
530impl<'a> Clone for JsonLdProcessedTermDefinitionRef<'a> {
531	fn clone(&self) -> Self {
532		*self
533	}
534}
535
536impl<'a> Copy for JsonLdProcessedTermDefinitionRef<'a> {}
537
538// A term definition.
539#[derive(PartialEq, Eq, Clone, Default)]
540pub struct JsonLdProcessedNormalTermDefinition {
541	/// Location of the term definition.
542	pub location: JsonLdBacktraceBuf,
543
544	// IRI mapping.
545	pub value: Option<JsonLdTerm>,
546
547	// Prefix flag.
548	pub prefix: bool,
549
550	// Protected flag.
551	pub protected: bool,
552
553	// Reverse property flag.
554	pub reverse_property: bool,
555
556	// Optional base URL.
557	pub base_url: Option<IriBuf>,
558
559	// Optional context.
560	pub context: Option<Box<JsonLdContext>>,
561
562	// Container mapping.
563	pub container: JsonLdContainer,
564
565	// Optional direction mapping.
566	pub direction: Option<JsonLdNullable<JsonLdDirection>>,
567
568	// Optional index mapping.
569	pub index: Option<JsonLdIndex>,
570
571	// Optional language mapping.
572	pub language: Option<JsonLdNullable<JsonLdLenient<LangTagBuf>>>,
573
574	// Optional nest value.
575	pub nest: Option<JsonLdNest>,
576
577	// Optional type mapping.
578	pub typ: Option<JsonLdType>,
579}
580
581impl JsonLdProcessedNormalTermDefinition {
582	pub fn modulo_protected_field(&self) -> JsonLdModuloProtected<&Self> {
583		JsonLdModuloProtected(self)
584	}
585
586	pub fn base_url(&self) -> Option<&IriBuf> {
587		self.base_url.as_ref()
588	}
589}
590
591/// Wrapper to consider a term definition without the `@protected` flag.
592pub struct JsonLdModuloProtected<T>(T);
593
594impl<'b> PartialEq<JsonLdModuloProtected<&'b JsonLdProcessedNormalTermDefinition>>
595	for JsonLdModuloProtected<&JsonLdProcessedNormalTermDefinition>
596{
597	fn eq(&self, other: &JsonLdModuloProtected<&'b JsonLdProcessedNormalTermDefinition>) -> bool {
598		// NOTE we ignore the `protected` flag.
599		self.0.prefix == other.0.prefix
600			&& self.0.reverse_property == other.0.reverse_property
601			&& self.0.language == other.0.language
602			&& self.0.direction == other.0.direction
603			&& self.0.nest == other.0.nest
604			&& self.0.index == other.0.index
605			&& self.0.container == other.0.container
606			&& self.0.base_url == other.0.base_url
607			&& self.0.value == other.0.value
608			&& self.0.typ == other.0.typ
609			&& self.0.context == other.0.context
610	}
611}
612
613impl Eq for JsonLdModuloProtected<&JsonLdProcessedNormalTermDefinition> {}
614
615impl<'b> PartialEq<JsonLdModuloProtected<&'b JsonLdProcessedTypeTermDefinition>>
616	for JsonLdModuloProtected<&JsonLdProcessedTypeTermDefinition>
617{
618	fn eq(&self, other: &JsonLdModuloProtected<&'b JsonLdProcessedTypeTermDefinition>) -> bool {
619		// NOTE we ignore the `protected` flag.
620		self.0.container == other.0.container
621	}
622}
623
624impl Eq for JsonLdModuloProtected<&JsonLdProcessedTypeTermDefinition> {}
625
626impl<'a, 'b> PartialEq<JsonLdModuloProtected<JsonLdProcessedTermDefinitionRef<'b>>>
627	for JsonLdModuloProtected<JsonLdProcessedTermDefinitionRef<'a>>
628{
629	fn eq(&self, other: &JsonLdModuloProtected<JsonLdProcessedTermDefinitionRef<'b>>) -> bool {
630		// NOTE we ignore the `protected` flag.
631		self.0.prefix() == other.0.prefix()
632			&& self.0.reverse_property() == other.0.reverse_property()
633			&& self.0.language() == other.0.language()
634			&& self.0.direction() == other.0.direction()
635			&& self.0.nest() == other.0.nest()
636			&& self.0.index() == other.0.index()
637			&& self.0.container() == other.0.container()
638			&& self.0.base_url() == other.0.base_url()
639			&& self.0.value() == other.0.value()
640			&& self.0.typ() == other.0.typ()
641			&& self.0.context() == other.0.context()
642	}
643}
644
645impl<'a> Eq for JsonLdModuloProtected<JsonLdProcessedTermDefinitionRef<'a>> {}