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#[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
38macro_rules! impl_decimal_from {
40 ($name:ident, $type:ty, $from_method:ident) => {
41 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
55impl NumericLiteral {
57 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 pub fn decimal(d: Decimal) -> NumericLiteral {
82 NumericLiteral::Decimal(d)
83 }
84
85 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 pub fn non_negative_integer(n: u128) -> NumericLiteral {
100 NumericLiteral::NonNegativeInteger(n)
101 }
102
103 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 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 pub fn unsigned_byte(n: u8) -> NumericLiteral {
131 NumericLiteral::UnsignedByte(n)
132 }
133
134 pub fn unsigned_short(n: u16) -> NumericLiteral {
136 NumericLiteral::UnsignedShort(n)
137 }
138
139 pub fn unsigned_int(n: u32) -> NumericLiteral {
141 NumericLiteral::UnsignedInt(n)
142 }
143
144 pub fn unsigned_long(n: u64) -> NumericLiteral {
146 NumericLiteral::UnsignedLong(n)
147 }
148
149 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 pub fn byte(d: i8) -> NumericLiteral {
161 NumericLiteral::Byte(d)
162 }
163
164 pub fn short(d: i16) -> NumericLiteral {
166 NumericLiteral::Short(d)
167 }
168
169 pub fn long(d: i64) -> NumericLiteral {
171 NumericLiteral::Long(d)
172 }
173
174 pub fn float(d: f32) -> NumericLiteral {
176 NumericLiteral::Float(d)
177 }
178
179 pub fn integer(n: i128) -> NumericLiteral {
181 NumericLiteral::Integer(n)
182 }
183
184 pub fn double(d: f64) -> NumericLiteral {
186 NumericLiteral::Double(d)
187 }
188}
189
190impl NumericLiteral {
192 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 pub fn integer_from_i64(d: i64) -> NumericLiteral {
205 NumericLiteral::Integer(d as i128)
206 }
207
208 pub fn integer_from_i128(d: i128) -> NumericLiteral {
210 NumericLiteral::Integer(d)
211 }
212
213 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
238impl NumericLiteral {
240 pub fn lexical_form(&self) -> String {
244 self.to_string()
245 }
246
247 pub fn less_than(&self, other: &NumericLiteral) -> bool {
252 match (self, other) {
253 (NumericLiteral::Integer(n1), NumericLiteral::Integer(n2)) => n1 < n2,
255 (v1, v2) => v1.to_decimal() < v2.to_decimal(),
257 }
258 }
259
260 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 pub fn total_digits(&self) -> Option<usize> {
273 let digits = match self {
274 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 NumericLiteral::Decimal(d) => {
325 let normalized = d.normalize();
326 normalized.to_string().chars().filter(|c| c.is_ascii_digit()).count()
327 },
328 NumericLiteral::Double(_) | NumericLiteral::Float(_) => return None,
330 };
331
332 Some(digits)
333 }
334
335 pub fn fraction_digits(&self) -> Option<usize> {
340 match self {
341 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 NumericLiteral::Decimal(d) => {
356 let s = d.to_string();
357 Some(s.find('.').map_or(0, |pos| s.len() - pos - 1))
358 },
359 NumericLiteral::Double(_) | NumericLiteral::Float(_) => None,
361 }
362 }
363}
364
365impl Eq for NumericLiteral {}
374
375impl PartialEq for NumericLiteral {
377 fn eq(&self, other: &Self) -> bool {
378 if let (Some(d1), Some(d2)) = (self.to_decimal(), other.to_decimal()) {
380 return d1 == d2;
381 }
382
383 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 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
411impl Hash for NumericLiteral {
413 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
414 if let Some(d) = self.to_decimal() {
416 d.normalize().hash(state);
418 return;
419 }
420
421 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 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
455impl 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 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
487impl 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
510impl PartialOrd for NumericLiteral {
512 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
521impl TryFrom<&str> for NumericLiteral {
529 type Error = String;
530
531 fn try_from(value: &str) -> Result<Self, Self::Error> {
532 if let Ok(i) = value.parse::<i128>() {
534 return Ok(NumericLiteral::Integer(i));
535 }
536 if let Ok(f) = value.parse::<f64>() {
538 return Ok(NumericLiteral::Double(f));
539 }
540 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
549impl 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 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}