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#[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(I),
21
22 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#[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(&'a I),
184
185 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
356pub trait RdfTypeIri {
361 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
383pub trait RdfTypeIriWithContext<C> {
388 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#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
412#[cfg_attr(feature = "serde", derive(serde::Serialize))]
413pub enum LexicalLiteralTypeRef<'a> {
414 Any(&'a Iri),
416
417 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}