use jiff::Timestamp;
use jiff::tz::TimeZone;
use crate::intervals::absolute::{
AbsBoundPair,
AbsInterval,
EmptiableAbsBoundPair,
EmptiableAbsInterval,
HasAbsBoundPair,
HasEmptiableAbsBoundPair,
};
use crate::intervals::ops::precision::absolute::bound::{
precise_abs_end_bound,
precise_abs_end_bound_with_base_time,
precise_abs_start_bound,
precise_abs_start_bound_with_base_time,
};
use crate::intervals::special::EmptyInterval;
use crate::ops::{Precision, PrecisionOutOfRangeError};
pub trait PreciseAbsInterval {
type PrecisedIntervalOutput;
#[must_use]
fn precise_different_precisions(
&self,
tz: TimeZone,
precision_start: Precision,
precision_end: Precision,
) -> Self::PrecisedIntervalOutput;
#[must_use]
fn precise(&self, tz: TimeZone, precision: Precision) -> Self::PrecisedIntervalOutput {
self.precise_different_precisions(tz, precision, precision)
}
#[must_use]
fn precise_different_precisions_with_base_time(
&self,
tz: TimeZone,
precision_start: Precision,
base_start: Timestamp,
precision_end: Precision,
base_end: Timestamp,
) -> Self::PrecisedIntervalOutput;
#[must_use]
fn precise_with_base_time(
&self,
tz: TimeZone,
precision: Precision,
base: Timestamp,
) -> Self::PrecisedIntervalOutput {
self.precise_different_precisions_with_base_time(tz, precision, base, precision, base)
}
}
impl PreciseAbsInterval for AbsBoundPair {
type PrecisedIntervalOutput = Result<Self, PrecisionOutOfRangeError>;
fn precise_different_precisions(
&self,
tz: TimeZone,
precision_start: Precision,
precision_end: Precision,
) -> Self::PrecisedIntervalOutput {
precise_abs_bound_pair(self, tz, precision_start, precision_end)
}
fn precise_different_precisions_with_base_time(
&self,
tz: TimeZone,
precision_start: Precision,
base_start: Timestamp,
precision_end: Precision,
base_end: Timestamp,
) -> Self::PrecisedIntervalOutput {
precise_abs_bound_pair_with_base_time(self, tz, precision_start, base_start, precision_end, base_end)
}
}
impl PreciseAbsInterval for EmptiableAbsBoundPair {
type PrecisedIntervalOutput = Result<Self, PrecisionOutOfRangeError>;
fn precise_different_precisions(
&self,
tz: TimeZone,
start_precision: Precision,
end_precision: Precision,
) -> Self::PrecisedIntervalOutput {
if let Self::Bound(abs_bound_pair) = self {
Ok(precise_abs_bound_pair(abs_bound_pair, tz, start_precision, end_precision)?.to_emptiable())
} else {
Ok(Self::Empty)
}
}
fn precise_different_precisions_with_base_time(
&self,
tz: TimeZone,
precision_start: Precision,
base_start: Timestamp,
precision_end: Precision,
base_end: Timestamp,
) -> Self::PrecisedIntervalOutput {
if let Self::Bound(abs_bound_pair) = self {
Ok(precise_abs_bound_pair_with_base_time(
abs_bound_pair,
tz,
precision_start,
base_start,
precision_end,
base_end,
)?
.to_emptiable())
} else {
Ok(Self::Empty)
}
}
}
impl PreciseAbsInterval for AbsInterval {
type PrecisedIntervalOutput = Result<Self, PrecisionOutOfRangeError>;
fn precise_different_precisions(
&self,
tz: TimeZone,
precision_start: Precision,
precision_end: Precision,
) -> Self::PrecisedIntervalOutput {
Ok(precise_abs_bound_pair(&self.abs_bound_pair(), tz, precision_start, precision_end)?.to_interval())
}
fn precise_different_precisions_with_base_time(
&self,
tz: TimeZone,
precision_start: Precision,
base_start: Timestamp,
precision_end: Precision,
base_end: Timestamp,
) -> Self::PrecisedIntervalOutput {
Ok(precise_abs_bound_pair_with_base_time(
&self.abs_bound_pair(),
tz,
precision_start,
base_start,
precision_end,
base_end,
)?
.to_interval())
}
}
impl PreciseAbsInterval for EmptiableAbsInterval {
type PrecisedIntervalOutput = Result<Self, PrecisionOutOfRangeError>;
fn precise_different_precisions(
&self,
tz: TimeZone,
precision_start: Precision,
precision_end: Precision,
) -> Self::PrecisedIntervalOutput {
if let EmptiableAbsBoundPair::Bound(ref abs_bound_pair) = self.emptiable_abs_bound_pair() {
Ok(precise_abs_bound_pair(abs_bound_pair, tz, precision_start, precision_end)?.to_emptiable_interval())
} else {
Ok(Self::Empty(EmptyInterval))
}
}
fn precise_different_precisions_with_base_time(
&self,
tz: TimeZone,
precision_start: Precision,
base_start: Timestamp,
precision_end: Precision,
base_end: Timestamp,
) -> Self::PrecisedIntervalOutput {
if let EmptiableAbsBoundPair::Bound(ref abs_bound_pair) = self.emptiable_abs_bound_pair() {
Ok(precise_abs_bound_pair_with_base_time(
abs_bound_pair,
tz,
precision_start,
base_start,
precision_end,
base_end,
)?
.to_emptiable_interval())
} else {
Ok(Self::Empty(EmptyInterval))
}
}
}
pub fn precise_abs_bound_pair(
bound_pair: &AbsBoundPair,
tz: TimeZone,
precision_start: Precision,
precision_end: Precision,
) -> Result<AbsBoundPair, PrecisionOutOfRangeError> {
Ok(AbsBoundPair::new(
precise_abs_start_bound(&bound_pair.start(), tz.clone(), precision_start)?,
precise_abs_end_bound(&bound_pair.end(), tz, precision_end)?,
))
}
pub fn precise_abs_bound_pair_with_base_time(
bound_pair: &AbsBoundPair,
tz: TimeZone,
precision_start: Precision,
base_start: Timestamp,
precision_end: Precision,
base_end: Timestamp,
) -> Result<AbsBoundPair, PrecisionOutOfRangeError> {
Ok(AbsBoundPair::new(
precise_abs_start_bound_with_base_time(&bound_pair.start(), tz.clone(), precision_start, base_start)?,
precise_abs_end_bound_with_base_time(&bound_pair.end(), tz, precision_end, base_end)?,
))
}