rudof_rdf/rdf_core/term/literal/literal.rs
1use crate::rdf_core::{
2 RDFError,
3 term::literal::{Lang, NumericLiteral, XsdDateTime},
4};
5use rust_decimal::Decimal;
6use std::{
7 fmt::{self, Debug, Display},
8 hash::Hash,
9 result,
10};
11
12use crate::rdf_core::vocabs::{RdfVocab, XsdVocab};
13use iri_s::IriS;
14use prefixmap::{DerefError, DerefIri, IriRef, PrefixMap};
15use serde::{Deserialize, Serialize, Serializer};
16
17/// Types that implement this trait can be used as RDF Literals.
18///
19/// This trait provides methods for accessing literal properties and converting
20/// literals to specific Rust types based on their XSD datatype.
21pub trait Literal: Debug + Clone + Display + PartialEq + Eq + Hash {
22 /// Returns the lexical form of the literal as a string slice.
23 fn lexical_form(&self) -> &str;
24
25 /// Returns the language tag if this is a language-tagged literal.
26 fn lang(&self) -> Option<Lang>;
27
28 /// Returns the datatype IRI of this literal.
29 fn datatype(&self) -> IriRef;
30
31 /// Converts this literal to an `ConcreteLiteral` if possible.
32 fn to_concrete_literal(&self) -> Option<ConcreteLiteral>;
33
34 /// Attempts to convert this literal to a boolean value.
35 ///
36 /// Returns `Some(bool)` if the literal has datatype `xsd:boolean` and
37 /// a valid lexical form ("true" or "false").
38 fn to_bool(&self) -> Option<bool> {
39 let datatype = self.datatype();
40 let iri = datatype.get_iri().ok()?;
41
42 if iri.as_str() != "http://www.w3.org/2001/XMLSchema#boolean" {
43 return None;
44 }
45
46 match self.lexical_form() {
47 "true" => Some(true),
48 "false" => Some(false),
49 _ => None,
50 }
51 }
52
53 /// Attempts to convert this literal to an integer value.
54 ///
55 /// Returns `Some(isize)` if the literal has datatype `xsd:integer` and
56 /// a valid parseable lexical form.
57 fn to_integer(&self) -> Option<isize> {
58 let datatype = self.datatype();
59 let iri = datatype.get_iri().ok()?;
60
61 if iri.as_str() != "http://www.w3.org/2001/XMLSchema#integer" {
62 return None;
63 }
64
65 self.lexical_form().parse().ok()
66 }
67
68 /// Attempts to convert this literal to a datetime value.
69 ///
70 /// Returns `Some(XsdDateTime)` if the literal has datatype `xsd:dateTime` and
71 /// a valid parseable lexical form.
72 fn to_date_time(&self) -> Option<XsdDateTime> {
73 let datatype = self.datatype();
74 let iri = datatype.get_iri().ok()?;
75
76 if iri.as_str() != "http://www.w3.org/2001/XMLSchema#dateTime" {
77 return None;
78 }
79
80 XsdDateTime::new(self.lexical_form()).ok()
81 }
82
83 /// Attempts to convert this literal to a double-precision float value.
84 ///
85 /// Returns `Some(f64)` if the literal has datatype `xsd:double` and
86 /// a valid parseable lexical form.
87 fn to_double(&self) -> Option<f64> {
88 let datatype = self.datatype();
89 let iri = datatype.get_iri().ok()?;
90
91 if iri.as_str() != "http://www.w3.org/2001/XMLSchema#double" {
92 return None;
93 }
94
95 self.lexical_form().parse().ok()
96 }
97
98 /// Attempts to convert this literal to a decimal value.
99 ///
100 /// Returns `Some(Decimal)` if the literal has datatype `xsd:decimal` and
101 /// a valid parseable lexical form.
102 fn to_decimal(&self) -> Option<Decimal> {
103 let datatype = self.datatype();
104 let iri = datatype.get_iri().ok()?;
105
106 if iri.as_str() != "http://www.w3.org/2001/XMLSchema#decimal" {
107 return None;
108 }
109
110 self.lexical_form().parse().ok()
111 }
112}
113
114/// Concrete representation of RDF literals with type-safe internal representations.
115///
116/// This enum provides a strongly-typed representation of RDF literals, using native
117/// Rust types (integers, floats, booleans, etc.) internally for efficiency. It also
118/// supports literals with incorrect datatypes to enable parsing and validation of
119/// potentially malformed RDF data.
120///
121/// # Type Safety
122///
123/// The enum uses native Rust types internally, providing type safety and efficient
124/// operations on numeric values. For example, `NumericLiteral` stores actual numeric
125/// values rather than strings, enabling direct mathematical operations.
126///
127/// # Error Handling
128///
129/// The [`WrongDatatypeLiteral`](Self::WrongDatatypeLiteral) variant allows parsing
130/// and representing malformed RDF data (e.g., `"hello"^^xsd:integer`) without losing
131/// information. This enables validation workflows that need to report specific errors
132/// while continuing to process other data.
133///
134/// # Comparison and Ordering
135///
136/// Literals implement [`PartialOrd`] and [`Ord`] following SPARQL ordering rules:
137/// - String literals are compared lexicographically
138/// - Numeric literals are compared by numeric value
139/// - Boolean literals follow `false < true`
140/// - Datetime literals are compared chronologically
141///
142/// # Panics
143///
144/// The [`Ord`] implementation panics when comparing incomparable literals (e.g., NaN
145/// floating-point values or literals with different datatypes). Use [`PartialOrd`]
146/// when comparing arbitrary literals to avoid panics.
147#[derive(PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone)]
148#[allow(clippy::enum_variant_names)]
149pub enum ConcreteLiteral {
150 /// A plain string literal, optionally with a language tag.
151 StringLiteral {
152 lexical_form: String,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 lang: Option<Lang>,
155 },
156
157 /// A literal with an explicit datatype IRI.
158 DatatypeLiteral { lexical_form: String, datatype: IriRef },
159
160 /// A numeric literal (integer, float, decimal, etc.).
161 NumericLiteral(NumericLiteral),
162
163 /// An XSD datetime literal.
164 DatetimeLiteral(XsdDateTime),
165
166 /// A boolean literal (true or false).
167 #[serde(serialize_with = "serialize_boolean_literal")]
168 BooleanLiteral(bool),
169
170 /// Represents a literal with an invalid datatype.
171 ///
172 /// For example, a value like `"hello"^^xsd:integer` would be represented as a
173 /// `WrongDatatypeLiteral`. This is useful for parsing RDF data that may contain
174 /// malformed literals while still enabling validation.
175 WrongDatatypeLiteral {
176 lexical_form: String,
177 datatype: IriRef,
178 error: String,
179 },
180}
181
182/// ## Display and formatting
183impl ConcreteLiteral {
184 /// Returns a string representation using the given prefix map to qualify IRIs.
185 ///
186 /// This method formats the literal using shortened IRI prefixes from the provided
187 /// prefix map, making the output more readable.
188 ///
189 /// # Arguments
190 ///
191 /// * `prefixmap` - The prefix map used to shorten IRIs
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// use rudof_rdf::rdf_core::term::literal::ConcreteLiteral;
197 /// use prefixmap::PrefixMap;
198 ///
199 /// let lit = ConcreteLiteral::integer(42);
200 /// let prefixmap = PrefixMap::basic();
201 /// println!("{}", lit.show_qualified(&prefixmap));
202 /// ```
203 pub fn show_qualified(&self, prefixmap: &PrefixMap) -> String {
204 let mut s = String::new();
205 let _ = self.display_qualified(&mut s, prefixmap);
206 s
207 }
208
209 /// Formats this literal using the given prefix map and writes the result
210 /// into the provided formatter.
211 ///
212 /// The output follows RDF/Turtle-style literal syntax:
213 /// - String literals are quoted, with an optional language tag
214 /// - Numeric and boolean literals are written as-is
215 /// - Datatype literals are written using `^^` and qualified IRIs
216 /// - Datatypes are shortened using the provided prefix map when possible
217 ///
218 /// This method is intended for internal use by [`show_qualified`] and
219 /// `Display` implementations rather than being called directly.
220 ///
221 /// # Arguments
222 ///
223 /// * `f` - The output writer to which the literal representation is written
224 /// * `prefixmap` - The prefix map used to qualify datatype IRIs
225 ///
226 /// # Errors
227 ///
228 /// Returns any formatting error encountered while writing to the formatter.
229 pub fn display_qualified<W: fmt::Write>(&self, f: &mut W, prefixmap: &PrefixMap) -> fmt::Result {
230 match self {
231 Self::StringLiteral { lexical_form, lang } => {
232 write!(f, "\"{lexical_form}\"")?;
233 if let Some(lang) = lang {
234 write!(f, "{lang}")?;
235 }
236 Ok(())
237 },
238 Self::DatatypeLiteral { lexical_form, datatype } => {
239 self.format_datatype_literal(f, lexical_form, datatype, prefixmap)
240 },
241 Self::NumericLiteral(n) => write!(f, "{n}"),
242 Self::BooleanLiteral(b) => write!(f, "{b}"),
243 Self::DatetimeLiteral(dt) => write!(f, "{}", dt.value()),
244 Self::WrongDatatypeLiteral {
245 lexical_form, datatype, ..
246 } => self.format_datatype_literal(f, lexical_form, datatype, prefixmap),
247 }
248 }
249
250 /// Helper method to format datatype literals in a consistent way.
251 ///
252 /// This method writes a typed literal using RDF/Turtle syntax:
253 /// "lexical_form"^^datatype
254 ///
255 /// If the datatype IRI can be qualified using the provided prefix map,
256 /// the shortened prefixed form is used (e.g. `xsd:string`). Otherwise,
257 /// the full IRI is written.
258 ///
259 /// # Arguments
260 ///
261 /// * `f` - The output writer to which the literal representation is written
262 /// * `lexical_form` - The lexical form of the literal
263 /// * `datatype` - The datatype IRI or prefixed name
264 /// * `prefixmap` - The prefix map used to qualify IRIs
265 ///
266 /// # Errors
267 ///
268 /// Returns any formatting error encountered while writing to the formatter.
269 fn format_datatype_literal<W: fmt::Write>(
270 &self,
271 f: &mut W,
272 lexical_form: &str,
273 datatype: &IriRef,
274 prefixmap: &PrefixMap,
275 ) -> fmt::Result {
276 match datatype {
277 IriRef::Iri(iri) => {
278 write!(f, "\"{lexical_form}\"^^{}", prefixmap.qualify(iri))
279 },
280 IriRef::Prefixed { prefix, local } => {
281 write!(f, "\"{lexical_form}\"^^{prefix}:{local}")
282 },
283 }
284 }
285}
286
287/// ## Validation and Conversion
288impl ConcreteLiteral {
289 /// Validates that the lexical form matches the declared datatype,
290 /// consuming the literal and returning a validated version.
291 ///
292 /// This method checks whether the lexical form of a datatype literal
293 /// is compatible with its declared datatype. If the validation succeeds,
294 /// a properly typed literal is returned. If the validation fails,
295 /// a `WrongDatatypeLiteral` is returned instead.
296 ///
297 /// For non-datatype literals, the value is returned unchanged.
298 ///
299 /// # Errors
300 ///
301 /// Returns an `LiteralError` if datatype validation fails.
302 ///
303 /// # Examples
304 ///
305 /// ```
306 /// use rudof_rdf::rdf_core::term::literal::ConcreteLiteral;
307 /// use iri_s::IriS;
308 /// use prefixmap::IriRef;
309 ///
310 /// // Create a datatype literal with an integer value
311 /// let dt_iri = IriRef::iri(IriS::new_unchecked("http://www.w3.org/2001/XMLSchema#integer"));
312 /// let lit = ConcreteLiteral::lit_datatype("42", &dt_iri);
313 ///
314 /// // Validate the literal
315 /// let checked = lit.into_checked_literal().unwrap();
316 /// ```
317 pub fn into_checked_literal(self) -> Result<Self, RDFError> {
318 if let Self::DatatypeLiteral { lexical_form, datatype } = self {
319 check_literal_datatype(lexical_form.as_ref(), &datatype)
320 } else {
321 Ok(self)
322 }
323 }
324
325 /// Compares this literal with another for equality.
326 ///
327 /// This method performs type-aware comparison, ensuring that literals of
328 /// different types are not considered equal even if their lexical forms match.
329 ///
330 /// # Arguments
331 ///
332 /// * `literal_expected` - The literal to compare against
333 ///
334 /// # Returns
335 ///
336 /// `true` if the literals are equal, `false` otherwise.
337 ///
338 /// # Examples
339 ///
340 /// ```
341 /// use rudof_rdf::rdf_core::term::literal::ConcreteLiteral;
342 /// use rudof_rdf::rdf_core::term::literal::Lang;
343 ///
344 /// let lit1 = ConcreteLiteral::str("hello");
345 /// let lit2 = ConcreteLiteral::str("hello");
346 /// let lit3 = ConcreteLiteral::lang_str("hello", Lang::new("en").unwrap());
347 /// let lit4 = ConcreteLiteral::integer(42);
348 ///
349 /// // Plain string literals with the same content are equal
350 /// assert!(lit1.match_literal(&lit2));
351 ///
352 /// // Language-tagged string literals must match both lexical form and lang
353 /// assert!(!lit1.match_literal(&lit3));
354 ///
355 /// // Numeric and string literals are not equal even if lexical forms match
356 /// let lit5 = ConcreteLiteral::lit_datatype("42", &lit4.datatype());
357 /// assert!(!lit5.match_literal(&lit4));
358 ///
359 /// // Comparing numeric literals of the same value returns true
360 /// let lit6 = ConcreteLiteral::integer(42);
361 /// assert!(lit4.match_literal(&lit6));
362 /// ```
363 pub fn match_literal(&self, literal_expected: &Self) -> bool {
364 match (self, literal_expected) {
365 (
366 Self::StringLiteral { lexical_form, lang },
367 Self::StringLiteral {
368 lexical_form: expected_lexical_form,
369 lang: expected_lang,
370 },
371 ) => lexical_form == expected_lexical_form && lang == expected_lang,
372 (
373 Self::DatatypeLiteral { lexical_form, datatype },
374 Self::DatatypeLiteral {
375 lexical_form: expected_lexical_form,
376 datatype: expected_datatype,
377 },
378 ) => lexical_form == expected_lexical_form && datatype == expected_datatype,
379 (Self::NumericLiteral(n1), Self::NumericLiteral(n2)) => n1 == n2,
380 (Self::DatetimeLiteral(dt1), Self::DatetimeLiteral(dt2)) => dt1 == dt2,
381 (Self::BooleanLiteral(b1), Self::BooleanLiteral(b2)) => b1 == b2,
382 (
383 Self::WrongDatatypeLiteral {
384 lexical_form, datatype, ..
385 },
386 Self::WrongDatatypeLiteral {
387 lexical_form: expected_lexical_form,
388 datatype: expected_datatype,
389 ..
390 },
391 ) => lexical_form == expected_lexical_form && datatype == expected_datatype,
392 _ => false,
393 }
394 }
395}
396
397/// ## Constructor Methods - Numeric Types
398impl ConcreteLiteral {
399 /// Creates a literal representing an unbounded integer (`i128`).
400 ///
401 /// This corresponds to XSD's `xsd:integer` type, which is unbounded.
402 #[inline]
403 pub fn integer(n: i128) -> Self {
404 Self::NumericLiteral(NumericLiteral::integer(n))
405 }
406
407 /// Creates a literal representing a non-negative integer (`u128` ≥ 0).
408 ///
409 /// This corresponds to XSD's `xsd:nonNegativeInteger` type.
410 #[inline]
411 pub fn non_negative_integer(n: u128) -> Self {
412 Self::NumericLiteral(NumericLiteral::non_negative_integer(n))
413 }
414
415 /// Creates a literal representing a non-positive integer (`i128` ≤ 0).
416 ///
417 /// This corresponds to XSD's `xsd:nonPositiveInteger` type.
418 ///
419 /// # Errors
420 /// Returns `RDFError::NumericOutOfRange` if `n` is greater than 0.
421 #[inline]
422 pub fn non_positive_integer(n: i128) -> Result<Self, RDFError> {
423 Ok(Self::NumericLiteral(NumericLiteral::non_positive_integer(n)?))
424 }
425
426 /// Creates a literal representing a strictly positive integer (`u128` > 0).
427 ///
428 /// This corresponds to XSD's `xsd:positiveInteger` type.
429 ///
430 /// # Errors
431 /// Returns `RDFError::NumericOutOfRange` if `n` is 0.
432 #[inline]
433 pub fn positive_integer(n: u128) -> Result<Self, RDFError> {
434 Ok(Self::NumericLiteral(NumericLiteral::positive_integer(n)?))
435 }
436
437 /// Creates a literal representing a strictly negative integer (`i128` < 0).
438 ///
439 /// This corresponds to XSD's `xsd:negativeInteger` type.
440 ///
441 /// # Errors
442 /// Returns `RDFError::NumericOutOfRange` if `n` is greater than or equal to 0.
443 #[inline]
444 pub fn negative_integer(n: i128) -> Result<Self, RDFError> {
445 Ok(Self::NumericLiteral(NumericLiteral::negative_integer(n)?))
446 }
447
448 /// Creates a literal representing a double-precision floating-point number (`f64`).
449 ///
450 /// This corresponds to XSD's `xsd:double` type (64-bit IEEE 754).
451 #[inline]
452 pub fn double(d: f64) -> Self {
453 Self::NumericLiteral(NumericLiteral::double(d))
454 }
455
456 /// Creates a literal representing a decimal number (`Decimal` type for precise arithmetic).
457 ///
458 /// This corresponds to XSD's `xsd:decimal` type for exact decimal arithmetic.
459 #[inline]
460 pub fn decimal(d: Decimal) -> Self {
461 Self::NumericLiteral(NumericLiteral::decimal(d))
462 }
463
464 /// Creates a literal representing a 64-bit signed long integer (`i64`).
465 ///
466 /// This corresponds to XSD's `xsd:long` type (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807).
467 #[inline]
468 pub fn long(n: i64) -> Self {
469 Self::NumericLiteral(NumericLiteral::long(n))
470 }
471
472 /// Creates a literal representing a signed byte (`i8`), values -128 to 127.
473 ///
474 /// This corresponds to XSD's `xsd:byte` type.
475 #[inline]
476 pub fn byte(n: i8) -> Self {
477 Self::NumericLiteral(NumericLiteral::byte(n))
478 }
479
480 /// Creates a literal representing a signed short (`i16`), values -32,768 to 32,767.
481 ///
482 /// This corresponds to XSD's `xsd:short` type.
483 #[inline]
484 pub fn short(n: i16) -> Self {
485 Self::NumericLiteral(NumericLiteral::short(n))
486 }
487
488 /// Creates a literal representing an unsigned byte (`u8`), values 0–255.
489 ///
490 /// This corresponds to XSD's `xsd:unsignedByte` type.
491 #[inline]
492 pub fn unsigned_byte(n: u8) -> Self {
493 Self::NumericLiteral(NumericLiteral::unsigned_byte(n))
494 }
495
496 /// Creates a literal representing an unsigned short (`u16`), values 0–65,535.
497 ///
498 /// This corresponds to XSD's `xsd:unsignedShort` type.
499 #[inline]
500 pub fn unsigned_short(n: u16) -> Self {
501 Self::NumericLiteral(NumericLiteral::unsigned_short(n))
502 }
503
504 /// Creates a literal representing an unsigned integer (`u32`).
505 ///
506 /// This corresponds to XSD's `xsd:unsignedInt` type.
507 #[inline]
508 pub fn unsigned_int(n: u32) -> Self {
509 Self::NumericLiteral(NumericLiteral::unsigned_int(n))
510 }
511
512 /// Creates a literal representing an unsigned long integer (`u64`).
513 ///
514 /// This corresponds to XSD's `xsd:unsignedLong` type.
515 #[inline]
516 pub fn unsigned_long(n: u64) -> Self {
517 Self::NumericLiteral(NumericLiteral::unsigned_long(n))
518 }
519
520 /// Creates a literal representing a single-precision floating-point number (`f32`).
521 ///
522 /// This corresponds to XSD's `xsd:float` type (32-bit IEEE 754).
523 #[inline]
524 pub fn float(n: f32) -> Self {
525 Self::NumericLiteral(NumericLiteral::float(n))
526 }
527
528 /// Creates a DatetimeLiteral
529 pub fn datetime(dt: XsdDateTime) -> Self {
530 Self::DatetimeLiteral(dt)
531 }
532}
533
534/// ## Constructor Methods - Other Types
535impl ConcreteLiteral {
536 /// Creates a literal with a custom datatype.
537 ///
538 /// # Parameters
539 /// - `lexical_form`: The string representation of the literal's value.
540 /// - `datatype`: The IRI that identifies the literal's datatype.
541 pub fn lit_datatype(lexical_form: &str, datatype: &IriRef) -> Self {
542 Self::DatatypeLiteral {
543 lexical_form: lexical_form.to_owned(),
544 datatype: datatype.clone(),
545 }
546 }
547
548 /// Creates a boolean literal (`true` or `false`).
549 #[inline]
550 pub fn boolean(b: bool) -> Self {
551 Self::BooleanLiteral(b)
552 }
553
554 /// Creates a plain string literal without a language tag.
555 ///
556 /// # Parameters
557 /// - `lexical_form`: The text content of the literal.
558 pub fn str(lexical_form: &str) -> Self {
559 Self::StringLiteral {
560 lexical_form: lexical_form.to_owned(),
561 lang: None,
562 }
563 }
564
565 /// Creates a string literal with a language tag.
566 ///
567 /// # Parameters
568 /// - `lexical_form`: The text content of the literal.
569 /// - `lang`: The language of the literal, e.g., `"en"` for English.
570 pub fn lang_str(lexical_form: &str, lang: Lang) -> Self {
571 Self::StringLiteral {
572 lexical_form: lexical_form.to_owned(),
573 lang: Some(lang),
574 }
575 }
576}
577
578/// ## Accessor Methods
579impl ConcreteLiteral {
580 /// Returns the language tag of the literal, if it is a language-tagged string.
581 pub fn lang(&self) -> Option<Lang> {
582 match self {
583 Self::StringLiteral { lang, .. } => lang.clone(),
584 _ => None,
585 }
586 }
587
588 /// Returns the lexical form (string representation) of the literal.
589 ///
590 /// # Returns
591 /// A `String` representing the literal's value:
592 /// - For string or datatype literals, returns the literal text.
593 /// - For numeric literals, returns the numeric value as a string.
594 /// - For boolean literals, returns `"true"` or `"false"`.
595 /// - For datetime literals, returns a standard string representation.
596 ///
597 pub fn lexical_form(&self) -> String {
598 match self {
599 Self::StringLiteral { lexical_form, .. }
600 | Self::DatatypeLiteral { lexical_form, .. }
601 | Self::WrongDatatypeLiteral { lexical_form, .. } => lexical_form.clone(),
602 Self::NumericLiteral(nl) => nl.lexical_form(),
603 Self::BooleanLiteral(b) => b.to_string(),
604 Self::DatetimeLiteral(dt) => dt.to_string(),
605 }
606 }
607
608 /// Returns the datatype IRI of the literal.
609 ///
610 /// # Returns
611 /// - For explicitly typed literals (`DatatypeLiteral` or `WrongDatatypeLiteral`), returns the stored datatype IRI.
612 /// - For plain string literals without a language tag, returns `xsd:string`.
613 /// - For language-tagged string literals, returns `rdf:langString`.
614 /// - For numeric literals, returns the appropriate XML Schema datatype (e.g., `xsd:integer`, `xsd:double`).
615 /// - For boolean literals, returns `xsd:boolean`.
616 /// - For datetime literals, returns `xsd:dateTime`.
617 pub fn datatype(&self) -> IriRef {
618 match self {
619 Self::DatatypeLiteral { datatype, .. } | Self::WrongDatatypeLiteral { datatype, .. } => datatype.clone(),
620
621 Self::StringLiteral { lang: None, .. } => IriRef::iri(IriS::new_unchecked(XsdVocab::XSD_STRING)),
622
623 Self::StringLiteral { lang: Some(_), .. } => IriRef::iri(IriS::new_unchecked(RdfVocab::RDF_LANG_STRING)),
624
625 Self::NumericLiteral(nl) => IriRef::iri(IriS::new_unchecked(nl.datatype())),
626
627 Self::BooleanLiteral(_) => IriRef::iri(IriS::new_unchecked(XsdVocab::XSD_BOOLEAN)),
628 Self::DatetimeLiteral(_) => IriRef::iri(IriS::new_unchecked(XsdVocab::XSD_DATE_TIME)),
629 }
630 }
631
632 /// Returns the numeric literal value, if this literal is numeric.
633 pub fn numeric_value(&self) -> Option<NumericLiteral> {
634 match self {
635 Self::NumericLiteral(nl) => Some(nl.clone()),
636 _ => None,
637 }
638 }
639}
640
641/// ## Parsing Methods
642impl ConcreteLiteral {
643 /// Parses a boolean from its XSD lexical representation.
644 ///
645 /// Valid values are: "true", "false", "1" (true), "0" (false).
646 /// Parsing is case-sensitive.
647 ///
648 /// # Errors
649 ///
650 /// Returns an error if the input string is not a valid boolean representation.
651 ///
652 /// # Examples
653 ///
654 /// ```
655 /// use rudof_rdf::rdf_core::term::literal::ConcreteLiteral;
656 /// assert_eq!(ConcreteLiteral::parse_bool("true").unwrap(), true);
657 /// assert_eq!(ConcreteLiteral::parse_bool("0").unwrap(), false);
658 /// assert!(ConcreteLiteral::parse_bool("yes").is_err());
659 /// ```
660 pub fn parse_bool(s: &str) -> Result<bool, String> {
661 match s {
662 "true" | "1" => Ok(true),
663 "false" | "0" => Ok(false),
664 _ => Err(format!("Cannot convert {s} to boolean")),
665 }
666 }
667
668 /// Parses an integer from its string representation.
669 ///
670 /// XSD integer is unbounded, so this returns `i128`.
671 ///
672 /// # Errors
673 ///
674 /// Returns an error if the string cannot be parsed as an integer.
675 ///
676 /// # Examples
677 ///
678 /// ```
679 /// use rudof_rdf::rdf_core::term::literal::ConcreteLiteral;
680 /// assert_eq!(ConcreteLiteral::parse_integer("-7").unwrap(), -7);
681 /// assert_eq!(ConcreteLiteral::parse_integer("2").unwrap(), 2);
682 /// assert!(ConcreteLiteral::parse_integer("x").is_err());
683 /// ```
684 pub fn parse_integer(s: &str) -> Result<i128, String> {
685 s.parse::<i128>()
686 .map_err(|e| format!("Cannot convert {s} to integer: {e}"))
687 }
688
689 /// Parses a negative integer from its string representation.
690 ///
691 /// # Errors
692 ///
693 /// Returns an error if the value is not negative or cannot be parsed.
694 ///
695 /// # Examples
696 ///
697 /// ```
698 /// use rudof_rdf::rdf_core::term::literal::ConcreteLiteral;
699 /// assert_eq!(ConcreteLiteral::parse_negative_integer("-3").unwrap(), -3);
700 /// assert!(ConcreteLiteral::parse_negative_integer("0").is_err());
701 /// ```
702 pub fn parse_negative_integer(s: &str) -> Result<i128, String> {
703 let value = s
704 .parse::<i128>()
705 .map_err(|e| format!("Cannot convert {s} to negative integer: {e}"))?;
706
707 if value < 0 {
708 Ok(value)
709 } else {
710 Err(format!("Cannot convert {s} to negative integer: value is not negative"))
711 }
712 }
713
714 /// Parses a non-positive integer from its string representation.
715 ///
716 /// # Errors
717 ///
718 /// Returns an error if the value is positive or cannot be parsed.
719 pub fn parse_non_positive_integer(s: &str) -> Result<i128, String> {
720 let value = s
721 .parse::<i128>()
722 .map_err(|e| format!("Cannot convert {s} to non-positive integer: {e}"))?;
723
724 if value <= 0 {
725 Ok(value)
726 } else {
727 Err(format!("Cannot convert {s} to non-positive integer: value is positive"))
728 }
729 }
730
731 /// Parses a positive integer from its string representation.
732 ///
733 /// # Errors
734 ///
735 /// Returns an error if the value is not positive or cannot be parsed.
736 pub fn parse_positive_integer(s: &str) -> Result<u128, String> {
737 let value = s
738 .parse::<u128>()
739 .map_err(|e| format!("Cannot convert {s} to positive integer: {e}"))?;
740
741 if value > 0 {
742 Ok(value)
743 } else {
744 Err(format!("Cannot convert {s} to positive integer: value is not positive"))
745 }
746 }
747
748 /// Parses a non-negative integer from its string representation.
749 ///
750 /// # Errors
751 ///
752 /// Returns an error if the string cannot be parsed as a non-negative integer.
753 pub fn parse_non_negative_integer(s: &str) -> Result<u128, String> {
754 s.parse::<u128>()
755 .map_err(|e| format!("Cannot convert {s} to non-negative integer: {e}"))
756 }
757
758 /// Parses an unsigned byte (0–255) from its string representation.
759 ///
760 /// # Errors
761 ///
762 /// Returns an error if the string cannot be parsed as a `u8`.
763 pub fn parse_unsigned_byte(s: &str) -> Result<u8, String> {
764 s.parse::<u8>()
765 .map_err(|e| format!("Cannot convert {s} to unsignedByte: {e}"))
766 }
767
768 /// Parses an unsigned short (0–65535) from its string representation.
769 ///
770 /// # Errors
771 ///
772 /// Returns an error if the string cannot be parsed as a `u16`.
773 pub fn parse_unsigned_short(s: &str) -> Result<u16, String> {
774 s.parse::<u16>()
775 .map_err(|e| format!("Cannot convert {s} to unsignedShort: {e}"))
776 }
777
778 /// Parses an unsigned integer from its string representation.
779 ///
780 /// # Errors
781 ///
782 /// Returns an error if the string cannot be parsed as a `u32`.
783 pub fn parse_unsigned_int(s: &str) -> Result<u32, String> {
784 s.parse::<u32>()
785 .map_err(|e| format!("Cannot convert {s} to unsignedInt: {e}"))
786 }
787
788 /// Parses an unsigned long (0–u64::MAX) from its string representation.
789 ///
790 /// # Errors
791 ///
792 /// Returns an error if the string cannot be parsed as a `u64`.
793 pub fn parse_unsigned_long(s: &str) -> Result<u64, String> {
794 s.parse::<u64>()
795 .map_err(|e| format!("Cannot convert {s} to unsignedLong: {e}"))
796 }
797
798 /// Parses a double (64-bit float) from its string representation.
799 ///
800 /// # Errors
801 ///
802 /// Returns an error if the string cannot be parsed as a `f64`.
803 pub fn parse_double(s: &str) -> Result<f64, String> {
804 s.parse::<f64>()
805 .map_err(|e| format!("Cannot convert {s} to double: {e}"))
806 }
807
808 /// Parses a long integer (64-bit signed) from its string representation.
809 ///
810 /// # Errors
811 ///
812 /// Returns an error if the string cannot be parsed as an `i64`.
813 pub fn parse_long(s: &str) -> Result<i64, String> {
814 s.parse::<i64>().map_err(|e| format!("Cannot convert {s} to long: {e}"))
815 }
816
817 /// Parses a decimal from its string representation using `rust_decimal::Decimal`.
818 ///
819 /// # Errors
820 ///
821 /// Returns an error if the string cannot be parsed as a `Decimal`.
822 pub fn parse_decimal(s: &str) -> Result<Decimal, String> {
823 s.parse::<Decimal>()
824 .map_err(|e| format!("Cannot convert {s} to decimal: {e}"))
825 }
826
827 /// Parses a float (32-bit) from its string representation.
828 ///
829 /// # Errors
830 ///
831 /// Returns an error if the string cannot be parsed as a float.
832 pub fn parse_float(s: &str) -> Result<f32, String> {
833 s.parse::<f32>()
834 .map_err(|e| format!("Cannot convert {s} to float: {e}"))
835 }
836
837 /// Parses a signed byte (-128 to 127) from its string representation.
838 ///
839 /// # Errors
840 ///
841 /// Returns an error if the string cannot be parsed as an `i8`.
842 pub fn parse_byte(s: &str) -> Result<i8, String> {
843 s.parse::<i8>().map_err(|e| format!("Cannot convert {s} to byte: {e}"))
844 }
845
846 /// Parses a signed short (-32768 to 32767) from its string representation.
847 ///
848 /// # Errors
849 ///
850 /// Returns an error if the string cannot be parsed as an `i16`.
851 pub fn parse_short(s: &str) -> Result<i16, String> {
852 s.parse::<i16>()
853 .map_err(|e| format!("Cannot convert {s} to short: {e}"))
854 }
855
856 /// Parses a datetime string using XsdDateTime
857 pub fn parse_datetime(s: &str) -> Result<XsdDateTime, String> {
858 XsdDateTime::new(s).map_err(|e| e.to_string())
859 }
860}
861
862// ============================================================================
863// Trait Implementations
864// ============================================================================
865
866impl Default for ConcreteLiteral {
867 /// Returns an empty string literal without a language tag.
868 ///
869 /// This is used as a neutral default value when a literal is required
870 /// but no concrete value is available.
871 fn default() -> Self {
872 Self::StringLiteral {
873 lexical_form: String::default(),
874 lang: None,
875 }
876 }
877}
878
879/// Partial ordering for literals following SPARQL comparison semantics.
880///
881/// Comparison rules:
882/// - String literals are compared lexicographically by their lexical form.
883/// - Datatype literals are comparable **only if** they share the same datatype,
884/// and are then compared by lexical form.
885/// - Numeric literals are compared by numeric value.
886/// - Boolean literals follow `true > false`.
887/// - Datetime literals are compared chronologically.
888///
889/// If two literals are not comparable under these rules, `None` is returned.
890///
891/// See: <https://www.w3.org/TR/sparql11-query/#OperatorMapping>
892#[allow(clippy::non_canonical_partial_ord_impl)]
893impl PartialOrd for ConcreteLiteral {
894 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
895 match (self, other) {
896 // Chronological comparison for datetime literals
897 (Self::DatetimeLiteral(dt1), Self::DatetimeLiteral(dt2)) => dt1.partial_cmp(dt2),
898 // Lexicographic comparison for plain string literals
899 (Self::StringLiteral { lexical_form: lf1, .. }, Self::StringLiteral { lexical_form: lf2, .. }) => {
900 Some(lf1.cmp(lf2))
901 },
902 // Datatype literals are only comparable if their datatypes match
903 (
904 Self::DatatypeLiteral {
905 lexical_form: lf1,
906 datatype: dt1,
907 },
908 Self::DatatypeLiteral {
909 lexical_form: lf2,
910 datatype: dt2,
911 },
912 ) if dt1 == dt2 => Some(lf1.cmp(lf2)),
913 // Numeric comparison (may return None for NaN)
914 (Self::NumericLiteral(n1), Self::NumericLiteral(n2)) => n1.partial_cmp(n2),
915 // Boolean ordering: false < true
916 (Self::BooleanLiteral(b1), Self::BooleanLiteral(b2)) => Some(b1.cmp(b2)),
917 // Wrong-datatype literals can still be compared lexically if the expected datatype matches
918 (
919 Self::WrongDatatypeLiteral {
920 lexical_form: lf1,
921 datatype: dt1,
922 ..
923 },
924 Self::DatatypeLiteral {
925 lexical_form: lf2,
926 datatype: dt2,
927 },
928 ) if dt1 == dt2 => Some(lf1.cmp(lf2)),
929 // All other combinations are considered incomparable
930 _ => None,
931 }
932 }
933}
934
935/// Total ordering for literals.
936///
937/// # Panics
938///
939/// This implementation **panics** if two literals are not comparable, such as:
940/// - Literals with different datatypes
941/// - Numeric literals involving `NaN`
942///
943/// This is intended as a temporary solution to support sorting in validation
944/// workflows where such cases are not expected.
945///
946/// # TODO
947///
948/// Define a total ordering that is well-defined for *all* literals.
949impl Ord for ConcreteLiteral {
950 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
951 self.partial_cmp(other)
952 .unwrap_or_else(|| panic!("Cannot compare literals {self} and {other}"))
953 }
954}
955
956impl Display for ConcreteLiteral {
957 /// Formats the literal using a basic prefix map for qualified display.
958 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
959 self.display_qualified(f, &PrefixMap::basic())
960 }
961}
962
963impl DerefIri for ConcreteLiteral {
964 /// Resolves IRIs and prefixes contained in the literal.
965 ///
966 /// - Value-based literals (`NumericLiteral`, `BooleanLiteral`, `DatetimeLiteral`, `StringLiteral`) are cloned directly.
967 /// - Datatype literals have their datatype IRIs dereferenced using `base` and `prefixmap`.
968 /// - Wrong datatype literals are converted into properly typed literals.
969 ///
970 /// # Errors
971 ///
972 /// Returns `DerefError` if datatype resolution fails.
973 fn deref_iri(self, base: Option<&IriS>, prefixmap: Option<&PrefixMap>) -> Result<Self, DerefError> {
974 match self {
975 Self::NumericLiteral(_) | Self::BooleanLiteral(_) | Self::DatetimeLiteral(_) => Ok(self.clone()),
976 Self::StringLiteral { .. } => Ok(self.clone()),
977
978 Self::DatatypeLiteral { lexical_form, datatype }
979 | Self::WrongDatatypeLiteral {
980 lexical_form, datatype, ..
981 } => {
982 let dt = datatype.deref_iri(base, prefixmap)?;
983 Ok(Self::DatatypeLiteral {
984 lexical_form: lexical_form.clone(),
985 datatype: dt,
986 })
987 },
988 }
989 }
990}
991
992// ============================================================================
993// Conversions
994// ============================================================================
995
996impl TryFrom<oxrdf::Literal> for ConcreteLiteral {
997 type Error = RDFError;
998
999 /// Attempts to convert an oxrdf literal into an `SLiteral`.
1000 ///
1001 /// Supported cases:
1002 /// - Plain string literals
1003 /// - Language-tagged string literals
1004 /// - Typed literals (with datatype parsing)
1005 ///
1006 /// # Errors
1007 ///
1008 /// Returns an `LiteralError` if:
1009 /// - The language tag is invalid
1010 /// - The datatype is unsupported or malformed
1011 /// - The literal structure is unknown
1012 fn try_from(value: oxrdf::Literal) -> Result<Self, Self::Error> {
1013 let literal_str = value.to_string();
1014
1015 let (lexical, datatype_opt, lang_opt, _) = value.destruct();
1016
1017 match (lexical, datatype_opt, lang_opt) {
1018 (s, None, None) => Ok(Self::str(&s)),
1019
1020 (s, None, Some(lang_tag)) => Lang::new(lang_tag.clone())
1021 .map(|lang| Self::lang_str(&s, lang))
1022 .map_err(|e| RDFError::LanguageTagError {
1023 literal: literal_str,
1024 language: lang_tag,
1025 error: e.to_string(),
1026 }),
1027
1028 (s, Some(dtype), None) => {
1029 // Use safe IRI creation if possible
1030 let datatype_iri = IriRef::iri(IriS::new_unchecked(dtype.as_str()));
1031 check_literal_datatype(s.as_ref(), &datatype_iri)
1032 },
1033
1034 _ => Err(RDFError::ConversionError {
1035 msg: format!("Unknown literal structure: {literal_str}"),
1036 }),
1037 }
1038 }
1039}
1040
1041impl From<ConcreteLiteral> for oxrdf::Literal {
1042 /// Converts an `SLiteral` into an `oxrdf::Literal`
1043 fn from(value: ConcreteLiteral) -> Self {
1044 // Helper for datatype literals to reduce repetition
1045 fn typed_literal(lexical: String, datatype: &IriRef) -> oxrdf::Literal {
1046 datatype
1047 .get_iri()
1048 .map(|dt: &IriS| oxrdf::Literal::new_typed_literal(lexical.clone(), oxrdf::NamedNode::from(dt.clone())))
1049 .unwrap_or_else(|_| lexical.into())
1050 }
1051
1052 match value {
1053 ConcreteLiteral::StringLiteral { lexical_form, lang } => match lang {
1054 Some(l) => oxrdf::Literal::new_language_tagged_literal_unchecked(lexical_form, l.to_string()),
1055 None => lexical_form.into(),
1056 },
1057
1058 ConcreteLiteral::DatatypeLiteral { lexical_form, datatype }
1059 | ConcreteLiteral::WrongDatatypeLiteral {
1060 lexical_form, datatype, ..
1061 } => typed_literal(lexical_form, &datatype),
1062
1063 ConcreteLiteral::NumericLiteral(number) => number.into(),
1064 ConcreteLiteral::BooleanLiteral(b) => b.into(),
1065 ConcreteLiteral::DatetimeLiteral(dt) => (*dt.value()).into(),
1066 }
1067 }
1068}
1069
1070impl From<&ConcreteLiteral> for oxrdf::Literal {
1071 // Converts a reference to an `SLiteral` into an `oxrdf::Literal`
1072 fn from(value: &ConcreteLiteral) -> Self {
1073 oxrdf::Literal::from(value.clone())
1074 }
1075}
1076
1077// ============================================================================
1078// Helper Functions
1079// ============================================================================
1080
1081/// Serializes a boolean literal as a string ("true" or "false").
1082///
1083/// # Parameters
1084/// - `value`: A reference to the boolean value to serialize.
1085/// - `serializer`: The serializer to use (implements the `Serializer` trait).
1086fn serialize_boolean_literal<S>(value: &bool, serializer: S) -> result::Result<S::Ok, S::Error>
1087where
1088 S: Serializer,
1089{
1090 serializer.serialize_str(if *value { "true" } else { "false" })
1091}
1092
1093/// Validates a literal's lexical form against its declared datatype.
1094///
1095/// Returns a properly typed literal if validation succeeds, or a
1096/// `WrongDatatypeLiteral` if the lexical form doesn't match the datatype.
1097///
1098/// For unknown or custom datatypes, returns a `DatatypeLiteral` without validating.
1099///
1100/// # Arguments
1101///
1102/// * `lexical_form` - The string value of the literal
1103/// * `datatype` - The declared datatype as an owned `IriRef`
1104///
1105/// # Errors
1106///
1107/// Returns `RDFError` if the datatype IRI itself is invalid.
1108fn check_literal_datatype(lexical_form: &str, datatype: &IriRef) -> Result<ConcreteLiteral, RDFError> {
1109 // Resolve the IRI
1110 let iri = datatype.get_iri().map_err(|_| RDFError::IriRefError {
1111 iri_ref: datatype.to_string(),
1112 })?;
1113
1114 let iri_str = iri.as_str();
1115
1116 // Macro for constructors that return ConcreteLiteral directly
1117 macro_rules! check_xsd_type {
1118 ($xsd_const:expr, $parse_fn:expr, $construct_fn:expr) => {
1119 if iri_str == $xsd_const {
1120 return Ok(validate(lexical_form, datatype, $parse_fn, $construct_fn));
1121 }
1122 };
1123 }
1124
1125 // Macro for constructors that return Result<ConcreteLiteral, RDFError>
1126 macro_rules! check_xsd_type_result {
1127 ($xsd_const:expr, $parse_fn:expr, $construct_fn:expr) => {
1128 if iri_str == $xsd_const {
1129 return Ok(validate_with_result(
1130 lexical_form,
1131 datatype,
1132 $parse_fn,
1133 $construct_fn,
1134 ));
1135 }
1136 };
1137 }
1138
1139 // Check all XSD types using appropriate macro
1140 check_xsd_type!(
1141 XsdVocab::XSD_INTEGER,
1142 ConcreteLiteral::parse_integer,
1143 ConcreteLiteral::integer
1144 );
1145 check_xsd_type!(XsdVocab::XSD_LONG, ConcreteLiteral::parse_long, ConcreteLiteral::long);
1146 check_xsd_type!(
1147 XsdVocab::XSD_DOUBLE,
1148 ConcreteLiteral::parse_double,
1149 ConcreteLiteral::double
1150 );
1151 check_xsd_type!(
1152 XsdVocab::XSD_BOOLEAN,
1153 ConcreteLiteral::parse_bool,
1154 ConcreteLiteral::boolean
1155 );
1156 check_xsd_type!(
1157 XsdVocab::XSD_FLOAT,
1158 ConcreteLiteral::parse_float,
1159 ConcreteLiteral::float
1160 );
1161 check_xsd_type!(
1162 XsdVocab::XSD_DECIMAL,
1163 ConcreteLiteral::parse_decimal,
1164 ConcreteLiteral::decimal
1165 );
1166 check_xsd_type!(XsdVocab::XSD_BYTE, ConcreteLiteral::parse_byte, ConcreteLiteral::byte);
1167 check_xsd_type!(
1168 XsdVocab::XSD_SHORT,
1169 ConcreteLiteral::parse_short,
1170 ConcreteLiteral::short
1171 );
1172 check_xsd_type!(
1173 XsdVocab::XSD_UNSIGNED_INT,
1174 ConcreteLiteral::parse_unsigned_int,
1175 ConcreteLiteral::unsigned_int
1176 );
1177 check_xsd_type!(
1178 XsdVocab::XSD_UNSIGNED_LONG,
1179 ConcreteLiteral::parse_unsigned_long,
1180 ConcreteLiteral::unsigned_long
1181 );
1182 check_xsd_type!(
1183 XsdVocab::XSD_UNSIGNED_BYTE,
1184 ConcreteLiteral::parse_unsigned_byte,
1185 ConcreteLiteral::unsigned_byte
1186 );
1187 check_xsd_type!(
1188 XsdVocab::XSD_UNSIGNED_SHORT,
1189 ConcreteLiteral::parse_unsigned_short,
1190 ConcreteLiteral::unsigned_short
1191 );
1192 check_xsd_type!(
1193 XsdVocab::XSD_NON_NEGATIVE_INTEGER,
1194 ConcreteLiteral::parse_non_negative_integer,
1195 ConcreteLiteral::non_negative_integer
1196 );
1197
1198 // These constructors return Result and need special handling
1199 check_xsd_type_result!(
1200 XsdVocab::XSD_NEGATIVE_INTEGER,
1201 ConcreteLiteral::parse_negative_integer,
1202 ConcreteLiteral::negative_integer
1203 );
1204 check_xsd_type_result!(
1205 XsdVocab::XSD_POSITIVE_INTEGER,
1206 ConcreteLiteral::parse_positive_integer,
1207 ConcreteLiteral::positive_integer
1208 );
1209 check_xsd_type_result!(
1210 XsdVocab::XSD_NON_POSITIVE_INTEGER,
1211 ConcreteLiteral::parse_non_positive_integer,
1212 ConcreteLiteral::non_positive_integer
1213 );
1214 check_xsd_type!(
1215 XsdVocab::XSD_DATE_TIME,
1216 ConcreteLiteral::parse_datetime,
1217 ConcreteLiteral::datetime
1218 );
1219
1220 // Unknown or custom datatype: do not validate lexical form
1221 Ok(ConcreteLiteral::DatatypeLiteral {
1222 lexical_form: lexical_form.to_string(),
1223 datatype: datatype.clone(),
1224 })
1225}
1226
1227/// Validates a lexical form against a specified datatype using a parser and constructor.
1228///
1229/// # Parameters
1230/// - `lexical_form`: The literal value as a string that needs to be validated.
1231/// - `datatype`: The IRI of the expected datatype.
1232/// - `parser`: A function that attempts to parse the `lexical_form` into a value of type `T`.
1233/// - `constructor`: A function that constructs a `ConcreteLiteral` from a successfully parsed value.
1234fn validate<T, P, C>(lexical_form: &str, datatype: &IriRef, parser: P, constructor: C) -> ConcreteLiteral
1235where
1236 P: Fn(&str) -> Result<T, String>,
1237 C: Fn(T) -> ConcreteLiteral,
1238{
1239 match parser(lexical_form) {
1240 Ok(value) => constructor(value),
1241 Err(err) => ConcreteLiteral::WrongDatatypeLiteral {
1242 lexical_form: lexical_form.to_string(),
1243 datatype: datatype.clone(),
1244 error: err.to_string(),
1245 },
1246 }
1247}
1248
1249/// Validates a lexical form with a constructor that returns `Result`.
1250///
1251/// This variant handles constructors that perform additional validation
1252/// (e.g., range checks for positiveInteger, negativeInteger).
1253///
1254/// # Parameters
1255/// - `lexical_form`: The literal value as a string that needs to be validated.
1256/// - `datatype`: The IRI of the expected datatype.
1257/// - `parser`: A function that attempts to parse the `lexical_form` into a value of type `T`.
1258/// - `constructor`: A function that constructs a `ConcreteLiteral` from a parsed value, returning `Result`.
1259fn validate_with_result<T, P, C>(lexical_form: &str, datatype: &IriRef, parser: P, constructor: C) -> ConcreteLiteral
1260where
1261 P: Fn(&str) -> Result<T, String>,
1262 C: Fn(T) -> Result<ConcreteLiteral, RDFError>,
1263{
1264 match parser(lexical_form) {
1265 Ok(value) => match constructor(value) {
1266 Ok(literal) => literal,
1267 Err(err) => ConcreteLiteral::WrongDatatypeLiteral {
1268 lexical_form: lexical_form.to_string(),
1269 datatype: datatype.clone(),
1270 error: err.to_string(),
1271 },
1272 },
1273 Err(err) => ConcreteLiteral::WrongDatatypeLiteral {
1274 lexical_form: lexical_form.to_string(),
1275 datatype: datatype.clone(),
1276 error: err.to_string(),
1277 },
1278 }
1279}