jiff/error/
unit.rs

1use crate::{error, util::b, Unit};
2
3#[derive(Clone, Debug)]
4pub(crate) enum UnitConfigError {
5    CalendarUnitsNotAllowed { unit: Unit },
6    CivilDate { given: Unit },
7    CivilTime { given: Unit },
8    IncrementDivide { unit: Unit, must_divide: MustDivide },
9    LargestSmallerThanSmallest { smallest: Unit, largest: Unit },
10    RelativeWeekOrDay { unit: Unit },
11    RelativeYearOrMonth { unit: Unit },
12    RelativeYearOrMonthGivenDaysAre24Hours { unit: Unit },
13    RoundToUnitUnsupported { unit: Unit },
14    SignedDurationCalendarUnit { smallest: Unit },
15    TimeZoneOffset { given: Unit },
16}
17
18impl From<UnitConfigError> for error::Error {
19    #[cold]
20    #[inline(never)]
21    fn from(err: UnitConfigError) -> error::Error {
22        error::ErrorKind::UnitConfig(err).into()
23    }
24}
25
26impl error::IntoError for UnitConfigError {
27    fn into_error(self) -> error::Error {
28        self.into()
29    }
30}
31
32impl core::fmt::Display for UnitConfigError {
33    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
34        use self::UnitConfigError::*;
35
36        match *self {
37            CalendarUnitsNotAllowed { unit } => write!(
38                f,
39                "operation can only be performed with units of hours \
40                 or smaller, but found non-zero '{unit}' units \
41                 (operations on `jiff::Timestamp`, `jiff::tz::Offset` \
42                  and `jiff::civil::Time` don't support calendar \
43                  units in a `jiff::Span`)",
44                unit = unit.singular(),
45            ),
46            CivilDate { given } => write!(
47                f,
48                "'{unit}' not allowed as a date unit for rounding span",
49                unit = given.singular()
50            ),
51            CivilTime { given } => write!(
52                f,
53                "'{unit}' not allowed as a time unit for rounding span",
54                unit = given.singular()
55            ),
56            IncrementDivide { unit, must_divide: MustDivide::Days } => write!(
57                f,
58                "increment for rounding to '{unit}' \
59                 must be equal to `1`",
60                unit = unit.plural(),
61            ),
62            IncrementDivide { unit, must_divide } => write!(
63                f,
64                "increment for rounding to '{unit}' \
65                 must divide into `{must_divide}` evenly",
66                unit = unit.plural(),
67                must_divide = must_divide.as_i64(),
68            ),
69            LargestSmallerThanSmallest { smallest, largest } => {
70                write!(
71                    f,
72                    "largest unit ('{largest}') cannot be smaller than \
73                     smallest unit ('{smallest}')",
74                    largest = largest.singular(),
75                    smallest = smallest.singular(),
76                )
77            }
78            RelativeWeekOrDay { unit } => write!(
79                f,
80                "using unit '{unit}' in a span or configuration \
81                 requires that either a relative reference time be given \
82                 or `jiff::SpanRelativeTo::days_are_24_hours()` is used to \
83                 indicate invariant 24-hour days, \
84                 but neither were provided",
85                unit = unit.singular(),
86            ),
87            RelativeYearOrMonth { unit } => write!(
88                f,
89                "using unit '{unit}' in a span or configuration \
90                 requires that a relative reference time be given, \
91                 but none was provided",
92                unit = unit.singular(),
93            ),
94            RelativeYearOrMonthGivenDaysAre24Hours { unit } => write!(
95                f,
96                "using unit '{unit}' in span or configuration \
97                 requires that a relative reference time be given \
98                 (`jiff::SpanRelativeTo::days_are_24_hours()` was given \
99                 but this only permits using days and weeks \
100                 without a relative reference time)",
101                unit = unit.singular(),
102            ),
103            RoundToUnitUnsupported { unit } => write!(
104                f,
105                "rounding to '{unit}' is not supported",
106                unit = unit.plural(),
107            ),
108            SignedDurationCalendarUnit { smallest } => write!(
109                f,
110                "rounding `jiff::SignedDuration` failed because \
111                 the smallest unit provided, '{plural}', is a calendar unit \
112                 (to round by calendar units, you must use a `jiff::Span`)",
113                plural = smallest.plural(),
114            ),
115            TimeZoneOffset { given } => write!(
116                f,
117                "'{unit}' not allowed when rounding time zone offset \
118                 (must use hours, minutes or seconds)",
119                unit = given.singular(),
120            ),
121        }
122    }
123}
124
125#[derive(Clone, Copy, Debug)]
126pub(crate) enum MustDivide {
127    NanosPerCivilDay,
128    MicrosPerCivilDay,
129    MillisPerCivilDay,
130    SecsPerCivilDay,
131    MinsPerCivilDay,
132    HoursPerCivilDay,
133    NanosPerMicro,
134    MicrosPerMilli,
135    MillisPerSec,
136    SecsPerMin,
137    MinsPerHour,
138    // A weird case because we require that the rounding increment, when
139    // rounding to the nearest day for a date or datetime, is always `1`.
140    Days,
141}
142
143impl MustDivide {
144    pub(crate) fn as_i64(&self) -> i64 {
145        use self::MustDivide::*;
146
147        match *self {
148            NanosPerCivilDay => b::NANOS_PER_CIVIL_DAY,
149            MicrosPerCivilDay => b::MICROS_PER_CIVIL_DAY,
150            MillisPerCivilDay => b::MILLIS_PER_CIVIL_DAY,
151            SecsPerCivilDay => b::SECS_PER_CIVIL_DAY,
152            MinsPerCivilDay => b::MINS_PER_CIVIL_DAY,
153            HoursPerCivilDay => b::HOURS_PER_CIVIL_DAY,
154            NanosPerMicro => b::NANOS_PER_MICRO,
155            MicrosPerMilli => b::MICROS_PER_MILLI,
156            MillisPerSec => b::MILLIS_PER_SEC,
157            SecsPerMin => b::SECS_PER_MIN,
158            MinsPerHour => b::MINS_PER_HOUR,
159            Days => 2,
160        }
161    }
162}