rdf_types/literal/
type.rs

1use core::fmt;
2
3use educe::Educe;
4use iref::{Iri, IriBuf};
5use langtag::{LangTag, LangTagBuf};
6
7use crate::{
8	vocabulary::{
9		EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary,
10		ExtractedFromVocabulary, IriVocabulary,
11	},
12	IsXsdStringIri, RdfDisplay, XSD_STRING,
13};
14
15/// RDF literal type.
16#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub enum LiteralType<I = IriBuf> {
19	/// Any type.
20	Any(I),
21
22	/// Language string.
23	LangString(LangTagBuf),
24}
25
26impl<I> LiteralType<I> {
27	pub fn is_lang_string(&self) -> bool {
28		matches!(self, Self::LangString(_))
29	}
30
31	pub fn lang_tag(&self) -> Option<&LangTag> {
32		match self {
33			Self::LangString(tag) => Some(tag),
34			_ => None,
35		}
36	}
37
38	pub fn is_xsd_string_with(&self, vocabulary: &impl IriVocabulary<Iri = I>) -> bool {
39		match self {
40			Self::Any(i) => vocabulary.iri(i).is_some_and(|iri| iri == XSD_STRING),
41			Self::LangString(_) => false,
42		}
43	}
44
45	pub fn is_xsd_string(&self) -> bool
46	where
47		I: IsXsdStringIri,
48	{
49		match self {
50			Self::Any(iri) => iri.is_xsd_string_iri(),
51			Self::LangString(_) => false,
52		}
53	}
54
55	pub fn is_iri(&self, iri: &I) -> bool
56	where
57		I: PartialEq,
58	{
59		match self {
60			Self::Any(i) => i == iri,
61			Self::LangString(_) => false,
62		}
63	}
64
65	pub fn as_ref(&self) -> LiteralTypeRef<I> {
66		match self {
67			Self::Any(i) => LiteralTypeRef::Any(i),
68			Self::LangString(l) => LiteralTypeRef::LangString(l),
69		}
70	}
71
72	pub fn as_lexical_type_ref_with<'a>(
73		&'a self,
74		vocabulary: &'a impl IriVocabulary<Iri = I>,
75	) -> LexicalLiteralTypeRef<'a> {
76		match self {
77			Self::Any(i) => LexicalLiteralTypeRef::Any(vocabulary.iri(i).unwrap()),
78			Self::LangString(l) => LexicalLiteralTypeRef::LangString(l),
79		}
80	}
81}
82
83impl LiteralType {
84	pub fn as_lexical_type_ref(&self) -> LexicalLiteralTypeRef {
85		match self {
86			Self::Any(i) => LexicalLiteralTypeRef::Any(i),
87			Self::LangString(l) => LexicalLiteralTypeRef::LangString(l),
88		}
89	}
90}
91
92impl<'a, I: PartialEq> PartialEq<LiteralTypeRef<'a, I>> for LiteralType<I> {
93	fn eq(&self, other: &LiteralTypeRef<'a, I>) -> bool {
94		match (self, *other) {
95			(Self::Any(a), LiteralTypeRef::Any(b)) => a == b,
96			(Self::LangString(a), LiteralTypeRef::LangString(b)) => a == b,
97			_ => false,
98		}
99	}
100}
101
102impl<V, I: EmbedIntoVocabulary<V>> EmbedIntoVocabulary<V> for LiteralType<I> {
103	type Embedded = LiteralType<I::Embedded>;
104
105	fn embed_into_vocabulary(self, vocabulary: &mut V) -> Self::Embedded {
106		match self {
107			Self::Any(i) => LiteralType::Any(i.embed_into_vocabulary(vocabulary)),
108			Self::LangString(l) => LiteralType::LangString(l),
109		}
110	}
111}
112
113impl<V, I: EmbeddedIntoVocabulary<V>> EmbeddedIntoVocabulary<V> for LiteralType<I> {
114	type Embedded = LiteralType<I::Embedded>;
115
116	fn embedded_into_vocabulary(&self, vocabulary: &mut V) -> Self::Embedded {
117		match self {
118			Self::Any(i) => LiteralType::Any(i.embedded_into_vocabulary(vocabulary)),
119			Self::LangString(l) => LiteralType::LangString(l.clone()),
120		}
121	}
122}
123
124impl<V: IriVocabulary> ExtractFromVocabulary<V> for LiteralType<V::Iri> {
125	type Extracted = LiteralType;
126
127	fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted {
128		match self {
129			Self::Any(t) => LiteralType::Any(vocabulary.owned_iri(t).ok().unwrap()),
130			Self::LangString(t) => LiteralType::LangString(t),
131		}
132	}
133}
134
135impl<V: IriVocabulary> ExtractedFromVocabulary<V> for LiteralType<V::Iri> {
136	type Extracted = LiteralType;
137
138	fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted {
139		match self {
140			Self::Any(t) => LiteralType::Any(vocabulary.iri(t).unwrap().to_owned()),
141			Self::LangString(t) => LiteralType::LangString(t.clone()),
142		}
143	}
144}
145
146impl<I: RdfDisplay> RdfDisplay for LiteralType<I> {
147	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148		match self {
149			Self::Any(ty) => {
150				write!(f, "^^")?;
151				ty.rdf_fmt(f)
152			}
153			Self::LangString(tag) => {
154				write!(f, "@")?;
155				tag.rdf_fmt(f)
156			}
157		}
158	}
159}
160
161#[cfg(feature = "contextual")]
162impl<T: crate::RdfDisplayWithContext<V>, V> crate::RdfDisplayWithContext<V> for LiteralType<T> {
163	fn rdf_fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
164		match self {
165			Self::Any(ty) => {
166				write!(f, "^^")?;
167				ty.rdf_fmt_with(vocabulary, f)
168			}
169			Self::LangString(tag) => {
170				write!(f, "@")?;
171				tag.rdf_fmt_with(vocabulary, f)
172			}
173		}
174	}
175}
176
177/// RDF literal type reference.
178#[derive(Educe, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
179#[educe(Clone, Copy)]
180#[cfg_attr(feature = "serde", derive(serde::Serialize))]
181pub enum LiteralTypeRef<'a, I = IriBuf> {
182	/// Any type.
183	Any(&'a I),
184
185	/// Language string.
186	LangString(&'a LangTag),
187}
188
189impl<'a, I> LiteralTypeRef<'a, I> {
190	pub fn is_lang_string(&self) -> bool {
191		matches!(self, Self::LangString(_))
192	}
193
194	pub fn lang_tag(&self) -> Option<&'a LangTag> {
195		match self {
196			Self::LangString(tag) => Some(tag),
197			_ => None,
198		}
199	}
200
201	pub fn is_xsd_string_with(&self, vocabulary: &impl IriVocabulary<Iri = I>) -> bool {
202		match self {
203			Self::Any(i) => vocabulary.iri(i).is_some_and(|iri| iri == XSD_STRING),
204			Self::LangString(_) => false,
205		}
206	}
207
208	pub fn is_xsd_string(&self) -> bool
209	where
210		I: IsXsdStringIri,
211	{
212		match self {
213			Self::Any(iri) => iri.is_xsd_string_iri(),
214			Self::LangString(_) => false,
215		}
216	}
217
218	pub fn is_iri(&self, iri: &I) -> bool
219	where
220		I: PartialEq,
221	{
222		match self {
223			Self::Any(i) => *i == iri,
224			Self::LangString(_) => false,
225		}
226	}
227
228	pub fn as_lexical_type_ref_with(
229		&self,
230		vocabulary: &'a impl IriVocabulary<Iri = I>,
231	) -> LexicalLiteralTypeRef<'a> {
232		match self {
233			Self::Any(i) => LexicalLiteralTypeRef::Any(vocabulary.iri(i).unwrap()),
234			Self::LangString(l) => LexicalLiteralTypeRef::LangString(l),
235		}
236	}
237}
238
239impl<I: ToOwned> LiteralTypeRef<'_, I> {
240	pub fn into_owned(self) -> LiteralType<I::Owned> {
241		match self {
242			Self::Any(i) => LiteralType::Any(i.to_owned()),
243			Self::LangString(l) => LiteralType::LangString(l.to_owned()),
244		}
245	}
246}
247
248impl<'a, I> LiteralTypeRef<'a, I> {
249	pub fn cast_into_owned<J>(self) -> LiteralType<J>
250	where
251		&'a I: Into<J>,
252	{
253		match self {
254			Self::Any(i) => LiteralType::Any(i.into()),
255			Self::LangString(l) => LiteralType::LangString(l.to_owned()),
256		}
257	}
258}
259
260impl LiteralTypeRef<'_> {
261	pub fn as_lexical_type_ref(&self) -> LexicalLiteralTypeRef {
262		match self {
263			Self::Any(i) => LexicalLiteralTypeRef::Any(i),
264			Self::LangString(l) => LexicalLiteralTypeRef::LangString(l),
265		}
266	}
267}
268
269impl<I: PartialEq> PartialEq<LiteralType<I>> for LiteralTypeRef<'_, I> {
270	fn eq(&self, other: &LiteralType<I>) -> bool {
271		match (*self, other) {
272			(Self::Any(a), LiteralType::Any(b)) => a == b,
273			(Self::LangString(a), LiteralType::LangString(b)) => a == b.as_lang_tag(),
274			_ => false,
275		}
276	}
277}
278
279impl<V, I: EmbeddedIntoVocabulary<V>> EmbedIntoVocabulary<V> for LiteralTypeRef<'_, I> {
280	type Embedded = LiteralType<I::Embedded>;
281
282	fn embed_into_vocabulary(self, vocabulary: &mut V) -> Self::Embedded {
283		match self {
284			Self::Any(i) => LiteralType::Any(i.embedded_into_vocabulary(vocabulary)),
285			Self::LangString(l) => LiteralType::LangString(l.to_owned()),
286		}
287	}
288}
289
290impl<V, I: EmbeddedIntoVocabulary<V>> EmbeddedIntoVocabulary<V> for LiteralTypeRef<'_, I> {
291	type Embedded = LiteralType<I::Embedded>;
292
293	fn embedded_into_vocabulary(&self, vocabulary: &mut V) -> Self::Embedded {
294		match *self {
295			Self::Any(i) => LiteralType::Any(i.embedded_into_vocabulary(vocabulary)),
296			Self::LangString(l) => LiteralType::LangString(l.to_owned()),
297		}
298	}
299}
300
301impl<V: IriVocabulary> ExtractFromVocabulary<V> for LiteralTypeRef<'_, V::Iri> {
302	type Extracted = LiteralType;
303
304	fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted {
305		match self {
306			Self::Any(t) => LiteralType::Any(vocabulary.iri(t).unwrap().to_owned()),
307			Self::LangString(t) => LiteralType::LangString(t.to_owned()),
308		}
309	}
310}
311
312impl<V: IriVocabulary> ExtractedFromVocabulary<V> for LiteralTypeRef<'_, V::Iri> {
313	type Extracted = LiteralType;
314
315	fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted {
316		match *self {
317			Self::Any(t) => LiteralType::Any(vocabulary.iri(t).unwrap().to_owned()),
318			Self::LangString(t) => LiteralType::LangString(t.to_owned()),
319		}
320	}
321}
322
323impl<I: RdfDisplay> RdfDisplay for LiteralTypeRef<'_, I> {
324	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
325		match self {
326			Self::Any(ty) => {
327				write!(f, "^^")?;
328				ty.rdf_fmt(f)
329			}
330			Self::LangString(tag) => {
331				write!(f, "@")?;
332				tag.rdf_fmt(f)
333			}
334		}
335	}
336}
337
338#[cfg(feature = "contextual")]
339impl<'a, T: crate::RdfDisplayWithContext<V>, V> crate::RdfDisplayWithContext<V>
340	for LiteralTypeRef<'a, T>
341{
342	fn rdf_fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
343		match self {
344			Self::Any(ty) => {
345				write!(f, "^^")?;
346				ty.rdf_fmt_with(vocabulary, f)
347			}
348			Self::LangString(tag) => {
349				write!(f, "@")?;
350				tag.rdf_fmt_with(vocabulary, f)
351			}
352		}
353	}
354}
355
356/// Literal type IRI.
357///
358/// This trait is used to correctly format literal type IRIs, which can be
359/// omitted when it is [`XSD_STRING`].
360pub trait RdfTypeIri {
361	/// Checks if the type IRI is [`XSD_STRING`].
362	fn is_xsd_string(&self) -> bool;
363}
364
365impl RdfTypeIri for IriBuf {
366	fn is_xsd_string(&self) -> bool {
367		self == XSD_STRING
368	}
369}
370
371impl RdfTypeIri for Iri {
372	fn is_xsd_string(&self) -> bool {
373		self == XSD_STRING
374	}
375}
376
377impl<T: RdfTypeIri> RdfTypeIri for &T {
378	fn is_xsd_string(&self) -> bool {
379		T::is_xsd_string(self)
380	}
381}
382
383/// Literal type IRI.
384///
385/// This trait is used to correctly format literal type IRIs, which can be
386/// omitted when it is [`XSD_STRING`].
387pub trait RdfTypeIriWithContext<C> {
388	/// Checks if the type IRI is [`XSD_STRING`] using the given context.
389	fn is_xsd_string_with(&self, context: &C) -> bool;
390}
391
392impl<C> RdfTypeIriWithContext<C> for IriBuf {
393	fn is_xsd_string_with(&self, _context: &C) -> bool {
394		self == XSD_STRING
395	}
396}
397
398impl<C> RdfTypeIriWithContext<C> for Iri {
399	fn is_xsd_string_with(&self, _context: &C) -> bool {
400		self == XSD_STRING
401	}
402}
403
404impl<C, T: RdfTypeIriWithContext<C>> RdfTypeIriWithContext<C> for &T {
405	fn is_xsd_string_with(&self, context: &C) -> bool {
406		T::is_xsd_string_with(self, context)
407	}
408}
409
410/// RDF literal type.
411#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
412#[cfg_attr(feature = "serde", derive(serde::Serialize))]
413pub enum LexicalLiteralTypeRef<'a> {
414	/// Any type.
415	Any(&'a Iri),
416
417	/// Language string.
418	LangString(&'a LangTag),
419}
420
421impl LexicalLiteralTypeRef<'_> {
422	pub fn is_iri(&self, iri: &Iri) -> bool {
423		match self {
424			Self::Any(i) => *i == iri,
425			Self::LangString(_) => false,
426		}
427	}
428}