Skip to main content

rudof_rdf/rdf_core/term/literal/
numeric_literal.rs

1use core::fmt;
2use std::fmt::Display;
3
4use crate::rdf_core::RDFError;
5use crate::rdf_core::vocabs::XsdVocab;
6use rust_decimal::{
7    Decimal,
8    prelude::{FromPrimitive, ToPrimitive},
9};
10use serde::{Deserialize, Serialize, Serializer};
11use std::hash::Hash;
12
13/// Represents RDF numeric literals with XSD datatype semantics.
14///
15/// This enum supports all XSD numeric types and provides type-safe
16/// conversions between them. Uses `#[serde(untagged)]` for flexible
17/// deserialization from JSON/other formats.
18#[derive(Debug, Clone, Deserialize)]
19#[serde(untagged)]
20pub enum NumericLiteral {
21    Integer(i128),
22    Byte(i8),
23    Short(i16),
24    NonNegativeInteger(u128),
25    UnsignedLong(u64),
26    UnsignedInt(u32),
27    UnsignedShort(u16),
28    UnsignedByte(u8),
29    PositiveInteger(u128),
30    NegativeInteger(i128),
31    NonPositiveInteger(i128),
32    Long(i64),
33    Decimal(Decimal),
34    Double(f64),
35    Float(f32),
36}
37
38// Macro to eliminate duplicated decimal conversion methods
39macro_rules! impl_decimal_from {
40    ($name:ident, $type:ty, $from_method:ident) => {
41        /// Converts value to Decimal literal.
42        ///
43        /// # Errors
44        /// Returns error if value cannot be represented as Decimal (e.g., NaN, infinity for floats).
45        pub fn $name(d: $type) -> Result<NumericLiteral, RDFError> {
46            Decimal::$from_method(d)
47                .ok_or_else(|| RDFError::ConversionError {
48                    msg: format!("Decimal conversion error from {}: {}", stringify!($type), d),
49                })
50                .map(NumericLiteral::Decimal)
51        }
52    };
53}
54
55/// ## Constructor Methods
56impl NumericLiteral {
57    /// Returns the XSD datatype IRI for this numeric literal.
58    ///
59    /// Each variant maps to its corresponding XML Schema datatype.
60    pub fn datatype(&self) -> &str {
61        match self {
62            NumericLiteral::Integer(_) => XsdVocab::XSD_INTEGER,
63            NumericLiteral::Decimal(_) => XsdVocab::XSD_DECIMAL,
64            NumericLiteral::Double(_) => XsdVocab::XSD_DOUBLE,
65            NumericLiteral::Long(_) => XsdVocab::XSD_LONG,
66            NumericLiteral::Float(_) => XsdVocab::XSD_FLOAT,
67            NumericLiteral::Byte(_) => XsdVocab::XSD_BYTE,
68            NumericLiteral::Short(_) => XsdVocab::XSD_SHORT,
69            NumericLiteral::NonNegativeInteger(_) => XsdVocab::XSD_NON_NEGATIVE_INTEGER,
70            NumericLiteral::UnsignedLong(_) => XsdVocab::XSD_UNSIGNED_LONG,
71            NumericLiteral::UnsignedInt(_) => XsdVocab::XSD_UNSIGNED_INT,
72            NumericLiteral::UnsignedShort(_) => XsdVocab::XSD_UNSIGNED_SHORT,
73            NumericLiteral::UnsignedByte(_) => XsdVocab::XSD_UNSIGNED_BYTE,
74            NumericLiteral::PositiveInteger(_) => XsdVocab::XSD_POSITIVE_INTEGER,
75            NumericLiteral::NegativeInteger(_) => XsdVocab::XSD_NEGATIVE_INTEGER,
76            NumericLiteral::NonPositiveInteger(_) => XsdVocab::XSD_NON_POSITIVE_INTEGER,
77        }
78    }
79
80    /// Creates a decimal literal from a Decimal value.
81    pub fn decimal(d: Decimal) -> NumericLiteral {
82        NumericLiteral::Decimal(d)
83    }
84
85    /// Creates a non-positive integer literal from an i128 value.
86    ///
87    /// # Errors
88    /// Returns error if value is greater than 0.
89    pub fn non_positive_integer(n: i128) -> Result<NumericLiteral, RDFError> {
90        if n > 0 {
91            return Err(RDFError::ConversionError {
92                msg: ("nonPositiveInteger (must be <= 0)".to_string()),
93            });
94        }
95        Ok(NumericLiteral::NonPositiveInteger(n))
96    }
97
98    /// Creates a non-negative integer literal from a u128 value.
99    pub fn non_negative_integer(n: u128) -> NumericLiteral {
100        NumericLiteral::NonNegativeInteger(n)
101    }
102
103    /// Creates a positive integer literal (value > 0).
104    ///
105    /// # Errors
106    /// Returns error if value is 0, as XSD positiveInteger requires > 0.
107    pub fn positive_integer(n: u128) -> Result<NumericLiteral, RDFError> {
108        if n == 0 {
109            return Err(RDFError::ConversionError {
110                msg: ("positiveInteger (must be > 0)".to_string()),
111            });
112        }
113        Ok(NumericLiteral::PositiveInteger(n))
114    }
115
116    /// Creates a negative integer literal from an i128 value.
117    ///
118    /// # Errors
119    /// Returns error if value is greater than or equal to 0.
120    pub fn negative_integer(n: i128) -> Result<NumericLiteral, RDFError> {
121        if n >= 0 {
122            return Err(RDFError::ConversionError {
123                msg: ("negativeInteger (must be < 0)".to_string()),
124            });
125        }
126        Ok(NumericLiteral::NegativeInteger(n))
127    }
128
129    /// Creates an unsigned byte literal (0-255).
130    pub fn unsigned_byte(n: u8) -> NumericLiteral {
131        NumericLiteral::UnsignedByte(n)
132    }
133
134    /// Creates an unsigned short literal (0-65535).
135    pub fn unsigned_short(n: u16) -> NumericLiteral {
136        NumericLiteral::UnsignedShort(n)
137    }
138
139    /// Creates an unsigned int literal.
140    pub fn unsigned_int(n: u32) -> NumericLiteral {
141        NumericLiteral::UnsignedInt(n)
142    }
143
144    /// Creates an unsigned long literal.
145    pub fn unsigned_long(n: u64) -> NumericLiteral {
146        NumericLiteral::UnsignedLong(n)
147    }
148
149    /// Creates a decimal from separate whole and fractional parts.
150    ///
151    /// # Errors
152    /// Returns error if the constructed string cannot be parsed as Decimal.
153    pub fn decimal_from_parts(whole: i64, fraction: u32) -> Result<NumericLiteral, RDFError> {
154        let s = format!("{whole}.{fraction}");
155        let d = Decimal::from_str_exact(&s).map_err(|e| RDFError::ConversionError { msg: e.to_string() })?;
156        Ok(NumericLiteral::Decimal(d))
157    }
158
159    /// Creates a byte literal (-128 to 127).
160    pub fn byte(d: i8) -> NumericLiteral {
161        NumericLiteral::Byte(d)
162    }
163
164    /// Creates a short literal (-32768 to 32767).
165    pub fn short(d: i16) -> NumericLiteral {
166        NumericLiteral::Short(d)
167    }
168
169    /// Creates a long literal (64-bit signed integer).
170    pub fn long(d: i64) -> NumericLiteral {
171        NumericLiteral::Long(d)
172    }
173
174    /// Creates a float literal (32-bit).
175    pub fn float(d: f32) -> NumericLiteral {
176        NumericLiteral::Float(d)
177    }
178
179    /// Creates an integer literal (unbounded).
180    pub fn integer(n: i128) -> NumericLiteral {
181        NumericLiteral::Integer(n)
182    }
183
184    /// Creates a double literal (64-bit).
185    pub fn double(d: f64) -> NumericLiteral {
186        NumericLiteral::Double(d)
187    }
188}
189
190/// ## Conversion Methods
191impl NumericLiteral {
192    // Use macro to generate all decimal_from_* methods
193    impl_decimal_from!(decimal_from_f64, f64, from_f64);
194    impl_decimal_from!(decimal_from_f32, f32, from_f32);
195    impl_decimal_from!(decimal_from_isize, isize, from_isize);
196    impl_decimal_from!(decimal_from_i32, i32, from_i32);
197    impl_decimal_from!(decimal_from_i64, i64, from_i64);
198    impl_decimal_from!(decimal_from_i128, i128, from_i128);
199    impl_decimal_from!(decimal_from_u32, u32, from_u32);
200    impl_decimal_from!(decimal_from_u64, u64, from_u64);
201    impl_decimal_from!(decimal_from_u128, u128, from_u128);
202
203    /// Creates an integer literal from i64.
204    pub fn integer_from_i64(d: i64) -> NumericLiteral {
205        NumericLiteral::Integer(d as i128)
206    }
207
208    /// Creates an integer literal from i128.
209    pub fn integer_from_i128(d: i128) -> NumericLiteral {
210        NumericLiteral::Integer(d)
211    }
212
213    /// Converts any numeric literal to Decimal for uniform comparison.
214    ///
215    /// This method enables cross-type numeric comparisons by normalizing
216    /// all variants to the Decimal type.
217    pub fn to_decimal(&self) -> Option<Decimal> {
218        match self {
219            NumericLiteral::Integer(n) => Decimal::from_i128(*n),
220            NumericLiteral::Double(d) => Decimal::from_f64(*d),
221            NumericLiteral::Decimal(d) => Some(*d),
222            NumericLiteral::Long(l) => Decimal::from_i64(*l),
223            NumericLiteral::Float(f) => Decimal::from_f32(*f),
224            NumericLiteral::Byte(b) => Decimal::from_i8(*b),
225            NumericLiteral::Short(s) => Decimal::from_i16(*s),
226            NumericLiteral::NonNegativeInteger(n) => Decimal::from_u128(*n),
227            NumericLiteral::UnsignedLong(n) => Decimal::from_u64(*n),
228            NumericLiteral::UnsignedInt(n) => Decimal::from_u32(*n),
229            NumericLiteral::UnsignedShort(n) => Decimal::from_u16(*n),
230            NumericLiteral::UnsignedByte(n) => Decimal::from_u8(*n),
231            NumericLiteral::PositiveInteger(n) => Decimal::from_u128(*n),
232            NumericLiteral::NegativeInteger(n) => Decimal::from_i128(*n),
233            NumericLiteral::NonPositiveInteger(n) => Decimal::from_i128(*n),
234        }
235    }
236}
237
238/// ## Utility Methods
239impl NumericLiteral {
240    /// Returns the lexical form (string representation) of this literal.
241    ///
242    /// This is equivalent to the Display implementation.
243    pub fn lexical_form(&self) -> String {
244        self.to_string()
245    }
246
247    /// Checks if this numeric literal is less than another.
248    ///
249    /// Optimized for integer comparisons; falls back to decimal conversion
250    /// for mixed-type comparisons.
251    pub fn less_than(&self, other: &NumericLiteral) -> bool {
252        match (self, other) {
253            // Fast path: direct integer comparison
254            (NumericLiteral::Integer(n1), NumericLiteral::Integer(n2)) => n1 < n2,
255            // Generic path: convert to decimal for comparison
256            (v1, v2) => v1.to_decimal() < v2.to_decimal(),
257        }
258    }
259
260    /// Checks if this numeric literal is less than or equal to another.
261    pub fn less_than_or_eq(&self, other: &NumericLiteral) -> bool {
262        match (self, other) {
263            (NumericLiteral::Integer(n1), NumericLiteral::Integer(n2)) => n1 <= n2,
264            (v1, v2) => v1.to_decimal() <= v2.to_decimal(),
265        }
266    }
267
268    /// Returns the total number of digits in the literal.
269    ///
270    /// For decimals, this excludes the decimal point and sign.
271    /// Returns None for float/double as they don't have a fixed digit count.
272    pub fn total_digits(&self) -> Option<usize> {
273        let digits = match self {
274            // For integer types, count digits in string representation
275            NumericLiteral::Integer(d) => {
276                if *d == i128::MIN {
277                    39
278                } else {
279                    d.abs().to_string().len()
280                }
281            },
282            NumericLiteral::Long(d) => {
283                if *d == i64::MIN {
284                    19
285                } else {
286                    d.abs().to_string().len()
287                }
288            },
289            NumericLiteral::Byte(d) => {
290                if *d == i8::MIN {
291                    3
292                } else {
293                    d.abs().to_string().len()
294                }
295            },
296            NumericLiteral::Short(d) => {
297                if *d == i16::MIN {
298                    5
299                } else {
300                    d.abs().to_string().len()
301                }
302            },
303            NumericLiteral::NonNegativeInteger(d) => d.to_string().len(),
304            NumericLiteral::UnsignedLong(d) => d.to_string().len(),
305            NumericLiteral::UnsignedInt(d) => d.to_string().len(),
306            NumericLiteral::UnsignedShort(d) => d.to_string().len(),
307            NumericLiteral::UnsignedByte(d) => d.to_string().len(),
308            NumericLiteral::PositiveInteger(d) => d.to_string().len(),
309            NumericLiteral::NegativeInteger(d) => {
310                if *d == i128::MIN {
311                    39
312                } else {
313                    d.abs().to_string().len()
314                }
315            },
316            NumericLiteral::NonPositiveInteger(d) => {
317                if *d == i128::MIN {
318                    39
319                } else {
320                    d.abs().to_string().len()
321                }
322            },
323            // For decimals, normalize and count only digits
324            NumericLiteral::Decimal(d) => {
325                let normalized = d.normalize();
326                normalized.to_string().chars().filter(|c| c.is_ascii_digit()).count()
327            },
328            // Float/double don't have meaningful total digits
329            NumericLiteral::Double(_) | NumericLiteral::Float(_) => return None,
330        };
331
332        Some(digits)
333    }
334
335    /// Returns the number of fractional digits.
336    ///
337    /// Returns 0 for integer types, counts digits after decimal point for decimals,
338    /// and None for float/double.
339    pub fn fraction_digits(&self) -> Option<usize> {
340        match self {
341            // All integer types have 0 fractional digits
342            NumericLiteral::Integer(_)
343            | NumericLiteral::Long(_)
344            | NumericLiteral::NonNegativeInteger(_)
345            | NumericLiteral::UnsignedLong(_)
346            | NumericLiteral::UnsignedInt(_)
347            | NumericLiteral::UnsignedShort(_)
348            | NumericLiteral::UnsignedByte(_)
349            | NumericLiteral::PositiveInteger(_)
350            | NumericLiteral::NegativeInteger(_)
351            | NumericLiteral::NonPositiveInteger(_)
352            | NumericLiteral::Byte(_)
353            | NumericLiteral::Short(_) => Some(0),
354            // For decimals, find position of decimal point and count digits after it
355            NumericLiteral::Decimal(d) => {
356                let s = d.to_string();
357                Some(s.find('.').map_or(0, |pos| s.len() - pos - 1))
358            },
359            // Float/double don't have meaningful fraction digits
360            NumericLiteral::Double(_) | NumericLiteral::Float(_) => None,
361        }
362    }
363}
364
365// ============================================================================
366// Trait Implementations
367// ============================================================================
368
369/// Eq implementation requires all values to be comparable.
370///
371/// Note: This implementation is consistent with Hash because both use
372/// the exact variant type + value, not normalized decimal values.
373impl Eq for NumericLiteral {}
374
375/// PartialEq that compares numeric value when possible (canonicalizing to Decimal).
376impl PartialEq for NumericLiteral {
377    fn eq(&self, other: &Self) -> bool {
378        // If both can be represented as Decimal, compare by decimal value.
379        if let (Some(d1), Some(d2)) = (self.to_decimal(), other.to_decimal()) {
380            return d1 == d2;
381        }
382
383        // Fall back to matching exact variants for cases that cannot be normalized.
384        match (self, other) {
385            (NumericLiteral::Double(a), NumericLiteral::Double(b)) => a.to_bits() == b.to_bits(),
386            (NumericLiteral::Float(a), NumericLiteral::Float(b)) => a.to_bits() == b.to_bits(),
387            _ => {
388                // Same variant and same value
389                core::mem::discriminant(self) == core::mem::discriminant(other)
390                    && match (self, other) {
391                        (NumericLiteral::Integer(a), NumericLiteral::Integer(b)) => a == b,
392                        (NumericLiteral::Byte(a), NumericLiteral::Byte(b)) => a == b,
393                        (NumericLiteral::Short(a), NumericLiteral::Short(b)) => a == b,
394                        (NumericLiteral::NonNegativeInteger(a), NumericLiteral::NonNegativeInteger(b)) => a == b,
395                        (NumericLiteral::UnsignedLong(a), NumericLiteral::UnsignedLong(b)) => a == b,
396                        (NumericLiteral::UnsignedInt(a), NumericLiteral::UnsignedInt(b)) => a == b,
397                        (NumericLiteral::UnsignedShort(a), NumericLiteral::UnsignedShort(b)) => a == b,
398                        (NumericLiteral::UnsignedByte(a), NumericLiteral::UnsignedByte(b)) => a == b,
399                        (NumericLiteral::PositiveInteger(a), NumericLiteral::PositiveInteger(b)) => a == b,
400                        (NumericLiteral::NegativeInteger(a), NumericLiteral::NegativeInteger(b)) => a == b,
401                        (NumericLiteral::NonPositiveInteger(a), NumericLiteral::NonPositiveInteger(b)) => a == b,
402                        (NumericLiteral::Long(a), NumericLiteral::Long(b)) => a == b,
403                        (NumericLiteral::Decimal(a), NumericLiteral::Decimal(b)) => a == b,
404                        _ => false,
405                    }
406            },
407        }
408    }
409}
410
411/// Hash implementation consistent with the numeric-value-based equality above.
412impl Hash for NumericLiteral {
413    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
414        // If convertible to Decimal, hash the normalized Decimal value (ignores variant)
415        if let Some(d) = self.to_decimal() {
416            // normalize to remove trailing zeros that would change string form
417            d.normalize().hash(state);
418            return;
419        }
420
421        // For floating types that couldn't be converted, hash bit representation
422        match self {
423            NumericLiteral::Double(d) => {
424                d.to_bits().hash(state);
425                return;
426            },
427            NumericLiteral::Float(f) => {
428                f.to_bits().hash(state);
429                return;
430            },
431            _ => {},
432        }
433
434        // Otherwise, hash discriminant and concrete value
435        core::mem::discriminant(self).hash(state);
436        match self {
437            NumericLiteral::Integer(n) => n.hash(state),
438            NumericLiteral::Byte(b) => b.hash(state),
439            NumericLiteral::Short(s) => s.hash(state),
440            NumericLiteral::NonNegativeInteger(n) => n.hash(state),
441            NumericLiteral::UnsignedLong(n) => n.hash(state),
442            NumericLiteral::UnsignedInt(n) => n.hash(state),
443            NumericLiteral::UnsignedShort(n) => n.hash(state),
444            NumericLiteral::UnsignedByte(n) => n.hash(state),
445            NumericLiteral::PositiveInteger(n) => n.hash(state),
446            NumericLiteral::NegativeInteger(n) => n.hash(state),
447            NumericLiteral::NonPositiveInteger(n) => n.hash(state),
448            NumericLiteral::Long(l) => l.hash(state),
449            NumericLiteral::Decimal(d) => d.hash(state),
450            _ => {},
451        }
452    }
453}
454
455/// Custom serialization to preserve numeric types in target format.
456impl Serialize for NumericLiteral {
457    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
458    where
459        S: Serializer,
460    {
461        match self {
462            NumericLiteral::Integer(n) => serializer.serialize_i128(*n),
463            NumericLiteral::Decimal(d) => {
464                // Try to convert to f64 for JSON compatibility
465                match d.to_f64() {
466                    Some(f) => serializer.serialize_f64(f),
467                    None => serializer.serialize_str(&d.to_string()),
468                }
469            },
470            NumericLiteral::Double(d) => serializer.serialize_f64(*d),
471            NumericLiteral::Long(n) => serializer.serialize_i64(*n),
472            NumericLiteral::Float(f) => serializer.serialize_f32(*f),
473            NumericLiteral::Byte(b) => serializer.serialize_i8(*b),
474            NumericLiteral::Short(s) => serializer.serialize_i16(*s),
475            NumericLiteral::NonNegativeInteger(n) => serializer.serialize_u128(*n),
476            NumericLiteral::UnsignedLong(n) => serializer.serialize_u64(*n),
477            NumericLiteral::UnsignedInt(n) => serializer.serialize_u32(*n),
478            NumericLiteral::UnsignedShort(n) => serializer.serialize_u16(*n),
479            NumericLiteral::UnsignedByte(n) => serializer.serialize_u8(*n),
480            NumericLiteral::PositiveInteger(n) => serializer.serialize_u128(*n),
481            NumericLiteral::NegativeInteger(n) => serializer.serialize_i128(*n),
482            NumericLiteral::NonPositiveInteger(n) => serializer.serialize_i128(*n),
483        }
484    }
485}
486
487/// Display implementation for human-readable output.
488impl Display for NumericLiteral {
489    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
490        match self {
491            NumericLiteral::Double(d) => write!(f, "{d}"),
492            NumericLiteral::Integer(n) => write!(f, "{n}"),
493            NumericLiteral::Decimal(d) => write!(f, "{d}"),
494            NumericLiteral::Long(l) => write!(f, "{l}"),
495            NumericLiteral::Float(n) => write!(f, "{n}"),
496            NumericLiteral::Byte(b) => write!(f, "{b}"),
497            NumericLiteral::Short(s) => write!(f, "{s}"),
498            NumericLiteral::NonNegativeInteger(n) => write!(f, "{n}"),
499            NumericLiteral::UnsignedLong(n) => write!(f, "{n}"),
500            NumericLiteral::UnsignedInt(n) => write!(f, "{n}"),
501            NumericLiteral::UnsignedShort(n) => write!(f, "{n}"),
502            NumericLiteral::UnsignedByte(n) => write!(f, "{n}"),
503            NumericLiteral::PositiveInteger(n) => write!(f, "{n}"),
504            NumericLiteral::NegativeInteger(n) => write!(f, "{n}"),
505            NumericLiteral::NonPositiveInteger(n) => write!(f, "{n}"),
506        }
507    }
508}
509
510/// Ordering based on decimal conversion for cross-type comparisons.
511impl PartialOrd for NumericLiteral {
512    // Convert both to Decimal and compare
513    // Returns None if conversion fails (e.g., NaN)
514    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
515        let self_decimal = self.to_decimal()?;
516        let other_decimal = other.to_decimal()?;
517        self_decimal.partial_cmp(&other_decimal)
518    }
519}
520
521// ============================================================================
522// Conversions
523// ============================================================================
524
525/// Parse numeric literals from strings.
526///
527/// Attempts to parse as integer first, then float, then decimal.
528impl TryFrom<&str> for NumericLiteral {
529    type Error = String;
530
531    fn try_from(value: &str) -> Result<Self, Self::Error> {
532        // Try integer first (most common case)
533        if let Ok(i) = value.parse::<i128>() {
534            return Ok(NumericLiteral::Integer(i));
535        }
536        // Then try float
537        if let Ok(f) = value.parse::<f64>() {
538            return Ok(NumericLiteral::Double(f));
539        }
540        // Finally try decimal
541        if let Ok(d) = Decimal::from_str_exact(value) {
542            return Ok(NumericLiteral::Decimal(d));
543        }
544
545        Err(format!("Cannot parse '{value}' as NumericLiteral"))
546    }
547}
548
549/// Conversion to oxrdf::Literal for RDF serialization.
550impl From<NumericLiteral> for oxrdf::Literal {
551    fn from(n: NumericLiteral) -> Self {
552        match n {
553            NumericLiteral::Integer(i) => oxrdf::Literal::new_typed_literal(i.to_string(), oxrdf::vocab::xsd::INTEGER),
554            NumericLiteral::Decimal(d) => {
555                // Try converting to f64, otherwise use typed literal
556                match d.to_f64() {
557                    Some(decimal) => oxrdf::Literal::from(decimal),
558                    None => oxrdf::Literal::new_typed_literal(d.to_string(), oxrdf::vocab::xsd::DECIMAL),
559                }
560            },
561            NumericLiteral::Double(d) => oxrdf::Literal::from(d),
562            NumericLiteral::Long(l) => oxrdf::Literal::new_typed_literal(l.to_string(), oxrdf::vocab::xsd::LONG),
563            NumericLiteral::Float(f) => oxrdf::Literal::from(f),
564            NumericLiteral::Byte(b) => oxrdf::Literal::new_typed_literal(b.to_string(), oxrdf::vocab::xsd::BYTE),
565            NumericLiteral::Short(s) => oxrdf::Literal::from(s),
566            NumericLiteral::NonNegativeInteger(n) => {
567                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::NON_NEGATIVE_INTEGER)
568            },
569            NumericLiteral::UnsignedLong(n) => {
570                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::UNSIGNED_LONG)
571            },
572            NumericLiteral::UnsignedInt(n) => {
573                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::UNSIGNED_INT)
574            },
575            NumericLiteral::UnsignedShort(n) => {
576                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::UNSIGNED_SHORT)
577            },
578            NumericLiteral::UnsignedByte(n) => {
579                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::UNSIGNED_BYTE)
580            },
581            NumericLiteral::PositiveInteger(n) => {
582                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::POSITIVE_INTEGER)
583            },
584            NumericLiteral::NegativeInteger(n) => {
585                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::NEGATIVE_INTEGER)
586            },
587            NumericLiteral::NonPositiveInteger(n) => {
588                oxrdf::Literal::new_typed_literal(n.to_string(), oxrdf::vocab::xsd::NON_POSITIVE_INTEGER)
589            },
590        }
591    }
592}