Skip to main content

json_ld/core/context/
mod.rs

1//! Context processing algorithm and related types.
2mod container;
3mod definition;
4mod embed;
5pub mod inverse;
6
7pub use container::JsonLdContainer;
8use langtag::{LangTag, LangTagBuf};
9
10use crate::syntax::context::JsonLdContextTerm;
11use crate::syntax::{JsonLdContext, JsonLdKeywordType};
12use crate::{JsonLdDirection, JsonLdLenient, JsonLdTerm};
13use rdf_syntax::{Iri, IriBuf};
14use std::borrow::{Borrow, Cow};
15use std::hash::Hash;
16use std::ops::{Deref, DerefMut};
17use std::sync::OnceLock;
18
19pub use definition::*;
20pub use embed::*;
21pub use inverse::InverseJsonLdContext;
22
23/// Processed JSON-LD context.
24///
25/// Represents the result of the [context processing algorithm][1] implemented
26/// by the [`json-ld-context-processing`] crate.
27///
28/// [1]: <https://www.w3.org/TR/json-ld11-api/#context-processing-algorithm>
29/// [`json-ld-context-processing`]: <https://crates.io/crates/json-ld-context-processing>
30pub struct JsonLdProcessedContext<'a> {
31	unprocessed: Cow<'a, JsonLdContext>,
32	raw: RawJsonLdProcessedContext,
33}
34
35impl<'a> JsonLdProcessedContext<'a> {
36	pub fn new(unprocessed: Cow<'a, JsonLdContext>, raw: RawJsonLdProcessedContext) -> Self {
37		Self { unprocessed, raw }
38	}
39
40	pub fn unprocessed(&self) -> &JsonLdContext {
41		&self.unprocessed
42	}
43
44	pub fn as_raw(&self) -> &RawJsonLdProcessedContext {
45		&self.raw
46	}
47
48	pub fn into_raw(self) -> RawJsonLdProcessedContext {
49		self.raw
50	}
51
52	pub fn into_owned(self) -> JsonLdProcessedContext<'static> {
53		JsonLdProcessedContext {
54			unprocessed: Cow::Owned(self.unprocessed.into_owned()),
55			raw: self.raw,
56		}
57	}
58}
59
60impl Deref for JsonLdProcessedContext<'_> {
61	type Target = RawJsonLdProcessedContext;
62
63	fn deref(&self) -> &Self::Target {
64		&self.raw
65	}
66}
67
68impl DerefMut for JsonLdProcessedContext<'_> {
69	fn deref_mut(&mut self) -> &mut Self::Target {
70		&mut self.raw
71	}
72}
73
74/// Processed JSON-LD context.
75///
76/// Represents the result of the [context processing algorithm][1] implemented
77/// by the [`json-ld-context-processing`] crate.
78///
79/// [1]: <https://www.w3.org/TR/json-ld11-api/#context-processing-algorithm>
80/// [`json-ld-context-processing`]: <https://crates.io/crates/json-ld-context-processing>
81#[derive(Default)]
82pub struct RawJsonLdProcessedContext {
83	original_base_url: Option<IriBuf>,
84	base_iri: Option<IriBuf>,
85	vocabulary: Option<JsonLdTerm>,
86	default_language: Option<JsonLdLenient<LangTagBuf>>,
87	default_base_direction: Option<JsonLdDirection>,
88	previous_context: Option<Box<Self>>,
89	definitions: JsonLdDefinitions,
90	inverse: OnceLock<InverseJsonLdContext>,
91}
92
93pub type DefinitionEntryRef<'a> = (&'a JsonLdContextTerm, &'a JsonLdProcessedTermDefinition);
94
95impl RawJsonLdProcessedContext {
96	/// Create a new context with the given base IRI.
97	pub fn new(base_iri: Option<IriBuf>) -> Self {
98		Self {
99			original_base_url: base_iri.clone(),
100			base_iri,
101			vocabulary: None,
102			default_language: None,
103			default_base_direction: None,
104			previous_context: None,
105			definitions: JsonLdDefinitions::default(),
106			inverse: OnceLock::default(),
107		}
108	}
109
110	/// Returns a reference to the given `term` definition, if any.
111	pub fn get<Q>(&self, term: &Q) -> Option<JsonLdProcessedTermDefinitionRef<'_>>
112	where
113		JsonLdContextTerm: Borrow<Q>,
114		JsonLdKeywordType: Borrow<Q>,
115		Q: ?Sized + Hash + Eq,
116	{
117		self.definitions.get(term)
118	}
119
120	/// Returns a reference to the given `term` normal definition, if any.
121	pub fn get_normal<Q>(&self, term: &Q) -> Option<&JsonLdProcessedNormalTermDefinition>
122	where
123		JsonLdContextTerm: Borrow<Q>,
124		Q: ?Sized + Hash + Eq,
125	{
126		self.definitions.get_normal(term)
127	}
128
129	/// Returns a reference to the `@type` definition, if any.
130	pub fn get_type(&self) -> Option<&JsonLdProcessedTypeTermDefinition> {
131		self.definitions.get_type()
132	}
133
134	/// Checks if the given `term` is defined.
135	pub fn contains_term<Q>(&self, term: &Q) -> bool
136	where
137		JsonLdContextTerm: Borrow<Q>,
138		JsonLdKeywordType: Borrow<Q>,
139		Q: ?Sized + Hash + Eq,
140	{
141		self.definitions.contains_term(term)
142	}
143
144	/// Returns the original base URL of the context.
145	pub fn original_base_url(&self) -> Option<&Iri> {
146		self.original_base_url.as_deref()
147	}
148
149	/// Returns the base IRI of the context.
150	pub fn base_iri(&self) -> Option<&Iri> {
151		self.base_iri.as_deref()
152	}
153
154	/// Returns the `@vocab` value, if any.
155	pub fn vocabulary(&self) -> Option<&JsonLdTerm> {
156		match &self.vocabulary {
157			Some(v) => Some(v),
158			None => None,
159		}
160	}
161
162	/// Returns the default `@language` value.
163	pub fn default_language(&self) -> Option<JsonLdLenient<&LangTag>> {
164		self.default_language.as_ref().map(|tag| tag.as_deref())
165	}
166
167	/// Returns the default `@direction` value.
168	pub fn default_base_direction(&self) -> Option<JsonLdDirection> {
169		self.default_base_direction
170	}
171
172	/// Returns a reference to the previous context.
173	pub fn previous_context(&self) -> Option<&Self> {
174		match &self.previous_context {
175			Some(c) => Some(c),
176			None => None,
177		}
178	}
179
180	/// Returns the number of terms defined.
181	pub fn len(&self) -> usize {
182		self.definitions.len()
183	}
184
185	/// Checks if no terms are defined.
186	pub fn is_empty(&self) -> bool {
187		self.definitions.is_empty()
188	}
189
190	/// Returns a handle to the term definitions.
191	pub fn definitions(&self) -> &JsonLdDefinitions {
192		&self.definitions
193	}
194
195	/// Checks if the context has a protected definition.
196	pub fn has_protected_items(&self) -> bool {
197		for binding in self.definitions() {
198			if binding.definition().protected() {
199				return true;
200			}
201		}
202
203		false
204	}
205
206	/// Returns the inverse of this context.
207	pub fn inverse(&self) -> &InverseJsonLdContext {
208		self.inverse.get_or_init(|| self.into())
209	}
210
211	/// Sets the normal definition for the given term `key`.
212	pub fn set_normal(
213		&mut self,
214		key: JsonLdContextTerm,
215		definition: Option<JsonLdProcessedNormalTermDefinition>,
216	) -> Option<JsonLdProcessedNormalTermDefinition> {
217		self.inverse.take();
218		self.definitions.set_normal(key, definition)
219	}
220
221	/// Sets the `@type` definition.
222	pub fn set_type(
223		&mut self,
224		type_: Option<JsonLdProcessedTypeTermDefinition>,
225	) -> Option<JsonLdProcessedTypeTermDefinition> {
226		self.definitions.set_type(type_)
227	}
228
229	/// Sets the base IRI.
230	pub fn set_base_iri(&mut self, iri: Option<IriBuf>) {
231		self.inverse.take();
232		self.base_iri = iri
233	}
234
235	/// Sets the `@vocab` value.
236	pub fn set_vocabulary(&mut self, vocab: Option<JsonLdTerm>) {
237		self.inverse.take();
238		self.vocabulary = vocab;
239	}
240
241	/// Sets the default `@language` value.
242	pub fn set_default_language(&mut self, lang: Option<JsonLdLenient<LangTagBuf>>) {
243		self.inverse.take();
244		self.default_language = lang;
245	}
246
247	/// Sets the default `@direction` value.
248	pub fn set_default_base_direction(&mut self, dir: Option<JsonLdDirection>) {
249		self.inverse.take();
250		self.default_base_direction = dir;
251	}
252
253	/// Sets the previous context.
254	pub fn set_previous_context(&mut self, previous: Self) {
255		self.inverse.take();
256		self.previous_context = Some(Box::new(previous))
257	}
258}
259
260impl Clone for RawJsonLdProcessedContext {
261	fn clone(&self) -> Self {
262		Self {
263			original_base_url: self.original_base_url.clone(),
264			base_iri: self.base_iri.clone(),
265			vocabulary: self.vocabulary.clone(),
266			default_language: self.default_language.clone(),
267			default_base_direction: self.default_base_direction,
268			previous_context: self.previous_context.clone(),
269			definitions: self.definitions.clone(),
270			inverse: OnceLock::default(),
271		}
272	}
273}
274
275impl PartialEq for RawJsonLdProcessedContext {
276	fn eq(&self, other: &Self) -> bool {
277		self.original_base_url == other.original_base_url
278			&& self.base_iri == other.base_iri
279			&& self.vocabulary == other.vocabulary
280			&& self.default_language == other.default_language
281			&& self.default_base_direction == other.default_base_direction
282			&& self.previous_context == other.previous_context
283	}
284}