1use std::{
21 collections::HashMap,
22 fmt,
23 ops::{Add, Neg, Sub},
24 str::FromStr,
25};
26
27use chrono::{DateTime, FixedOffset, MappedLocalTime, NaiveDate, NaiveDateTime};
28use chrono_tz::Tz;
29
30use crate::Error;
31
32#[derive(Clone, PartialEq, Eq)]
34pub enum ValueType {
35 Boolean,
36 Integer,
37 Double,
38 Decimal,
39 String,
40 Date,
41 Datetime,
42 DatetimeTZ,
43 Duration,
44 Struct(String),
45}
46
47impl ValueType {
48 pub(crate) const NONE_STR: &'static str = "none";
49 pub(crate) const BOOLEAN_STR: &'static str = "boolean";
50 pub(crate) const INTEGER_STR: &'static str = "integer";
51 pub(crate) const DOUBLE_STR: &'static str = "double";
52 pub(crate) const DECIMAL_STR: &'static str = "decimal";
53 pub(crate) const STRING_STR: &'static str = "string";
54 pub(crate) const DATE_STR: &'static str = "date";
55 pub(crate) const DATETIME_STR: &'static str = "datetime";
56 pub(crate) const DATETIME_TZ_STR: &'static str = "datetime-tz";
57 pub(crate) const DURATION_STR: &'static str = "duration";
58
59 pub fn name(&self) -> &str {
60 match self {
61 Self::Boolean => Self::BOOLEAN_STR,
62 Self::Integer => Self::INTEGER_STR,
63 Self::Double => Self::DOUBLE_STR,
64 Self::Decimal => Self::DECIMAL_STR,
65 Self::String => Self::STRING_STR,
66 Self::Date => Self::DATE_STR,
67 Self::Datetime => Self::DATETIME_STR,
68 Self::DatetimeTZ => Self::DATETIME_TZ_STR,
69 Self::Duration => Self::DURATION_STR,
70 Self::Struct(name) => &name,
71 }
72 }
73}
74
75impl fmt::Display for ValueType {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 fmt::Debug::fmt(self, f)
78 }
79}
80
81impl fmt::Debug for ValueType {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(f, "{}", self.name())
84 }
85}
86
87#[derive(Clone, PartialEq)]
88pub enum Value {
89 Boolean(bool),
90 Integer(i64),
91 Double(f64),
92 Decimal(Decimal),
93 String(String),
94 Date(NaiveDate),
95 Datetime(NaiveDateTime),
96 DatetimeTZ(DateTime<TimeZone>),
97 Duration(Duration),
98 Struct(Struct, String),
99}
100
101impl Value {
102 pub fn get_type(&self) -> ValueType {
110 match self {
111 Self::Boolean(_) => ValueType::Boolean,
112 Self::Integer(_) => ValueType::Integer,
113 Self::Double(_) => ValueType::Double,
114 Self::String(_) => ValueType::String,
115 Self::Decimal(_) => ValueType::Decimal,
116 Self::Date(_) => ValueType::Date,
117 Self::Datetime(_) => ValueType::Datetime,
118 Self::DatetimeTZ(_) => ValueType::DatetimeTZ,
119 Self::Duration(_) => ValueType::Duration,
120 Self::Struct(_, struct_type_name) => ValueType::Struct(struct_type_name.clone()),
121 }
122 }
123
124 pub fn get_type_name(&self) -> &str {
132 match self {
133 Self::Boolean(_) => ValueType::Boolean.name(),
134 Self::Integer(_) => ValueType::Integer.name(),
135 Self::Double(_) => ValueType::Double.name(),
136 Self::String(_) => ValueType::String.name(),
137 Self::Decimal(_) => ValueType::Decimal.name(),
138 Self::Date(_) => ValueType::Date.name(),
139 Self::Datetime(_) => ValueType::Datetime.name(),
140 Self::DatetimeTZ(_) => ValueType::DatetimeTZ.name(),
141 Self::Duration(_) => ValueType::Duration.name(),
142 Self::Struct(_, struct_type_name) => struct_type_name,
143 }
144 }
145
146 pub fn get_boolean(&self) -> Option<bool> {
147 if let Value::Boolean(bool) = self {
148 Some(*bool)
149 } else {
150 None
151 }
152 }
153
154 pub fn get_integer(&self) -> Option<i64> {
155 if let Value::Integer(integer) = self {
156 Some(*integer)
157 } else {
158 None
159 }
160 }
161
162 pub fn get_double(&self) -> Option<f64> {
163 if let Value::Double(double) = self {
164 Some(*double)
165 } else {
166 None
167 }
168 }
169
170 pub fn get_string(&self) -> Option<&str> {
171 if let Value::String(string) = self {
172 Some(&**string)
173 } else {
174 None
175 }
176 }
177
178 pub fn get_decimal(&self) -> Option<Decimal> {
179 if let Value::Decimal(decimal) = self {
180 Some(*decimal)
181 } else {
182 None
183 }
184 }
185
186 pub fn get_date(&self) -> Option<NaiveDate> {
187 if let Value::Date(naive_date) = self {
188 Some(*naive_date)
189 } else {
190 None
191 }
192 }
193
194 pub fn get_datetime(&self) -> Option<NaiveDateTime> {
195 if let Value::Datetime(datetime) = self {
196 Some(*datetime)
197 } else {
198 None
199 }
200 }
201
202 pub fn get_datetime_tz(&self) -> Option<DateTime<TimeZone>> {
203 if let Value::DatetimeTZ(datetime_tz) = self {
204 Some(*datetime_tz)
205 } else {
206 None
207 }
208 }
209
210 pub fn get_duration(&self) -> Option<Duration> {
211 if let Value::Duration(duration) = self {
212 Some(*duration)
213 } else {
214 None
215 }
216 }
217
218 pub fn get_struct(&self) -> Option<&Struct> {
219 if let Value::Struct(struct_, _) = self {
220 Some(struct_)
221 } else {
222 None
223 }
224 }
225}
226
227impl fmt::Display for Value {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 match self {
230 Self::Boolean(bool) => write!(f, "{}", bool),
231 Self::Integer(integer) => write!(f, "{}", integer),
232 Self::Double(double) => write!(f, "{}", double),
233 Self::String(string) => write!(f, "\"{}\"", string),
234 Self::Decimal(decimal) => write!(f, "{}", decimal),
235 Self::Date(date) => write!(f, "{}", date.format("%Y-%m-%d")),
236 Self::Datetime(datetime) => write!(f, "{}", datetime.format("%FT%T%.9f")),
237 Self::DatetimeTZ(datetime_tz) => match datetime_tz.timezone() {
238 TimeZone::IANA(tz) => write!(f, "{} {}", datetime_tz.format("%FT%T%.9f"), tz.name()),
239 TimeZone::Fixed(_) => write!(f, "{}", datetime_tz.format("%FT%T%.9f%:z")),
240 },
241 Self::Duration(duration) => write!(f, "{}", duration),
242 Self::Struct(value, name) => write!(f, "{} {}", name, value),
243 }
244 }
245}
246
247impl fmt::Debug for Value {
248 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249 write!(f, "{}: ", self.get_type_name())?;
250 match self {
251 Value::Boolean(bool) => write!(f, "{}", bool),
252 Value::Integer(integer) => write!(f, "{}", integer),
253 Value::Double(double) => write!(f, "{}", double),
254 Value::Decimal(decimal) => write!(f, "{}", decimal),
255 Value::String(string) => write!(f, "\"{}\"", string),
256 Value::Date(date) => write!(f, "{}", date),
257 Value::Datetime(datetime) => write!(f, "{}", datetime),
258 Value::DatetimeTZ(datetime_tz) => write!(f, "{}", datetime_tz),
259 Value::Duration(duration) => write!(f, "{}", duration),
260 Value::Struct(value, name) => write!(f, "{} {}", name, value),
261 }
262 }
263}
264
265#[repr(C)]
268#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
269pub struct Decimal {
270 integer: i64,
271 fractional: u64,
272}
273
274impl Decimal {
275 const FRACTIONAL_PART_DENOMINATOR_LOG10: u32 = 19;
276 pub const FRACTIONAL_PART_DENOMINATOR: u64 = 10u64.pow(Decimal::FRACTIONAL_PART_DENOMINATOR_LOG10);
277 pub const MIN: Self = Self::new(i64::MIN, 0);
278 pub const MAX: Self = Self::new(i64::MAX, Decimal::FRACTIONAL_PART_DENOMINATOR - 1);
279
280 pub const fn new(integer: i64, fractional: u64) -> Self {
281 assert!(fractional < Decimal::FRACTIONAL_PART_DENOMINATOR);
282 Self { integer, fractional }
283 }
284
285 pub fn integer_part(&self) -> i64 {
287 self.integer
288 }
289
290 pub fn fractional_part(&self) -> u64 {
293 self.fractional
294 }
295}
296
297impl Neg for Decimal {
298 type Output = Self;
299
300 fn neg(self) -> Self::Output {
301 Self::default() - self
302 }
303}
304
305impl Add for Decimal {
306 type Output = Self;
307
308 fn add(self, rhs: Self) -> Self::Output {
309 let lhs = self;
310 let (fractional, carry) = match lhs.fractional.overflowing_add(rhs.fractional) {
311 (frac, false) if frac < Self::FRACTIONAL_PART_DENOMINATOR => (frac, 0),
312 (frac, true) if frac < Self::FRACTIONAL_PART_DENOMINATOR => {
313 (frac + 0u64.wrapping_sub(Self::FRACTIONAL_PART_DENOMINATOR), 1)
314 }
315 (frac, false) => (frac - Self::FRACTIONAL_PART_DENOMINATOR, 1),
316 (_, true) => unreachable!(),
317 };
318 let integer = lhs.integer + rhs.integer + carry;
319
320 Self::new(integer, fractional)
321 }
322}
323
324impl Sub for Decimal {
325 type Output = Self;
326
327 fn sub(self, rhs: Self) -> Self::Output {
328 let lhs = self;
329 let (fractional, carry) = match lhs.fractional.overflowing_sub(rhs.fractional) {
330 (frac, false) => (frac, 0),
331 (frac, true) => (frac.wrapping_add(Self::FRACTIONAL_PART_DENOMINATOR), 1),
332 };
333 let integer = lhs.integer - rhs.integer - carry;
334
335 Self::new(integer, fractional)
336 }
337}
338
339impl fmt::Display for Decimal {
340 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341 fmt::Debug::fmt(self, f)
342 }
343}
344
345impl fmt::Debug for Decimal {
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 if self.fractional == 0 {
348 write!(f, "{}.0", self.integer_part())?;
349 } else {
350 let mut tail_0s = 0;
352 let mut fractional = self.fractional;
353 while fractional % 10 == 0 {
354 tail_0s += 1;
355 fractional /= 10;
356 }
357
358 let fractional_width = Self::FRACTIONAL_PART_DENOMINATOR_LOG10 - tail_0s;
359 write!(f, "{}.{:0width$}dec", self.integer_part(), fractional, width = fractional_width as usize)?;
360 }
361 Ok(())
362 }
363}
364
365#[derive(Copy, Clone, Debug)]
367pub enum Offset {
368 IANA(<Tz as chrono::TimeZone>::Offset),
369 Fixed(FixedOffset),
370}
371
372impl chrono::Offset for Offset {
373 fn fix(&self) -> FixedOffset {
374 match self {
375 Self::IANA(inner) => inner.fix(),
376 Self::Fixed(inner) => inner.fix(),
377 }
378 }
379}
380
381impl fmt::Display for Offset {
382 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383 match self {
384 Self::IANA(inner) => fmt::Display::fmt(inner, f),
385 Self::Fixed(inner) => fmt::Display::fmt(inner, f),
386 }
387 }
388}
389
390#[derive(Copy, Clone, Debug)]
392pub enum TimeZone {
393 IANA(Tz),
394 Fixed(FixedOffset),
395}
396
397impl Default for TimeZone {
398 fn default() -> Self {
399 Self::IANA(Tz::default())
400 }
401}
402
403impl chrono::TimeZone for TimeZone {
404 type Offset = Offset;
405
406 fn from_offset(offset: &Self::Offset) -> Self {
407 match offset {
408 Offset::IANA(offset) => Self::IANA(Tz::from_offset(offset)),
409 Offset::Fixed(offset) => Self::Fixed(FixedOffset::from_offset(offset)),
410 }
411 }
412
413 fn offset_from_local_date(&self, local: &NaiveDate) -> MappedLocalTime<Self::Offset> {
414 match self {
415 Self::IANA(inner) => inner.offset_from_local_date(local).map(Offset::IANA),
416 Self::Fixed(inner) => inner.offset_from_local_date(local).map(Offset::Fixed),
417 }
418 }
419
420 fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> MappedLocalTime<Self::Offset> {
421 match self {
422 Self::IANA(inner) => inner.offset_from_local_datetime(local).map(Offset::IANA),
423 Self::Fixed(inner) => inner.offset_from_local_datetime(local).map(Offset::Fixed),
424 }
425 }
426
427 fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset {
428 match self {
429 TimeZone::IANA(inner) => Offset::IANA(inner.offset_from_utc_date(utc)),
430 TimeZone::Fixed(inner) => Offset::Fixed(inner.offset_from_utc_date(utc)),
431 }
432 }
433
434 fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset {
435 match self {
436 TimeZone::IANA(inner) => Offset::IANA(inner.offset_from_utc_datetime(utc)),
437 TimeZone::Fixed(inner) => Offset::Fixed(inner.offset_from_utc_datetime(utc)),
438 }
439 }
440}
441
442#[repr(C)]
446#[derive(Clone, Copy, Hash, PartialEq, Eq)]
447pub struct Duration {
448 pub months: u32,
449 pub days: u32,
450 pub nanos: u64,
451}
452
453impl Duration {
454 const NANOS_PER_SEC: u64 = 1_000_000_000;
455 const NANOS_PER_MINUTE: u64 = 60 * Self::NANOS_PER_SEC;
456 const NANOS_PER_HOUR: u64 = 60 * 60 * Self::NANOS_PER_SEC;
457 const DAYS_PER_WEEK: u32 = 7;
458 const MONTHS_PER_YEAR: u32 = 12;
459
460 pub fn new(months: u32, days: u32, nanos: u64) -> Self {
461 Self { months, days, nanos }
462 }
463
464 pub fn months(&self) -> u32 {
465 self.months
466 }
467
468 pub fn days(&self) -> u32 {
469 self.days
470 }
471
472 pub fn nanos(&self) -> u64 {
473 self.nanos
474 }
475
476 fn is_empty(&self) -> bool {
477 self.months == 0 && self.days == 0 && self.nanos == 0
478 }
479}
480
481impl TryFrom<Duration> for chrono::Duration {
482 type Error = crate::Error;
483
484 fn try_from(duration: Duration) -> Result<Self, Self::Error> {
485 if duration.months != 0 || duration.days != 0 {
486 Err(Error::Other(String::from(
487 "Converting TypeDB duration to chrono::Duration is only possible when months and days are not set.",
488 )))
489 } else {
490 match i64::try_from(duration.nanos) {
491 Ok(nanos) => Ok(chrono::Duration::nanoseconds(nanos)),
492 Err(_) => {
493 Err(Error::Other(String::from("Duration u64 nanos exceeded i64 required for chrono::Duration")))
494 }
495 }
496 }
497 }
498}
499
500#[derive(Debug)]
502pub struct DurationParseError;
503
504struct Segment {
505 number: u64,
506 symbol: u8,
507 number_len: usize,
508}
509
510fn read_u32(str: &str) -> Result<(Segment, &str), DurationParseError> {
511 let mut i = 0;
512 while i + 1 < str.len() && str.as_bytes()[i].is_ascii_digit() {
513 i += 1;
514 }
515 if i == 0 {
516 return Err(DurationParseError);
517 }
518 let value = str[..i].parse().map_err(|_| DurationParseError)?;
519 Ok((Segment { number: value, symbol: str.as_bytes()[i], number_len: i }, &str[i + 1..]))
520}
521
522impl FromStr for Duration {
523 type Err = DurationParseError;
524
525 fn from_str(mut str: &str) -> Result<Self, Self::Err> {
526 let mut months = 0;
527 let mut days = 0;
528 let mut nanos = 0;
529
530 if str.as_bytes()[0] != b'P' {
531 return Err(DurationParseError);
532 }
533 str = &str[1..];
534
535 let mut parsing_time = false;
536 let mut previous_symbol = None;
537 while !str.is_empty() {
538 if str.as_bytes()[0] == b'T' {
539 parsing_time = true;
540 str = &str[1..];
541 }
542
543 let (Segment { number, symbol, number_len }, tail) = read_u32(str)?;
544 str = tail;
545
546 if previous_symbol == Some(b'.') && symbol != b'S' {
547 return Err(DurationParseError);
548 }
549
550 match symbol {
551 b'Y' => months += number as u32 * Self::MONTHS_PER_YEAR,
552 b'M' if !parsing_time => months += number as u32,
553
554 b'W' => days += number as u32 * Self::DAYS_PER_WEEK,
555 b'D' => days += number as u32,
556
557 b'H' => nanos += number * Self::NANOS_PER_HOUR,
558 b'M' if parsing_time => nanos += number * Self::NANOS_PER_MINUTE,
559 b'.' => nanos += number * Self::NANOS_PER_SEC,
560 b'S' if previous_symbol != Some(b'.') => nanos += number * Self::NANOS_PER_SEC,
561 b'S' if previous_symbol == Some(b'.') => nanos += number * 10u64.pow(9 - number_len as u32),
562 _ => return Err(DurationParseError),
563 }
564 previous_symbol = Some(symbol);
565 }
566
567 Ok(Self { months, days, nanos })
568 }
569}
570
571impl fmt::Display for Duration {
573 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
574 if self.is_empty() {
575 f.write_str("PT0S")?;
576 return Ok(());
577 }
578
579 write!(f, "P")?;
580
581 if self.months > 0 || self.days > 0 {
582 let years = self.months / Self::MONTHS_PER_YEAR;
583 let months = self.months % Self::MONTHS_PER_YEAR;
584 let days = self.days;
585 if years > 0 {
586 write!(f, "{years}Y")?;
587 }
588 if months > 0 {
589 write!(f, "{months}M")?;
590 }
591 if days > 0 {
592 write!(f, "{days}D")?;
593 }
594 }
595
596 if self.nanos > 0 {
597 write!(f, "T")?;
598
599 let hours = self.nanos / Self::NANOS_PER_HOUR;
600 let minutes = (self.nanos % Self::NANOS_PER_HOUR) / Self::NANOS_PER_MINUTE;
601 let seconds = (self.nanos % Self::NANOS_PER_MINUTE) / Self::NANOS_PER_SEC;
602 let nanos = self.nanos % Self::NANOS_PER_SEC;
603
604 if hours > 0 {
605 write!(f, "{hours}H")?;
606 }
607 if minutes > 0 {
608 write!(f, "{minutes}M")?;
609 }
610 if seconds > 0 && nanos == 0 {
611 write!(f, "{seconds}S")?;
612 } else if nanos > 0 {
613 write!(f, "{seconds}.{nanos:09}S")?;
614 }
615 }
616
617 Ok(())
618 }
619}
620
621impl fmt::Debug for Duration {
622 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
623 write!(f, "months: {}, days: {}, nanos: {}", self.months, self.days, self.nanos)
624 }
625}
626
627#[derive(Clone, PartialEq)]
628pub struct Struct {
629 pub(crate) fields: HashMap<String, Option<Value>>,
630}
631
632impl Struct {
633 pub fn fields(&self) -> &HashMap<String, Option<Value>> {
634 &self.fields
635 }
636}
637
638impl fmt::Display for Struct {
639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640 fmt::Debug::fmt(self, f)
641 }
642}
643
644impl fmt::Debug for Struct {
645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
646 write!(f, "{:?}", self.fields)
647 }
648}