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 { Some(*bool) } else { None }
148 }
149
150 pub fn get_integer(&self) -> Option<i64> {
151 if let Value::Integer(integer) = self { Some(*integer) } else { None }
152 }
153
154 pub fn get_double(&self) -> Option<f64> {
155 if let Value::Double(double) = self { Some(*double) } else { None }
156 }
157
158 pub fn get_string(&self) -> Option<&str> {
159 if let Value::String(string) = self { Some(&**string) } else { None }
160 }
161
162 pub fn get_decimal(&self) -> Option<Decimal> {
163 if let Value::Decimal(decimal) = self { Some(*decimal) } else { None }
164 }
165
166 pub fn get_date(&self) -> Option<NaiveDate> {
167 if let Value::Date(naive_date) = self { Some(*naive_date) } else { None }
168 }
169
170 pub fn get_datetime(&self) -> Option<NaiveDateTime> {
171 if let Value::Datetime(datetime) = self { Some(*datetime) } else { None }
172 }
173
174 pub fn get_datetime_tz(&self) -> Option<DateTime<TimeZone>> {
175 if let Value::DatetimeTZ(datetime_tz) = self { Some(*datetime_tz) } else { None }
176 }
177
178 pub fn get_duration(&self) -> Option<Duration> {
179 if let Value::Duration(duration) = self { Some(*duration) } else { None }
180 }
181
182 pub fn get_struct(&self) -> Option<&Struct> {
183 if let Value::Struct(struct_, _) = self { Some(struct_) } else { None }
184 }
185}
186
187impl fmt::Display for Value {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 match self {
190 Self::Boolean(bool) => write!(f, "{}", bool),
191 Self::Integer(integer) => write!(f, "{}", integer),
192 Self::Double(double) => write!(f, "{}", double),
193 Self::String(string) => write!(f, "\"{}\"", string),
194 Self::Decimal(decimal) => write!(f, "{}", decimal),
195 Self::Date(date) => write!(f, "{}", date.format("%Y-%m-%d")),
196 Self::Datetime(datetime) => write!(f, "{}", datetime.format("%FT%T%.9f")),
197 Self::DatetimeTZ(datetime_tz) => match datetime_tz.timezone() {
198 TimeZone::IANA(tz) => write!(f, "{} {}", datetime_tz.format("%FT%T%.9f"), tz.name()),
199 TimeZone::Fixed(_) => write!(f, "{}", datetime_tz.format("%FT%T%.9f%:z")),
200 },
201 Self::Duration(duration) => write!(f, "{}", duration),
202 Self::Struct(value, name) => write!(f, "{} {}", name, value),
203 }
204 }
205}
206
207impl fmt::Debug for Value {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 write!(f, "{}: ", self.get_type_name())?;
210 match self {
211 Value::Boolean(bool) => write!(f, "{}", bool),
212 Value::Integer(integer) => write!(f, "{}", integer),
213 Value::Double(double) => write!(f, "{}", double),
214 Value::Decimal(decimal) => write!(f, "{}", decimal),
215 Value::String(string) => write!(f, "\"{}\"", string),
216 Value::Date(date) => write!(f, "{}", date),
217 Value::Datetime(datetime) => write!(f, "{}", datetime),
218 Value::DatetimeTZ(datetime_tz) => write!(f, "{}", datetime_tz),
219 Value::Duration(duration) => write!(f, "{}", duration),
220 Value::Struct(value, name) => write!(f, "{} {}", name, value),
221 }
222 }
223}
224
225#[repr(C)]
228#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
229pub struct Decimal {
230 integer: i64,
231 fractional: u64,
232}
233
234impl Decimal {
235 const FRACTIONAL_PART_DENOMINATOR_LOG10: u32 = 19;
236 pub const FRACTIONAL_PART_DENOMINATOR: u64 = 10u64.pow(Decimal::FRACTIONAL_PART_DENOMINATOR_LOG10);
237 pub const MIN: Self = Self::new(i64::MIN, 0);
238 pub const MAX: Self = Self::new(i64::MAX, Decimal::FRACTIONAL_PART_DENOMINATOR - 1);
239
240 pub const fn new(integer: i64, fractional: u64) -> Self {
241 assert!(fractional < Decimal::FRACTIONAL_PART_DENOMINATOR);
242 Self { integer, fractional }
243 }
244
245 pub fn integer_part(&self) -> i64 {
247 self.integer
248 }
249
250 pub fn fractional_part(&self) -> u64 {
253 self.fractional
254 }
255}
256
257impl Neg for Decimal {
258 type Output = Self;
259
260 fn neg(self) -> Self::Output {
261 Self::default() - self
262 }
263}
264
265impl Add for Decimal {
266 type Output = Self;
267
268 fn add(self, rhs: Self) -> Self::Output {
269 let lhs = self;
270 let (fractional, carry) = match lhs.fractional.overflowing_add(rhs.fractional) {
271 (frac, false) if frac < Self::FRACTIONAL_PART_DENOMINATOR => (frac, 0),
272 (frac, true) if frac < Self::FRACTIONAL_PART_DENOMINATOR => {
273 (frac + 0u64.wrapping_sub(Self::FRACTIONAL_PART_DENOMINATOR), 1)
274 }
275 (frac, false) => (frac - Self::FRACTIONAL_PART_DENOMINATOR, 1),
276 (_, true) => unreachable!(),
277 };
278 let integer = lhs.integer + rhs.integer + carry;
279
280 Self::new(integer, fractional)
281 }
282}
283
284impl Sub for Decimal {
285 type Output = Self;
286
287 fn sub(self, rhs: Self) -> Self::Output {
288 let lhs = self;
289 let (fractional, carry) = match lhs.fractional.overflowing_sub(rhs.fractional) {
290 (frac, false) => (frac, 0),
291 (frac, true) => (frac.wrapping_add(Self::FRACTIONAL_PART_DENOMINATOR), 1),
292 };
293 let integer = lhs.integer - rhs.integer - carry;
294
295 Self::new(integer, fractional)
296 }
297}
298
299impl fmt::Display for Decimal {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 fmt::Debug::fmt(self, f)
302 }
303}
304
305impl fmt::Debug for Decimal {
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 if self.fractional == 0 {
308 write!(f, "{}.0", self.integer_part())?;
309 } else {
310 let mut tail_0s = 0;
312 let mut fractional = self.fractional;
313 while fractional.is_multiple_of(10) {
314 tail_0s += 1;
315 fractional /= 10;
316 }
317
318 let fractional_width = Self::FRACTIONAL_PART_DENOMINATOR_LOG10 - tail_0s;
319 write!(f, "{}.{:0width$}dec", self.integer_part(), fractional, width = fractional_width as usize)?;
320 }
321 Ok(())
322 }
323}
324
325#[derive(Copy, Clone, Debug)]
327pub enum Offset {
328 IANA(<Tz as chrono::TimeZone>::Offset),
329 Fixed(FixedOffset),
330}
331
332impl chrono::Offset for Offset {
333 fn fix(&self) -> FixedOffset {
334 match self {
335 Self::IANA(inner) => inner.fix(),
336 Self::Fixed(inner) => inner.fix(),
337 }
338 }
339}
340
341impl fmt::Display for Offset {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 match self {
344 Self::IANA(inner) => fmt::Display::fmt(inner, f),
345 Self::Fixed(inner) => fmt::Display::fmt(inner, f),
346 }
347 }
348}
349
350#[derive(Copy, Clone, Debug)]
352pub enum TimeZone {
353 IANA(Tz),
354 Fixed(FixedOffset),
355}
356
357impl Default for TimeZone {
358 fn default() -> Self {
359 Self::IANA(Tz::default())
360 }
361}
362
363impl chrono::TimeZone for TimeZone {
364 type Offset = Offset;
365
366 fn from_offset(offset: &Self::Offset) -> Self {
367 match offset {
368 Offset::IANA(offset) => Self::IANA(Tz::from_offset(offset)),
369 Offset::Fixed(offset) => Self::Fixed(FixedOffset::from_offset(offset)),
370 }
371 }
372
373 fn offset_from_local_date(&self, local: &NaiveDate) -> MappedLocalTime<Self::Offset> {
374 match self {
375 Self::IANA(inner) => inner.offset_from_local_date(local).map(Offset::IANA),
376 Self::Fixed(inner) => inner.offset_from_local_date(local).map(Offset::Fixed),
377 }
378 }
379
380 fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> MappedLocalTime<Self::Offset> {
381 match self {
382 Self::IANA(inner) => inner.offset_from_local_datetime(local).map(Offset::IANA),
383 Self::Fixed(inner) => inner.offset_from_local_datetime(local).map(Offset::Fixed),
384 }
385 }
386
387 fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset {
388 match self {
389 TimeZone::IANA(inner) => Offset::IANA(inner.offset_from_utc_date(utc)),
390 TimeZone::Fixed(inner) => Offset::Fixed(inner.offset_from_utc_date(utc)),
391 }
392 }
393
394 fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset {
395 match self {
396 TimeZone::IANA(inner) => Offset::IANA(inner.offset_from_utc_datetime(utc)),
397 TimeZone::Fixed(inner) => Offset::Fixed(inner.offset_from_utc_datetime(utc)),
398 }
399 }
400}
401
402#[repr(C)]
406#[derive(Clone, Copy, Hash, PartialEq, Eq)]
407pub struct Duration {
408 pub months: u32,
409 pub days: u32,
410 pub nanos: u64,
411}
412
413impl Duration {
414 pub const NANOS_PER_SEC: u64 = 1_000_000_000;
415 #[doc(hidden)]
416 pub const NANOS_PER_MINUTE: u64 = 60 * Self::NANOS_PER_SEC;
418 #[doc(hidden)]
419 pub const NANOS_PER_HOUR: u64 = 60 * 60 * Self::NANOS_PER_SEC;
421 pub const DAYS_PER_WEEK: u32 = 7;
422 pub const MONTHS_PER_YEAR: u32 = 12;
423
424 pub fn new(months: u32, days: u32, nanos: u64) -> Self {
425 Self { months, days, nanos }
426 }
427
428 pub fn months(&self) -> u32 {
429 self.months
430 }
431
432 pub fn days(&self) -> u32 {
433 self.days
434 }
435
436 pub fn nanos(&self) -> u64 {
437 self.nanos
438 }
439
440 fn is_empty(&self) -> bool {
441 self.months == 0 && self.days == 0 && self.nanos == 0
442 }
443}
444
445impl TryFrom<Duration> for chrono::Duration {
446 type Error = crate::Error;
447
448 fn try_from(duration: Duration) -> Result<Self, Self::Error> {
449 if duration.months != 0 || duration.days != 0 {
450 Err(Error::Other(String::from(
451 "Converting TypeDB duration to chrono::Duration is only possible when months and days are not set.",
452 )))
453 } else {
454 match i64::try_from(duration.nanos) {
455 Ok(nanos) => Ok(chrono::Duration::nanoseconds(nanos)),
456 Err(_) => {
457 Err(Error::Other(String::from("Duration u64 nanos exceeded i64 required for chrono::Duration")))
458 }
459 }
460 }
461 }
462}
463
464#[derive(Debug)]
466pub struct DurationParseError;
467
468struct Segment {
469 number: u64,
470 symbol: u8,
471 number_len: usize,
472}
473
474fn read_u32(str: &str) -> Result<(Segment, &str), DurationParseError> {
475 let mut i = 0;
476 while i + 1 < str.len() && str.as_bytes()[i].is_ascii_digit() {
477 i += 1;
478 }
479 if i == 0 {
480 return Err(DurationParseError);
481 }
482 let value = str[..i].parse().map_err(|_| DurationParseError)?;
483 Ok((Segment { number: value, symbol: str.as_bytes()[i], number_len: i }, &str[i + 1..]))
484}
485
486impl FromStr for Duration {
487 type Err = DurationParseError;
488
489 fn from_str(mut str: &str) -> Result<Self, Self::Err> {
490 let mut months = 0;
491 let mut days = 0;
492 let mut nanos = 0;
493
494 if str.as_bytes()[0] != b'P' {
495 return Err(DurationParseError);
496 }
497 str = &str[1..];
498
499 let mut parsing_time = false;
500 let mut previous_symbol = None;
501 while !str.is_empty() {
502 if str.as_bytes()[0] == b'T' {
503 parsing_time = true;
504 str = &str[1..];
505 }
506
507 let (Segment { number, symbol, number_len }, tail) = read_u32(str)?;
508 str = tail;
509
510 if previous_symbol == Some(b'.') && symbol != b'S' {
511 return Err(DurationParseError);
512 }
513
514 match symbol {
515 b'Y' => months += number as u32 * Self::MONTHS_PER_YEAR,
516 b'M' if !parsing_time => months += number as u32,
517
518 b'W' => days += number as u32 * Self::DAYS_PER_WEEK,
519 b'D' => days += number as u32,
520
521 b'H' => nanos += number * Self::NANOS_PER_HOUR,
522 b'M' if parsing_time => nanos += number * Self::NANOS_PER_MINUTE,
523 b'.' => nanos += number * Self::NANOS_PER_SEC,
524 b'S' if previous_symbol != Some(b'.') => nanos += number * Self::NANOS_PER_SEC,
525 b'S' if previous_symbol == Some(b'.') => nanos += number * 10u64.pow(9 - number_len as u32),
526 _ => return Err(DurationParseError),
527 }
528 previous_symbol = Some(symbol);
529 }
530
531 Ok(Self { months, days, nanos })
532 }
533}
534
535impl fmt::Display for Duration {
537 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538 if self.is_empty() {
539 f.write_str("PT0S")?;
540 return Ok(());
541 }
542
543 write!(f, "P")?;
544
545 if self.months > 0 || self.days > 0 {
546 let years = self.months / Self::MONTHS_PER_YEAR;
547 let months = self.months % Self::MONTHS_PER_YEAR;
548 let days = self.days;
549 if years > 0 {
550 write!(f, "{years}Y")?;
551 }
552 if months > 0 {
553 write!(f, "{months}M")?;
554 }
555 if days > 0 {
556 write!(f, "{days}D")?;
557 }
558 }
559
560 if self.nanos > 0 {
561 write!(f, "T")?;
562
563 let hours = self.nanos / Self::NANOS_PER_HOUR;
564 let minutes = (self.nanos % Self::NANOS_PER_HOUR) / Self::NANOS_PER_MINUTE;
565 let seconds = (self.nanos % Self::NANOS_PER_MINUTE) / Self::NANOS_PER_SEC;
566 let nanos = self.nanos % Self::NANOS_PER_SEC;
567
568 if hours > 0 {
569 write!(f, "{hours}H")?;
570 }
571 if minutes > 0 {
572 write!(f, "{minutes}M")?;
573 }
574 if seconds > 0 && nanos == 0 {
575 write!(f, "{seconds}S")?;
576 } else if nanos > 0 {
577 write!(f, "{seconds}.{nanos:09}S")?;
578 }
579 }
580
581 Ok(())
582 }
583}
584
585impl fmt::Debug for Duration {
586 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587 write!(f, "months: {}, days: {}, nanos: {}", self.months, self.days, self.nanos)
588 }
589}
590
591#[derive(Clone, PartialEq)]
592pub struct Struct {
593 pub(crate) fields: HashMap<String, Option<Value>>,
594}
595
596impl Struct {
597 pub fn fields(&self) -> &HashMap<String, Option<Value>> {
598 &self.fields
599 }
600}
601
602impl fmt::Display for Struct {
603 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
604 fmt::Debug::fmt(self, f)
605 }
606}
607
608impl fmt::Debug for Struct {
609 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
610 write!(f, "{:?}", self.fields)
611 }
612}