1use std::convert::TryFrom;
4
5use llkv_result::{Error, Result};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
13pub struct IntervalValue {
14 pub months: i32,
15 pub days: i32,
16 pub nanos: i64,
17}
18
19impl IntervalValue {
20 pub const fn new(months: i32, days: i32, nanos: i64) -> Self {
21 Self {
22 months,
23 days,
24 nanos,
25 }
26 }
27
28 pub const fn zero() -> Self {
29 Self::new(0, 0, 0)
30 }
31
32 pub fn from_components(months: i64, days: i64, nanos: i64) -> Result<Self> {
34 let months = i32::try_from(months)
35 .map_err(|_| Error::InvalidArgumentError("interval months out of range".into()))?;
36 let days = i32::try_from(days)
37 .map_err(|_| Error::InvalidArgumentError("interval days out of range".into()))?;
38 Ok(Self::new(months, days, nanos))
39 }
40
41 pub fn checked_add(self, other: Self) -> Option<Self> {
42 Some(Self {
43 months: self.months.checked_add(other.months)?,
44 days: self.days.checked_add(other.days)?,
45 nanos: self.nanos.checked_add(other.nanos)?,
46 })
47 }
48
49 pub fn checked_sub(self, other: Self) -> Option<Self> {
50 Some(Self {
51 months: self.months.checked_sub(other.months)?,
52 days: self.days.checked_sub(other.days)?,
53 nanos: self.nanos.checked_sub(other.nanos)?,
54 })
55 }
56
57 pub fn checked_neg(self) -> Option<Self> {
58 Some(Self {
59 months: self.months.checked_neg()?,
60 days: self.days.checked_neg()?,
61 nanos: self.nanos.checked_neg()?,
62 })
63 }
64
65 pub fn checked_scale(self, factor: i64) -> Option<Self> {
66 let months = i64::from(self.months).checked_mul(factor)?;
67 let days = i64::from(self.days).checked_mul(factor)?;
68 let nanos = self.nanos.checked_mul(factor)?;
69 Some(Self {
70 months: months.try_into().ok()?,
71 days: days.try_into().ok()?,
72 nanos,
73 })
74 }
75
76 pub const fn is_zero(self) -> bool {
77 self.months == 0 && self.days == 0 && self.nanos == 0
78 }
79}