Skip to main content

json_ld/core/object/
value.rs

1use crate::object::{JsonLdObjectMut, JsonLdObjectRef};
2use crate::syntax::JsonLdKeyword;
3use crate::{JsonLdDirection, JsonLdLangString, JsonLdLenient, JsonLdType, JsonLdVisit, object};
4use educe::Educe;
5use json_syntax::{JsonNumber, JsonNumberBuf, JsonValue, ryu_js};
6use langtag::LangTag;
7use rdf_syntax::{IdRef, Iri, IriBuf};
8use rdf_syntax::{Literal, RDF_JSON};
9use std::hash::Hash;
10use xsd_types::{XSD_BOOLEAN, XSD_FLOAT, XSD_INTEGER};
11
12/// Value type.
13pub enum JsonLdValueType {
14	Json,
15	Id(IriBuf),
16}
17
18impl JsonLdValueType {
19	pub fn as_id(&self) -> Option<IdRef<'_>> {
20		match self {
21			Self::Json => None,
22			Self::Id(t) => Some(IdRef::Iri(t)),
23		}
24	}
25}
26
27/// Value type reference.
28#[derive(Educe)]
29#[educe(Clone, Copy)]
30pub enum JsonLdValueTypeRef<'a> {
31	Json,
32	Id(&'a Iri),
33}
34
35impl<'a> JsonLdValueTypeRef<'a> {
36	pub fn into_object_type(self) -> JsonLdType {
37		match self {
38			Self::Json => JsonLdType::Json,
39			Self::Id(id) => JsonLdType::Iri(id.to_owned()),
40		}
41	}
42
43	pub fn into_id_ref(self) -> Option<IdRef<'a>> {
44		match self {
45			Self::Json => None,
46			Self::Id(t) => Some(IdRef::Iri(t)),
47		}
48	}
49}
50
51/// Literal type.
52#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
53pub enum JsonLdLiteralType {
54	/// JSON literal (`@json`).
55	Json,
56
57	/// Typed by an IRI.
58	Iri(IriBuf),
59}
60
61impl JsonLdLiteralType {
62	/// Returns this type IRI.
63	///
64	/// If the type is `@json`, this will return [`RDF_JSON`].
65	pub fn iri(&self) -> &Iri {
66		match self {
67			Self::Json => RDF_JSON,
68			Self::Iri(iri) => iri,
69		}
70	}
71
72	/// Returns whether this is the JSON type.
73	///
74	/// Returns `true` if it is `@json` or the [`RDF_JSON`] IRI.
75	pub fn is_json(&self) -> bool {
76		match self {
77			Self::Json => true,
78			Self::Iri(iri) => iri == RDF_JSON,
79		}
80	}
81}
82
83#[cfg(feature = "serde")]
84impl serde::Serialize for JsonLdLiteralType {
85	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
86		match self {
87			Self::Json => serializer.serialize_str("@json"),
88			Self::Iri(iri) => serializer.serialize_str(iri.as_str()),
89		}
90	}
91}
92
93#[cfg(feature = "serde")]
94impl<'de> serde::Deserialize<'de> for JsonLdLiteralType {
95	fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
96		let s = String::deserialize(deserializer)?;
97		if s == "@json" {
98			Ok(Self::Json)
99		} else {
100			IriBuf::new(s)
101				.map(Self::Iri)
102				.map_err(serde::de::Error::custom)
103		}
104	}
105}
106
107/// Literal value.
108///
109/// A JSON-LD value object with a `@value` entry and an optional `@type`.
110#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
111#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
112pub struct JsonLdLiteralValue {
113	/// The value.
114	#[cfg_attr(feature = "serde", serde(rename = "@value"))]
115	pub value: JsonValue,
116
117	/// Optional type.
118	#[cfg_attr(
119		feature = "serde",
120		serde(rename = "@type", default, skip_serializing_if = "Option::is_none")
121	)]
122	pub type_: Option<JsonLdLiteralType>,
123}
124
125impl JsonLdLiteralValue {
126	/// Creates a new literal value.
127	pub fn new(value: JsonValue, type_: Option<JsonLdLiteralType>) -> Self {
128		Self { value, type_ }
129	}
130
131	/// Creates a null literal value.
132	pub fn null() -> Self {
133		Self::new(JsonValue::Null, None)
134	}
135
136	/// Creates a JSON literal value (`@type: "@json"`).
137	pub fn json(value: JsonValue) -> Self {
138		Self::new(value, Some(JsonLdLiteralType::Json))
139	}
140
141	/// Returns the value as a string if it is one.
142	#[inline(always)]
143	pub fn as_str(&self) -> Option<&str> {
144		self.value.as_str().map(AsRef::as_ref)
145	}
146
147	/// Returns the value as a boolean if it is one.
148	#[inline(always)]
149	pub fn as_bool(&self) -> Option<bool> {
150		self.value.as_boolean()
151	}
152
153	/// Returns the value as a number if it is one.
154	#[inline(always)]
155	pub fn as_number(&self) -> Option<&JsonNumber> {
156		self.value.as_number()
157	}
158
159	/// Returns the type IRI.
160	pub fn type_iri(&self) -> Option<&Iri> {
161		match &self.type_ {
162			Some(JsonLdLiteralType::Iri(iri)) => Some(iri),
163			_ => None,
164		}
165	}
166
167	/// Returns true if this is a JSON literal.
168	pub fn is_json(&self) -> bool {
169		self.type_.as_ref().is_some_and(JsonLdLiteralType::is_json)
170	}
171
172	/// Puts this literal into canonical form using the given `buffer`.
173	///
174	/// The buffer is used to compute the canonical form of numbers.
175	pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
176		if let JsonValue::Number(n) = &mut self.value {
177			*n = JsonNumberBuf::from_number(n.canonicalized_with(buffer))
178		}
179	}
180
181	/// Puts this literal into canonical form.
182	pub fn canonicalize(&mut self) {
183		let mut buffer = ryu_js::Buffer::new();
184		self.canonicalize_with(&mut buffer)
185	}
186}
187
188/// Value object.
189///
190/// Either a typed literal value, or an internationalized language string.
191#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
192#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
193#[cfg_attr(feature = "serde", serde(untagged))]
194pub enum JsonLdValue {
195	/// Language tagged string.
196	LangString(JsonLdLangString),
197
198	/// Typed literal value (including JSON literals).
199	Literal(JsonLdLiteralValue),
200}
201
202impl JsonLdValue {
203	/// Creates a `null` value object.
204	#[inline(always)]
205	pub fn null() -> Self {
206		Self::Literal(JsonLdLiteralValue::null())
207	}
208
209	#[inline(always)]
210	pub fn as_str(&self) -> Option<&str> {
211		match self {
212			JsonLdValue::Literal(lit) => lit.as_str(),
213			JsonLdValue::LangString(s) => Some(s.as_str()),
214		}
215	}
216
217	#[inline(always)]
218	pub fn as_literal(&self) -> Option<&JsonLdLiteralValue> {
219		match self {
220			Self::Literal(lit) => Some(lit),
221			_ => None,
222		}
223	}
224
225	pub fn literal_type(&self) -> Option<&JsonLdLiteralType> {
226		match self {
227			Self::Literal(lit) => lit.type_.as_ref(),
228			_ => None,
229		}
230	}
231
232	pub fn literal_type_iri(&self) -> Option<&Iri> {
233		match self {
234			Self::Literal(lit) => lit.type_iri(),
235			_ => None,
236		}
237	}
238
239	/// Set the literal value type, and returns the old type.
240	///
241	/// Has no effect and return `None` if the value is not a literal value.
242	pub fn set_literal_type(&mut self, ty: Option<JsonLdLiteralType>) -> Option<JsonLdLiteralType> {
243		match self {
244			Self::Literal(lit) => std::mem::replace(&mut lit.type_, ty),
245			_ => None,
246		}
247	}
248
249	#[inline(always)]
250	pub fn as_bool(&self) -> Option<bool> {
251		match self {
252			JsonLdValue::Literal(lit) => lit.as_bool(),
253			_ => None,
254		}
255	}
256
257	#[inline(always)]
258	pub fn as_number(&self) -> Option<&JsonNumber> {
259		match self {
260			JsonLdValue::Literal(lit) => lit.as_number(),
261			_ => None,
262		}
263	}
264
265	/// Return the type of the value if any.
266	pub fn typ(&self) -> Option<JsonLdValueTypeRef<'_>> {
267		match self {
268			JsonLdValue::Literal(lit) => match &lit.type_ {
269				Some(JsonLdLiteralType::Json) => Some(JsonLdValueTypeRef::Json),
270				Some(JsonLdLiteralType::Iri(iri)) => Some(JsonLdValueTypeRef::Id(iri)),
271				None => None,
272			},
273			_ => None,
274		}
275	}
276
277	/// If the value is a language tagged string, return its associated language if any.
278	///
279	/// Returns `None` if the value is not a language tagged string.
280	#[inline(always)]
281	pub fn language(&self) -> Option<JsonLdLenient<&LangTag>> {
282		match self {
283			JsonLdValue::LangString(tag) => tag.language(),
284			_ => None,
285		}
286	}
287
288	/// If the value is a language tagged string, return its associated direction if any.
289	///
290	/// Returns `None` if the value is not a language tagged string.
291	#[inline(always)]
292	pub fn direction(&self) -> Option<JsonLdDirection> {
293		match self {
294			JsonLdValue::LangString(s) => s.direction(),
295			_ => None,
296		}
297	}
298
299	/// Returns true if this is a JSON literal.
300	pub fn is_json(&self) -> bool {
301		matches!(self, Self::Literal(lit) if lit.is_json())
302	}
303
304	/// Returns the JSON value if this is a JSON literal.
305	pub fn as_json(&self) -> Option<&JsonValue> {
306		match self {
307			Self::Literal(lit) if lit.is_json() => Some(&lit.value),
308			_ => None,
309		}
310	}
311
312	/// Puts this value object literal into canonical form using the given
313	/// `buffer`.
314	///
315	/// The buffer is used to compute the canonical form of numbers.
316	pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
317		match self {
318			Self::Literal(l) => l.canonicalize_with(buffer),
319			Self::LangString(_) => (),
320		}
321	}
322
323	/// Puts this literal into canonical form.
324	pub fn canonicalize(&mut self) {
325		let mut buffer = ryu_js::Buffer::new();
326		self.canonicalize_with(&mut buffer)
327	}
328
329	#[inline(always)]
330	pub fn entries(&self) -> JsonLdValueEntries<'_> {
331		match self {
332			Self::Literal(lit) => JsonLdValueEntries {
333				value: Some(JsonLdValueValueEntryRef::Value(&lit.value)),
334				type_: match &lit.type_ {
335					Some(JsonLdLiteralType::Json) => Some(JsonLdValueTypeRef::Json),
336					Some(JsonLdLiteralType::Iri(iri)) => Some(JsonLdValueTypeRef::Id(iri)),
337					None => None,
338				},
339				language: None,
340				direction: None,
341			},
342			Self::LangString(l) => JsonLdValueEntries {
343				value: Some(JsonLdValueValueEntryRef::LangString(l.as_str())),
344				type_: None,
345				language: l.language(),
346				direction: l.direction(),
347			},
348		}
349	}
350}
351
352impl JsonLdVisit for JsonLdValue {
353	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
354		f(JsonLdObjectRef::Value(self))
355	}
356
357	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
358		f(JsonLdObjectMut::Value(self))
359	}
360}
361
362impl object::AnyJsonLdObject for JsonLdValue {
363	#[inline(always)]
364	fn as_ref(&self) -> object::JsonLdObjectRef<'_> {
365		object::JsonLdObjectRef::Value(self)
366	}
367}
368
369impl From<Literal> for JsonLdValue {
370	fn from(literal: Literal) -> Self {
371		match literal.r#type {
372			rdf_syntax::LiteralType::Any(ty) => {
373				if ty == XSD_BOOLEAN {
374					match literal.value.as_str() {
375						"true" => {
376							return Self::Literal(JsonLdLiteralValue::new(
377								JsonValue::Boolean(true),
378								Some(JsonLdLiteralType::Iri(ty)),
379							));
380						}
381						"false" => {
382							return Self::Literal(JsonLdLiteralValue::new(
383								JsonValue::Boolean(false),
384								Some(JsonLdLiteralType::Iri(ty)),
385							));
386						}
387						_ => (),
388					}
389				} else if ty == XSD_INTEGER || ty == XSD_FLOAT {
390					if let Ok(number) = literal.value.parse::<JsonNumberBuf>() {
391						return Self::Literal(JsonLdLiteralValue::new(
392							JsonValue::Number(number),
393							Some(JsonLdLiteralType::Iri(ty)),
394						));
395					}
396				} else if ty == RDF_JSON
397					&& let Ok(json) = json_syntax::from_str(&literal.value)
398				{
399					return Self::Literal(JsonLdLiteralValue::json(json));
400				}
401
402				Self::Literal(JsonLdLiteralValue::new(
403					JsonValue::String(literal.value.into()),
404					Some(JsonLdLiteralType::Iri(ty)),
405				))
406			}
407			rdf_syntax::LiteralType::LangString(langtag) => {
408				Self::LangString(JsonLdLangString::from_language(literal.value, langtag))
409			}
410		}
411	}
412}
413
414#[derive(Educe)]
415#[educe(Clone, Copy)]
416pub enum JsonLdValueEntryRef<'a> {
417	Value(JsonLdValueValueEntryRef<'a>),
418	Type(JsonLdValueTypeRef<'a>),
419	Language(JsonLdLenient<&'a LangTag>),
420	Direction(JsonLdDirection),
421}
422
423impl<'a> JsonLdValueEntryRef<'a> {
424	pub fn into_key(self) -> JsonLdValueEntryKey {
425		match self {
426			Self::Value(_) => JsonLdValueEntryKey::Value,
427			Self::Type(_) => JsonLdValueEntryKey::Type,
428			Self::Language(_) => JsonLdValueEntryKey::Language,
429			Self::Direction(_) => JsonLdValueEntryKey::Direction,
430		}
431	}
432
433	pub fn key(&self) -> JsonLdValueEntryKey {
434		self.into_key()
435	}
436
437	pub fn into_value(self) -> JsonLdValueEntryValueRef<'a> {
438		match self {
439			Self::Value(v) => JsonLdValueEntryValueRef::Value(v),
440			Self::Type(v) => JsonLdValueEntryValueRef::Type(v),
441			Self::Language(v) => JsonLdValueEntryValueRef::Language(v),
442			Self::Direction(v) => JsonLdValueEntryValueRef::Direction(v),
443		}
444	}
445
446	pub fn value(&self) -> JsonLdValueEntryValueRef<'a> {
447		match self {
448			Self::Value(v) => JsonLdValueEntryValueRef::Value(*v),
449			Self::Type(v) => JsonLdValueEntryValueRef::Type(*v),
450			Self::Language(v) => JsonLdValueEntryValueRef::Language(*v),
451			Self::Direction(v) => JsonLdValueEntryValueRef::Direction(*v),
452		}
453	}
454}
455
456#[derive(Educe)]
457#[educe(Clone, Copy)]
458pub enum JsonLdValueEntryValueRef<'a> {
459	Value(JsonLdValueValueEntryRef<'a>),
460	Type(JsonLdValueTypeRef<'a>),
461	Language(JsonLdLenient<&'a LangTag>),
462	Direction(JsonLdDirection),
463}
464
465pub enum JsonLdValueValueEntryRef<'a> {
466	Value(&'a JsonValue),
467	LangString(&'a str),
468}
469
470impl<'a> Clone for JsonLdValueValueEntryRef<'a> {
471	fn clone(&self) -> Self {
472		*self
473	}
474}
475
476impl<'a> Copy for JsonLdValueValueEntryRef<'a> {}
477
478#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
479pub enum JsonLdValueEntryKey {
480	Value,
481	Type,
482	Language,
483	Direction,
484}
485
486impl JsonLdValueEntryKey {
487	pub fn into_keyword(self) -> JsonLdKeyword {
488		match self {
489			Self::Value => JsonLdKeyword::Value,
490			Self::Type => JsonLdKeyword::Type,
491			Self::Language => JsonLdKeyword::Language,
492			Self::Direction => JsonLdKeyword::Direction,
493		}
494	}
495
496	pub fn as_keyword(&self) -> JsonLdKeyword {
497		self.into_keyword()
498	}
499
500	pub fn into_str(&self) -> &'static str {
501		match self {
502			Self::Value => "@value",
503			Self::Type => "@type",
504			Self::Language => "@language",
505			Self::Direction => "@direction",
506		}
507	}
508
509	pub fn as_str(&self) -> &'static str {
510		self.into_str()
511	}
512}
513
514#[derive(Educe)]
515#[educe(Clone)]
516pub struct JsonLdValueEntries<'a> {
517	value: Option<JsonLdValueValueEntryRef<'a>>,
518	type_: Option<JsonLdValueTypeRef<'a>>,
519	language: Option<JsonLdLenient<&'a LangTag>>,
520	direction: Option<JsonLdDirection>,
521}
522
523impl<'a> Iterator for JsonLdValueEntries<'a> {
524	type Item = JsonLdValueEntryRef<'a>;
525
526	fn size_hint(&self) -> (usize, Option<usize>) {
527		let mut len = 0;
528
529		if self.value.is_some() {
530			len += 1
531		}
532
533		if self.type_.is_some() {
534			len += 1
535		}
536
537		if self.language.is_some() {
538			len += 1
539		}
540
541		if self.direction.is_some() {
542			len += 1
543		}
544
545		(len, Some(len))
546	}
547
548	fn next(&mut self) -> Option<Self::Item> {
549		self.value
550			.take()
551			.map(JsonLdValueEntryRef::Value)
552			.or_else(|| {
553				self.type_
554					.take()
555					.map(JsonLdValueEntryRef::Type)
556					.or_else(|| {
557						self.language
558							.take()
559							.map(JsonLdValueEntryRef::Language)
560							.or_else(|| self.direction.take().map(JsonLdValueEntryRef::Direction))
561					})
562			})
563	}
564}
565
566impl<'a> ExactSizeIterator for JsonLdValueEntries<'a> {}
567
568impl<'a> DoubleEndedIterator for JsonLdValueEntries<'a> {
569	fn next_back(&mut self) -> Option<Self::Item> {
570		self.direction
571			.take()
572			.map(JsonLdValueEntryRef::Direction)
573			.or_else(|| {
574				self.language
575					.take()
576					.map(JsonLdValueEntryRef::Language)
577					.or_else(|| {
578						self.type_
579							.take()
580							.map(JsonLdValueEntryRef::Type)
581							.or_else(|| self.value.take().map(JsonLdValueEntryRef::Value))
582					})
583			})
584	}
585}