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 pub integer: i64,
232 pub fractional: u64,
235}
236
237impl Decimal {
238 const FRACTIONAL_PART_DENOMINATOR_LOG10: u32 = 19;
239 pub const FRACTIONAL_PART_DENOMINATOR: u64 = 10u64.pow(Decimal::FRACTIONAL_PART_DENOMINATOR_LOG10);
240 pub const MIN: Self = Self::new(i64::MIN, 0);
241 pub const MAX: Self = Self::new(i64::MAX, Decimal::FRACTIONAL_PART_DENOMINATOR - 1);
242
243 pub const fn new(integer: i64, fractional: u64) -> Self {
244 assert!(fractional < Decimal::FRACTIONAL_PART_DENOMINATOR);
245 Self { integer, fractional }
246 }
247}
248
249impl Neg for Decimal {
250 type Output = Self;
251
252 fn neg(self) -> Self::Output {
253 Self::default() - self
254 }
255}
256
257impl Add for Decimal {
258 type Output = Self;
259
260 fn add(self, rhs: Self) -> Self::Output {
261 let lhs = self;
262 let (fractional, carry) = match lhs.fractional.overflowing_add(rhs.fractional) {
263 (frac, false) if frac < Self::FRACTIONAL_PART_DENOMINATOR => (frac, 0),
264 (frac, true) if frac < Self::FRACTIONAL_PART_DENOMINATOR => {
265 (frac + 0u64.wrapping_sub(Self::FRACTIONAL_PART_DENOMINATOR), 1)
266 }
267 (frac, false) => (frac - Self::FRACTIONAL_PART_DENOMINATOR, 1),
268 (_, true) => unreachable!(),
269 };
270 let integer = lhs.integer + rhs.integer + carry;
271
272 Self::new(integer, fractional)
273 }
274}
275
276impl Sub for Decimal {
277 type Output = Self;
278
279 fn sub(self, rhs: Self) -> Self::Output {
280 let lhs = self;
281 let (fractional, carry) = match lhs.fractional.overflowing_sub(rhs.fractional) {
282 (frac, false) => (frac, 0),
283 (frac, true) => (frac.wrapping_add(Self::FRACTIONAL_PART_DENOMINATOR), 1),
284 };
285 let integer = lhs.integer - rhs.integer - carry;
286
287 Self::new(integer, fractional)
288 }
289}
290
291impl fmt::Display for Decimal {
292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 fmt::Debug::fmt(self, f)
294 }
295}
296
297impl fmt::Debug for Decimal {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 if self.fractional == 0 {
300 write!(f, "{}.0", self.integer)?;
301 } else {
302 let mut tail_0s = 0;
304 let mut fractional = self.fractional;
305 while fractional.is_multiple_of(10) {
306 tail_0s += 1;
307 fractional /= 10;
308 }
309
310 let fractional_width = Self::FRACTIONAL_PART_DENOMINATOR_LOG10 - tail_0s;
311 write!(f, "{}.{:0width$}dec", self.integer, fractional, width = fractional_width as usize)?;
312 }
313 Ok(())
314 }
315}
316
317#[derive(Copy, Clone, Debug)]
319pub enum Offset {
320 IANA(<Tz as chrono::TimeZone>::Offset),
321 Fixed(FixedOffset),
322}
323
324impl chrono::Offset for Offset {
325 fn fix(&self) -> FixedOffset {
326 match self {
327 Self::IANA(inner) => inner.fix(),
328 Self::Fixed(inner) => inner.fix(),
329 }
330 }
331}
332
333impl fmt::Display for Offset {
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 match self {
336 Self::IANA(inner) => fmt::Display::fmt(inner, f),
337 Self::Fixed(inner) => fmt::Display::fmt(inner, f),
338 }
339 }
340}
341
342#[derive(Copy, Clone, Debug)]
344pub enum TimeZone {
345 IANA(Tz),
346 Fixed(FixedOffset),
347}
348
349impl Default for TimeZone {
350 fn default() -> Self {
351 Self::IANA(Tz::default())
352 }
353}
354
355impl chrono::TimeZone for TimeZone {
356 type Offset = Offset;
357
358 fn from_offset(offset: &Self::Offset) -> Self {
359 match offset {
360 Offset::IANA(offset) => Self::IANA(Tz::from_offset(offset)),
361 Offset::Fixed(offset) => Self::Fixed(FixedOffset::from_offset(offset)),
362 }
363 }
364
365 fn offset_from_local_date(&self, local: &NaiveDate) -> MappedLocalTime<Self::Offset> {
366 match self {
367 Self::IANA(inner) => inner.offset_from_local_date(local).map(Offset::IANA),
368 Self::Fixed(inner) => inner.offset_from_local_date(local).map(Offset::Fixed),
369 }
370 }
371
372 fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> MappedLocalTime<Self::Offset> {
373 match self {
374 Self::IANA(inner) => inner.offset_from_local_datetime(local).map(Offset::IANA),
375 Self::Fixed(inner) => inner.offset_from_local_datetime(local).map(Offset::Fixed),
376 }
377 }
378
379 fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset {
380 match self {
381 TimeZone::IANA(inner) => Offset::IANA(inner.offset_from_utc_date(utc)),
382 TimeZone::Fixed(inner) => Offset::Fixed(inner.offset_from_utc_date(utc)),
383 }
384 }
385
386 fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset {
387 match self {
388 TimeZone::IANA(inner) => Offset::IANA(inner.offset_from_utc_datetime(utc)),
389 TimeZone::Fixed(inner) => Offset::Fixed(inner.offset_from_utc_datetime(utc)),
390 }
391 }
392}
393
394#[repr(C)]
398#[derive(Clone, Copy, Hash, PartialEq, Eq)]
399pub struct Duration {
400 pub months: u32,
402 pub days: u32,
404 pub nanos: u64,
406}
407
408impl Duration {
409 pub const NANOS_PER_SEC: u64 = 1_000_000_000;
411 #[doc(hidden)]
412 pub const NANOS_PER_MINUTE: u64 = 60 * Self::NANOS_PER_SEC;
414 #[doc(hidden)]
415 pub const NANOS_PER_HOUR: u64 = 60 * 60 * Self::NANOS_PER_SEC;
417 pub const DAYS_PER_WEEK: u32 = 7;
419 pub const MONTHS_PER_YEAR: u32 = 12;
421
422 pub fn new(months: u32, days: u32, nanos: u64) -> Self {
423 Self { months, days, nanos }
424 }
425
426 fn is_empty(&self) -> bool {
427 self.months == 0 && self.days == 0 && self.nanos == 0
428 }
429}
430
431impl TryFrom<Duration> for chrono::Duration {
432 type Error = crate::Error;
433
434 fn try_from(duration: Duration) -> Result<Self, Self::Error> {
435 if duration.months != 0 || duration.days != 0 {
436 Err(Error::Other(String::from(
437 "Converting TypeDB duration to chrono::Duration is only possible when months and days are not set.",
438 )))
439 } else {
440 match i64::try_from(duration.nanos) {
441 Ok(nanos) => Ok(chrono::Duration::nanoseconds(nanos)),
442 Err(_) => {
443 Err(Error::Other(String::from("Duration u64 nanos exceeded i64 required for chrono::Duration")))
444 }
445 }
446 }
447 }
448}
449
450#[derive(Debug)]
452pub struct DurationParseError;
453
454struct Segment {
455 number: u64,
456 symbol: u8,
457 number_len: usize,
458}
459
460fn read_u32(str: &str) -> Result<(Segment, &str), DurationParseError> {
461 let mut i = 0;
462 while i + 1 < str.len() && str.as_bytes()[i].is_ascii_digit() {
463 i += 1;
464 }
465 if i == 0 {
466 return Err(DurationParseError);
467 }
468 let value = str[..i].parse().map_err(|_| DurationParseError)?;
469 Ok((Segment { number: value, symbol: str.as_bytes()[i], number_len: i }, &str[i + 1..]))
470}
471
472impl FromStr for Duration {
473 type Err = DurationParseError;
474
475 fn from_str(mut str: &str) -> Result<Self, Self::Err> {
476 let mut months = 0;
477 let mut days = 0;
478 let mut nanos = 0;
479
480 if str.as_bytes()[0] != b'P' {
481 return Err(DurationParseError);
482 }
483 str = &str[1..];
484
485 let mut parsing_time = false;
486 let mut previous_symbol = None;
487 while !str.is_empty() {
488 if str.as_bytes()[0] == b'T' {
489 parsing_time = true;
490 str = &str[1..];
491 }
492
493 let (Segment { number, symbol, number_len }, tail) = read_u32(str)?;
494 str = tail;
495
496 if previous_symbol == Some(b'.') && symbol != b'S' {
497 return Err(DurationParseError);
498 }
499
500 match symbol {
501 b'Y' => months += number as u32 * Self::MONTHS_PER_YEAR,
502 b'M' if !parsing_time => months += number as u32,
503
504 b'W' => days += number as u32 * Self::DAYS_PER_WEEK,
505 b'D' => days += number as u32,
506
507 b'H' => nanos += number * Self::NANOS_PER_HOUR,
508 b'M' if parsing_time => nanos += number * Self::NANOS_PER_MINUTE,
509 b'.' => nanos += number * Self::NANOS_PER_SEC,
510 b'S' if previous_symbol != Some(b'.') => nanos += number * Self::NANOS_PER_SEC,
511 b'S' if previous_symbol == Some(b'.') => nanos += number * 10u64.pow(9 - number_len as u32),
512 _ => return Err(DurationParseError),
513 }
514 previous_symbol = Some(symbol);
515 }
516
517 Ok(Self { months, days, nanos })
518 }
519}
520
521impl fmt::Display for Duration {
523 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
524 if self.is_empty() {
525 f.write_str("PT0S")?;
526 return Ok(());
527 }
528
529 write!(f, "P")?;
530
531 if self.months > 0 || self.days > 0 {
532 let years = self.months / Self::MONTHS_PER_YEAR;
533 let months = self.months % Self::MONTHS_PER_YEAR;
534 let days = self.days;
535 if years > 0 {
536 write!(f, "{years}Y")?;
537 }
538 if months > 0 {
539 write!(f, "{months}M")?;
540 }
541 if days > 0 {
542 write!(f, "{days}D")?;
543 }
544 }
545
546 if self.nanos > 0 {
547 write!(f, "T")?;
548
549 let hours = self.nanos / Self::NANOS_PER_HOUR;
550 let minutes = (self.nanos % Self::NANOS_PER_HOUR) / Self::NANOS_PER_MINUTE;
551 let seconds = (self.nanos % Self::NANOS_PER_MINUTE) / Self::NANOS_PER_SEC;
552 let nanos = self.nanos % Self::NANOS_PER_SEC;
553
554 if hours > 0 {
555 write!(f, "{hours}H")?;
556 }
557 if minutes > 0 {
558 write!(f, "{minutes}M")?;
559 }
560 if seconds > 0 && nanos == 0 {
561 write!(f, "{seconds}S")?;
562 } else if nanos > 0 {
563 write!(f, "{seconds}.{nanos:09}S")?;
564 }
565 }
566
567 Ok(())
568 }
569}
570
571impl fmt::Debug for Duration {
572 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
573 write!(f, "months: {}, days: {}, nanos: {}", self.months, self.days, self.nanos)
574 }
575}
576
577#[derive(Clone, PartialEq)]
578pub struct Struct {
579 pub(crate) fields: HashMap<String, Option<Value>>,
580}
581
582impl Struct {
583 pub fn fields(&self) -> &HashMap<String, Option<Value>> {
584 &self.fields
585 }
586}
587
588impl fmt::Display for Struct {
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 fmt::Debug::fmt(self, f)
591 }
592}
593
594impl fmt::Debug for Struct {
595 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596 write!(f, "{:?}", self.fields)
597 }
598}