Skip to main content

json_ld/syntax/context/
mod.rs

1use rdf_syntax::{Iri, IriBuf, IriRef, IriRefBuf};
2
3mod definition;
4
5pub use definition::*;
6
7/// JSON-LD Context.
8///
9/// Can represent a single context entry, or a list of context entries.
10#[derive(PartialEq, Eq, Clone, Debug)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[cfg_attr(feature = "serde", serde(untagged))]
13pub enum JsonLdContext {
14	One(JsonLdContextEntry),
15	Many(Vec<JsonLdContextEntry>),
16}
17
18impl Default for JsonLdContext {
19	fn default() -> Self {
20		Self::Many(Vec::new())
21	}
22}
23
24impl JsonLdContext {
25	/// Creates a new context with a single entry.
26	pub fn one(context: JsonLdContextEntry) -> Self {
27		Self::One(context)
28	}
29
30	/// Creates the `null` context.
31	pub fn null() -> Self {
32		Self::one(JsonLdContextEntry::Null)
33	}
34
35	/// Creates a new context with a single IRI-reference entry.
36	pub fn iri_ref(iri_ref: IriRefBuf) -> Self {
37		Self::one(JsonLdContextEntry::IriRef(iri_ref))
38	}
39
40	/// Creates a new context with a single context definition entry.
41	pub fn definition(def: JsonLdContextDefinition) -> Self {
42		Self::one(JsonLdContextEntry::Definition(def))
43	}
44
45	/// Deserializes an optional context, preserving `null`.
46	///
47	/// Maps JSON `null` to `Some(Box(Self::null()))` instead of `None`,
48	/// distinguishing absent `@context` from explicit `@context: null`.
49	/// Use with `#[serde(default, deserialize_with = "Context::optional")]`.
50	#[cfg(feature = "serde")]
51	pub fn optional<'de, D>(deserializer: D) -> Result<Option<Box<Self>>, D::Error>
52	where
53		D: serde::Deserializer<'de>,
54	{
55		<Self as serde::Deserialize>::deserialize(deserializer).map(|c| Some(Box::new(c)))
56	}
57
58	#[cfg(feature = "serde")]
59	pub fn to_json(&self) -> json_syntax::JsonValue {
60		json_syntax::to_value(self).unwrap()
61	}
62}
63
64impl JsonLdContext {
65	pub fn len(&self) -> usize {
66		match self {
67			Self::One(_) => 1,
68			Self::Many(l) => l.len(),
69		}
70	}
71
72	pub fn is_empty(&self) -> bool {
73		match self {
74			Self::One(_) => false,
75			Self::Many(l) => l.is_empty(),
76		}
77	}
78
79	pub fn as_slice(&self) -> &[JsonLdContextEntry] {
80		match self {
81			Self::One(c) => std::slice::from_ref(c),
82			Self::Many(list) => list,
83		}
84	}
85
86	pub fn is_object(&self) -> bool {
87		match self {
88			Self::One(c) => c.is_object(),
89			_ => false,
90		}
91	}
92
93	pub fn is_array(&self) -> bool {
94		matches!(self, Self::Many(_))
95	}
96
97	pub fn iter(&self) -> std::slice::Iter<'_, JsonLdContextEntry> {
98		self.as_slice().iter()
99	}
100}
101
102pub enum JsonLdContextIntoIter {
103	One(Option<JsonLdContextEntry>),
104	Many(std::vec::IntoIter<JsonLdContextEntry>),
105}
106
107impl Iterator for JsonLdContextIntoIter {
108	type Item = JsonLdContextEntry;
109
110	fn next(&mut self) -> Option<Self::Item> {
111		match self {
112			Self::One(t) => t.take(),
113			Self::Many(t) => t.next(),
114		}
115	}
116}
117
118impl IntoIterator for JsonLdContext {
119	type Item = JsonLdContextEntry;
120	type IntoIter = JsonLdContextIntoIter;
121
122	fn into_iter(self) -> Self::IntoIter {
123		match self {
124			Self::One(t) => JsonLdContextIntoIter::One(Some(t)),
125			Self::Many(t) => JsonLdContextIntoIter::Many(t.into_iter()),
126		}
127	}
128}
129
130impl<'a> IntoIterator for &'a JsonLdContext {
131	type IntoIter = std::slice::Iter<'a, JsonLdContextEntry>;
132	type Item = &'a JsonLdContextEntry;
133
134	fn into_iter(self) -> Self::IntoIter {
135		self.iter()
136	}
137}
138
139impl From<JsonLdContextEntry> for JsonLdContext {
140	fn from(c: JsonLdContextEntry) -> Self {
141		Self::One(c)
142	}
143}
144
145impl From<IriRefBuf> for JsonLdContext {
146	fn from(i: IriRefBuf) -> Self {
147		Self::One(JsonLdContextEntry::IriRef(i))
148	}
149}
150
151impl<'a> From<&'a IriRef> for JsonLdContext {
152	fn from(i: &'a IriRef) -> Self {
153		Self::One(JsonLdContextEntry::IriRef(i.to_owned()))
154	}
155}
156
157impl From<IriBuf> for JsonLdContext {
158	fn from(i: IriBuf) -> Self {
159		Self::One(JsonLdContextEntry::IriRef(i.into()))
160	}
161}
162
163impl<'a> From<&'a Iri> for JsonLdContext {
164	fn from(i: &'a Iri) -> Self {
165		Self::One(JsonLdContextEntry::IriRef(i.to_owned().into()))
166	}
167}
168
169impl From<JsonLdContextDefinition> for JsonLdContext {
170	fn from(c: JsonLdContextDefinition) -> Self {
171		Self::One(JsonLdContextEntry::Definition(c))
172	}
173}
174
175/// Context.
176#[derive(PartialEq, Eq, Clone, Debug)]
177#[cfg_attr(
178	feature = "serde",
179	derive(serde::Serialize, serde::Deserialize),
180	serde(untagged)
181)]
182pub enum JsonLdContextEntry {
183	Null,
184	IriRef(IriRefBuf),
185	Definition(JsonLdContextDefinition),
186}
187
188impl JsonLdContextEntry {
189	pub fn is_object(&self) -> bool {
190		matches!(self, Self::Definition(_))
191	}
192
193	pub fn is_iri_ref(&self) -> bool {
194		matches!(self, Self::IriRef(_))
195	}
196
197	pub fn as_iri_ref(&self) -> Option<&IriRef> {
198		match self {
199			Self::IriRef(r) => Some(r),
200			_ => None,
201		}
202	}
203}
204
205impl From<IriRefBuf> for JsonLdContextEntry {
206	fn from(i: IriRefBuf) -> Self {
207		JsonLdContextEntry::IriRef(i)
208	}
209}
210
211impl<'a> From<&'a IriRef> for JsonLdContextEntry {
212	fn from(i: &'a IriRef) -> Self {
213		JsonLdContextEntry::IriRef(i.to_owned())
214	}
215}
216
217impl From<IriBuf> for JsonLdContextEntry {
218	fn from(i: IriBuf) -> Self {
219		JsonLdContextEntry::IriRef(i.into())
220	}
221}
222
223impl<'a> From<&'a Iri> for JsonLdContextEntry {
224	fn from(i: &'a Iri) -> Self {
225		JsonLdContextEntry::IriRef(i.to_owned().into())
226	}
227}
228
229impl From<JsonLdContextDefinition> for JsonLdContextEntry {
230	fn from(c: JsonLdContextDefinition) -> Self {
231		JsonLdContextEntry::Definition(c)
232	}
233}
234
235impl PartialEq<IriRef> for JsonLdContextEntry {
236	fn eq(&self, other: &IriRef) -> bool {
237		self.as_iri_ref().is_some_and(|r| r == other)
238	}
239}
240
241impl<'a> PartialEq<&'a IriRef> for JsonLdContextEntry {
242	fn eq(&self, other: &&'a IriRef) -> bool {
243		self.as_iri_ref().is_some_and(|r| r == other)
244	}
245}
246
247impl PartialEq<Iri> for JsonLdContextEntry {
248	fn eq(&self, other: &Iri) -> bool {
249		self.as_iri_ref().is_some_and(|r| r == other)
250	}
251}
252
253impl<'a> PartialEq<&'a Iri> for JsonLdContextEntry {
254	fn eq(&self, other: &&'a Iri) -> bool {
255		self.as_iri_ref().is_some_and(|r| r == other)
256	}
257}
258
259/// Context document.
260///
261/// A context document is a JSON-LD document containing an object with a single
262/// `@context` entry.
263#[derive(PartialEq, Eq, Clone, Debug)]
264#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
265pub struct JsonLdContextDocumentValue {
266	#[cfg_attr(feature = "serde", serde(rename = "@context"))]
267	pub context: JsonLdContext,
268}
269
270#[cfg(feature = "serde")]
271impl JsonLdContextDocumentValue {
272	pub fn to_json(&self) -> json_syntax::JsonValue {
273		json_syntax::to_value(self).unwrap()
274	}
275}
276
277#[cfg(feature = "serde")]
278impl TryFrom<json_syntax::JsonValue> for JsonLdContextDocumentValue {
279	type Error = crate::syntax::serde::DeserializeError;
280
281	fn try_from(value: json_syntax::JsonValue) -> Result<Self, Self::Error> {
282		crate::syntax::serde::from_value(value)
283	}
284}