1use chrono::Offset;
2use ibig::IBig;
3use iri_string::types::{IriReferenceStr, IriReferenceString, IriString};
4use ordered_float::OrderedFloat;
5use rust_decimal::prelude::*;
6use std::cmp::Ordering;
7use std::fmt;
8use std::rc::Rc;
9use xee_xpath_ast::ast::Name;
10
11use xee_schema_type::Xs;
12
13use crate::atomic::types::{BinaryType, IntegerType, StringType};
14use crate::error;
15use crate::string::Collation;
16
17use super::datetime::{
18 Duration, GDay, GMonth, GMonthDay, GYear, GYearMonth, NaiveDateTimeWithOffset,
19 NaiveDateWithOffset, NaiveTimeWithOffset, YearMonthDuration,
20};
21use super::{op_unary, OpEq};
22use super::{AtomicCompare, OpGt};
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub enum Atomic {
35 Untyped(Rc<str>),
37 String(StringType, Rc<str>),
39 Float(OrderedFloat<f32>),
43 Double(OrderedFloat<f64>),
47 Decimal(Rc<Decimal>),
51 Integer(IntegerType, Rc<IBig>),
55 Duration(Rc<Duration>),
57 YearMonthDuration(YearMonthDuration),
59 DayTimeDuration(Rc<chrono::Duration>),
63 DateTime(Rc<NaiveDateTimeWithOffset>),
65 DateTimeStamp(Rc<chrono::DateTime<chrono::FixedOffset>>),
69 Time(Rc<NaiveTimeWithOffset>),
71 Date(Rc<NaiveDateWithOffset>),
73 GYearMonth(Rc<GYearMonth>),
75 GYear(Rc<GYear>),
77 GMonthDay(Rc<GMonthDay>),
79 GDay(Rc<GDay>),
81 GMonth(Rc<GMonth>),
83 Boolean(bool),
85 Binary(BinaryType, Rc<[u8]>),
87 QName(Rc<Name>),
89}
90
91#[cfg(target_arch = "x86_64")]
98static_assertions::assert_eq_size!(Atomic, [u8; 24]);
99
100impl Atomic {
101 pub(crate) fn effective_boolean_value(&self) -> error::Result<bool> {
116 match self {
117 Atomic::Boolean(b) => Ok(*b),
118 Atomic::String(_, s) => Ok(!s.is_empty()),
121 Atomic::Untyped(s) => Ok(!s.is_empty()),
122 Atomic::Integer(_, i) => Ok(!i.is_zero()),
124 Atomic::Decimal(d) => Ok(!d.is_zero()),
125 Atomic::Float(f) => Ok(!f.is_zero() && !f.is_nan()),
127 Atomic::Double(d) => Ok(!d.is_zero() && !d.is_nan()),
128 _ => Err(error::Error::FORG0006),
130 }
131 }
132
133 pub(crate) fn to_str(&self) -> error::Result<&str> {
136 match self {
137 Atomic::String(_, s) => Ok(s),
138 _ => Err(error::Error::XPTY0004),
139 }
140 }
141
142 pub fn to_string(&self) -> error::Result<String> {
144 Ok(self.to_str()?.to_string())
145 }
146
147 pub(crate) fn string_value(&self) -> String {
152 self.clone().into_canonical()
153 }
154
155 pub fn is_nan(&self) -> bool {
159 match self {
160 Atomic::Float(f) => f.is_nan(),
161 Atomic::Double(d) => d.is_nan(),
162 _ => false,
163 }
164 }
165
166 pub fn is_infinite(&self) -> bool {
170 match self {
171 Atomic::Float(f) => f.is_infinite(),
172 Atomic::Double(d) => d.is_infinite(),
173 _ => false,
174 }
175 }
176
177 pub fn is_zero(&self) -> bool {
181 match self {
182 Atomic::Float(f) => f.is_zero(),
183 Atomic::Double(d) => d.is_zero(),
184 Atomic::Decimal(d) => d.is_zero(),
185 Atomic::Integer(_, i) => i.is_zero(),
186 _ => false,
187 }
188 }
189
190 pub fn is_numeric(&self) -> bool {
195 matches!(
196 self,
197 Atomic::Float(_) | Atomic::Double(_) | Atomic::Decimal(_) | Atomic::Integer(_, _)
198 )
199 }
200
201 pub(crate) fn is_addable(&self) -> bool {
202 matches!(
203 self,
204 Atomic::Float(_)
205 | Atomic::Double(_)
206 | Atomic::Decimal(_)
207 | Atomic::Integer(_, _)
208 | Atomic::DayTimeDuration(_)
209 | Atomic::YearMonthDuration(_)
210 )
211 }
212
213 pub(crate) fn is_comparable(&self) -> bool {
214 matches!(
215 self,
216 Atomic::String(_, _)
217 | Atomic::Float(_)
218 | Atomic::Double(_)
219 | Atomic::Decimal(_)
220 | Atomic::Integer(_, _)
221 | Atomic::YearMonthDuration(_)
222 | Atomic::DayTimeDuration(_)
223 | Atomic::DateTime(_)
224 | Atomic::DateTimeStamp(_)
225 | Atomic::Time(_)
226 | Atomic::Date(_)
227 | Atomic::Boolean(_)
228 | Atomic::Binary(_, _)
229 )
230 }
231
232 pub(crate) fn is_true(&self) -> bool {
233 if let Atomic::Boolean(b) = self {
234 *b
235 } else {
236 false
237 }
238 }
239
240 pub(crate) fn is_untyped(&self) -> bool {
241 matches!(self, Atomic::Untyped(_))
242 }
243
244 pub(crate) fn schema_type(&self) -> Xs {
245 match self {
246 Atomic::String(string_type, _) => string_type.schema_type(),
247 Atomic::Untyped(_) => Xs::UntypedAtomic,
248 Atomic::Boolean(_) => Xs::Boolean,
249 Atomic::Decimal(_) => Xs::Decimal,
250 Atomic::Integer(integer_type, _) => integer_type.schema_type(),
251 Atomic::Float(_) => Xs::Float,
252 Atomic::Double(_) => Xs::Double,
253 Atomic::QName(_) => Xs::QName,
254 Atomic::Binary(binary_type, _) => binary_type.schema_type(),
255 Atomic::Duration(_) => Xs::Duration,
256 Atomic::YearMonthDuration(_) => Xs::YearMonthDuration,
257 Atomic::DayTimeDuration(_) => Xs::DayTimeDuration,
258 Atomic::Time(_) => Xs::Time,
259 Atomic::Date(_) => Xs::Date,
260 Atomic::DateTime(_) => Xs::DateTime,
261 Atomic::DateTimeStamp(_) => Xs::DateTimeStamp,
262 Atomic::GYearMonth(_) => Xs::GYearMonth,
263 Atomic::GYear(_) => Xs::GYear,
264 Atomic::GMonthDay(_) => Xs::GMonthDay,
265 Atomic::GMonth(_) => Xs::GMonth,
266 Atomic::GDay(_) => Xs::GDay,
267 }
268 }
269
270 pub(crate) fn ensure_base_schema_type(&self, xs: Xs) -> error::Result<()> {
271 if self.schema_type().derives_from(xs) {
272 Ok(())
273 } else {
274 Err(error::Error::XPTY0004)
275 }
276 }
277
278 pub(crate) fn derives_from(&self, other: &Atomic) -> bool {
279 self.schema_type().derives_from(other.schema_type())
280 }
281
282 pub(crate) fn has_same_schema_type(&self, other: &Atomic) -> bool {
283 self.schema_type() == other.schema_type()
284 }
285
286 pub(crate) fn plus(self) -> error::Result<Atomic> {
287 op_unary::unary_plus(self)
288 }
289
290 pub(crate) fn minus(self) -> error::Result<Atomic> {
291 op_unary::unary_minus(self)
292 }
293
294 pub fn simple_equal(&self, other: &Atomic) -> bool {
304 self.equal(other, &Collation::CodePoint, chrono::offset::Utc.fix())
305 }
306
307 pub fn equal(
309 &self,
310 other: &Atomic,
311 collation: &Collation,
312 default_offset: chrono::FixedOffset,
313 ) -> bool {
314 let equal = OpEq::atomic_compare(
316 self.clone(),
317 other.clone(),
318 |a, b| collation.compare(a, b),
319 default_offset,
320 );
321 equal.unwrap_or_default()
322 }
323
324 pub(crate) fn deep_equal(
328 &self,
329 other: &Atomic,
330 collation: &Collation,
331 default_offset: chrono::FixedOffset,
332 ) -> bool {
333 if self.is_nan() && other.is_nan() {
334 return true;
335 }
336 self.equal(other, collation, default_offset)
337 }
338
339 pub(crate) fn fallible_compare(
340 &self,
341 other: &Atomic,
342 collation: &Collation,
343 default_offset: chrono::FixedOffset,
344 ) -> error::Result<Ordering> {
345 if !self.is_comparable() || !other.is_comparable() {
346 return Err(error::Error::XPTY0004);
347 }
348 let is_equal = OpEq::atomic_compare(
349 self.clone(),
350 other.clone(),
351 |a, b| collation.compare(a, b),
352 default_offset,
353 )?;
354
355 if is_equal {
356 Ok(Ordering::Equal)
357 } else {
358 let is_greater = OpGt::atomic_compare(
359 self.clone(),
360 other.clone(),
361 |a, b| collation.compare(a, b),
362 default_offset,
363 )?;
364 if is_greater {
365 Ok(Ordering::Greater)
366 } else {
367 Ok(Ordering::Less)
368 }
369 }
370 }
371
372 pub(crate) fn compare(
378 &self,
379 other: &Atomic,
380 collation: &Collation,
381 default_offset: chrono::FixedOffset,
382 ) -> Ordering {
383 self.fallible_compare(other, collation, default_offset)
384 .unwrap_or(Ordering::Less)
385 }
386}
387
388impl fmt::Display for Atomic {
389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390 write!(
391 f,
392 "{:?} {}",
393 self.schema_type(),
394 self.clone().into_canonical()
395 )
396 }
397}
398
399impl From<String> for Atomic {
402 fn from(s: String) -> Self {
403 Atomic::String(StringType::String, s.into())
404 }
405}
406
407impl From<&str> for Atomic {
408 fn from(s: &str) -> Self {
409 Atomic::String(StringType::String, s.into())
410 }
411}
412
413impl From<&String> for Atomic {
414 fn from(s: &String) -> Self {
415 Atomic::String(StringType::String, s.clone().into())
416 }
417}
418
419impl TryFrom<Atomic> for String {
420 type Error = error::Error;
421
422 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
423 match a {
424 Atomic::String(_, s) => Ok(s.to_string()),
425 _ => Err(error::Error::XPTY0004),
426 }
427 }
428}
429
430impl From<bool> for Atomic {
433 fn from(b: bool) -> Self {
434 Atomic::Boolean(b)
435 }
436}
437
438impl TryFrom<Atomic> for bool {
439 type Error = error::Error;
440
441 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
442 match a {
443 Atomic::Boolean(b) => Ok(b),
444 _ => Err(error::Error::XPTY0004),
445 }
446 }
447}
448
449impl From<Decimal> for Atomic {
452 fn from(d: Decimal) -> Self {
453 Atomic::Decimal(d.into())
454 }
455}
456
457impl TryFrom<Atomic> for Decimal {
458 type Error = error::Error;
459
460 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
461 match a {
462 Atomic::Decimal(d) => Ok(*d.as_ref()),
463 _ => Err(error::Error::XPTY0004),
464 }
465 }
466}
467
468impl From<IriString> for Atomic {
471 fn from(u: IriString) -> Self {
472 Atomic::String(StringType::AnyURI, u.to_string().into())
473 }
474}
475
476impl From<IriReferenceString> for Atomic {
477 fn from(u: IriReferenceString) -> Self {
478 Atomic::String(StringType::AnyURI, u.to_string().into())
479 }
480}
481
482impl From<&IriReferenceStr> for Atomic {
483 fn from(u: &IriReferenceStr) -> Self {
484 Atomic::String(StringType::AnyURI, u.to_string().into())
485 }
486}
487
488impl TryFrom<Atomic> for IriReferenceString {
489 type Error = error::Error;
490
491 fn try_from(a: Atomic) -> Result<Self, error::Error> {
492 match a {
493 Atomic::String(_, s) => {
494 Ok(s.as_ref().try_into().map_err(|_| error::Error::FORG0002)?)
495 }
496 _ => Err(error::Error::XPTY0004),
497 }
498 }
499}
500
501impl From<IBig> for Atomic {
504 fn from(i: IBig) -> Self {
505 Atomic::Integer(IntegerType::Integer, i.into())
506 }
507}
508
509impl From<Rc<IBig>> for Atomic {
510 fn from(i: Rc<IBig>) -> Self {
511 Atomic::Integer(IntegerType::Integer, i)
512 }
513}
514
515impl TryFrom<Atomic> for Rc<IBig> {
516 type Error = error::Error;
517
518 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
519 match a {
520 Atomic::Integer(_, i) => Ok(i),
521 _ => Err(error::Error::XPTY0004),
522 }
523 }
524}
525
526impl TryFrom<Atomic> for IBig {
527 type Error = error::Error;
528
529 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
530 match a {
531 Atomic::Integer(_, i) => Ok(i.as_ref().clone()),
532 _ => Err(error::Error::XPTY0004),
533 }
534 }
535}
536
537impl From<i64> for Atomic {
538 fn from(i: i64) -> Self {
539 let i: IBig = i.into();
540 Atomic::Integer(IntegerType::Long, i.into())
541 }
542}
543
544impl TryFrom<Atomic> for i64 {
545 type Error = error::Error;
546
547 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
548 match a {
549 Atomic::Integer(IntegerType::Long, i) => Ok(i.as_ref().clone().try_into()?),
550 _ => Err(error::Error::XPTY0004),
551 }
552 }
553}
554
555impl From<i32> for Atomic {
556 fn from(i: i32) -> Self {
557 let i: IBig = i.into();
558 Atomic::Integer(IntegerType::Int, i.into())
559 }
560}
561
562impl TryFrom<Atomic> for i32 {
563 type Error = error::Error;
564
565 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
566 match a {
567 Atomic::Integer(IntegerType::Int, i) => Ok(i.as_ref().clone().try_into()?),
568 _ => Err(error::Error::XPTY0004),
569 }
570 }
571}
572
573impl From<i16> for Atomic {
574 fn from(i: i16) -> Self {
575 let i: IBig = i.into();
576 Atomic::Integer(IntegerType::Short, i.into())
577 }
578}
579
580impl TryFrom<Atomic> for i16 {
581 type Error = error::Error;
582
583 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
584 match a {
585 Atomic::Integer(IntegerType::Short, i) => Ok(i.as_ref().clone().try_into()?),
586 _ => Err(error::Error::XPTY0004),
587 }
588 }
589}
590
591impl From<i8> for Atomic {
592 fn from(i: i8) -> Self {
593 let i: IBig = i.into();
594 Atomic::Integer(IntegerType::Byte, i.into())
595 }
596}
597
598impl TryFrom<Atomic> for i8 {
599 type Error = error::Error;
600
601 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
602 match a {
603 Atomic::Integer(IntegerType::Byte, i) => Ok(i.as_ref().clone().try_into()?),
604 _ => Err(error::Error::XPTY0004),
605 }
606 }
607}
608
609impl From<u64> for Atomic {
610 fn from(i: u64) -> Self {
611 let i: IBig = i.into();
612 Atomic::Integer(IntegerType::UnsignedLong, i.into())
613 }
614}
615
616impl TryFrom<Atomic> for u64 {
617 type Error = error::Error;
618
619 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
620 match a {
621 Atomic::Integer(IntegerType::UnsignedLong, i) => Ok(i.as_ref().clone().try_into()?),
622 _ => Err(error::Error::XPTY0004),
623 }
624 }
625}
626
627impl From<u32> for Atomic {
628 fn from(i: u32) -> Self {
629 let i: IBig = i.into();
630 Atomic::Integer(IntegerType::UnsignedInt, i.into())
631 }
632}
633
634impl TryFrom<Atomic> for u32 {
635 type Error = error::Error;
636
637 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
638 match a {
639 Atomic::Integer(IntegerType::UnsignedInt, i) => Ok(i.as_ref().clone().try_into()?),
640 _ => Err(error::Error::XPTY0004),
641 }
642 }
643}
644
645impl From<u16> for Atomic {
646 fn from(i: u16) -> Self {
647 let i: IBig = i.into();
648 Atomic::Integer(IntegerType::UnsignedShort, i.into())
649 }
650}
651
652impl TryFrom<Atomic> for u16 {
653 type Error = error::Error;
654
655 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
656 match a {
657 Atomic::Integer(IntegerType::UnsignedShort, i) => Ok(i.as_ref().clone().try_into()?),
658 _ => Err(error::Error::XPTY0004),
659 }
660 }
661}
662
663impl From<u8> for Atomic {
664 fn from(i: u8) -> Self {
665 let i: IBig = i.into();
666 Atomic::Integer(IntegerType::UnsignedByte, i.into())
667 }
668}
669
670impl TryFrom<Atomic> for u8 {
671 type Error = error::Error;
672
673 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
674 match a {
675 Atomic::Integer(IntegerType::UnsignedByte, i) => Ok(i.as_ref().clone().try_into()?),
676 _ => Err(error::Error::XPTY0004),
677 }
678 }
679}
680
681impl From<f32> for Atomic {
684 fn from(f: f32) -> Self {
685 Atomic::Float(OrderedFloat(f))
686 }
687}
688
689impl From<OrderedFloat<f32>> for Atomic {
690 fn from(f: OrderedFloat<f32>) -> Self {
691 Atomic::Float(f)
692 }
693}
694
695impl TryFrom<Atomic> for f32 {
696 type Error = error::Error;
697
698 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
699 match a {
700 Atomic::Float(f) => Ok(f.into_inner()),
701 Atomic::Decimal(_) | Atomic::Integer(_, _) => {
703 let f: f32 = a.cast_to_float()?.try_into()?;
704 Ok(f)
705 }
706 _ => Err(error::Error::XPTY0004),
707 }
708 }
709}
710
711impl From<f64> for Atomic {
712 fn from(f: f64) -> Self {
713 Atomic::Double(OrderedFloat(f))
714 }
715}
716
717impl From<OrderedFloat<f64>> for Atomic {
718 fn from(f: OrderedFloat<f64>) -> Self {
719 Atomic::Double(f)
720 }
721}
722
723impl TryFrom<Atomic> for f64 {
724 type Error = error::Error;
725
726 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
727 match a {
728 Atomic::Double(f) => Ok(f.into_inner()),
729 Atomic::Float(f) => Ok(f.into_inner() as f64),
731 Atomic::Decimal(_) | Atomic::Integer(_, _) => {
732 let f: f64 = a.cast_to_double()?.try_into()?;
733 Ok(f)
734 }
735 _ => Err(error::Error::XPTY0004),
736 }
737 }
738}
739
740impl From<Name> for Atomic {
741 fn from(n: Name) -> Self {
742 Atomic::QName(n.into())
743 }
744}
745
746impl TryFrom<Atomic> for Name {
747 type Error = error::Error;
748
749 fn try_from(a: Atomic) -> Result<Self, Self::Error> {
750 match a {
751 Atomic::QName(n) => Ok(n.as_ref().clone()),
752 _ => Err(error::Error::XPTY0004),
753 }
754 }
755}