jiff/util/
t.rs

1use crate::util::rangeint::{ri128, ri16, ri32, ri64, ri8, RInto};
2
3/// A type alias for the sign of a number.
4///
5/// It can be -1 for a negative sign, 1 for a positive sign or 0 for no sign.
6pub(crate) type Sign = ri8<-1, 1>;
7
8/// A type alias for a ranged integer with no units.
9///
10/// In particular, the range of this type is just the range of an `i64`. This
11/// is useful when too many things with different units need to be combined at
12/// once, and it's just too painful to keep them straight. In cases like that,
13/// it's useful to just convert everything to `NoUnits`, do the necessary math,
14/// and then convert back to the appropriate ranged types.
15///
16/// Note that we don't actually lose much by doing this, since the computed
17/// min/max values are retained even when converting *to and from* this type.
18/// In general, this type is just about making some math easier by making
19/// everything uniform.
20pub(crate) type NoUnits = ri64<{ i64::MIN as i128 }, { i64::MAX as i128 }>;
21
22/// A type alias for a ranged 96-bit integer with no units.
23///
24/// This is like `NoUnits`, but useful in contexts where one wants to limit
25/// values to what can be represented to 96 bits.
26pub(crate) type NoUnits96 = ri128<{ -(1 << 95) }, { (1 << 95) - 1 }>;
27
28/// A type alias for a ranged 128-bit integer with no units.
29///
30/// This is like `NoUnits`, but useful in contexts where one wants to limit
31/// values to what can be represented by an `i128`.
32pub(crate) type NoUnits128 = ri128<{ i128::MIN }, { i128::MAX }>;
33
34/// A type alias for a ranged 32-bit integer with no units.
35///
36/// This is like `NoUnits`, but useful in contexts where one wants to limit
37/// values to what can be represented by an `i32`.
38pub(crate) type NoUnits32 = ri32<{ i32::MIN as i128 }, { i32::MAX as i128 }>;
39
40/// A type alias for a ranged 16-bit integer with no units.
41///
42/// This is like `NoUnits`, but useful in contexts where one wants to limit
43/// values to what can be represented by an `i16`.
44pub(crate) type NoUnits16 = ri16<{ i16::MIN as i128 }, { i16::MAX as i128 }>;
45
46/*
47/// A type alias for a ranged 8-bit integer with no units.
48///
49/// This is like `NoUnits`, but useful in contexts where one wants to limit
50/// values to what can be represented by an `i8`.
51pub(crate) type NoUnits8 = ri8<{ i8::MIN as i128 }, { i8::MAX as i128 }>;
52*/
53
54/// The range of years supported by jiff.
55///
56/// This is ultimately where some of the other ranges (like `UnixSeconds`)
57/// were determined from. That is, the range of years is the primary point at
58/// which the space of supported time instants is derived from. If one wanted
59/// to expand this range, you'd need to change it here and then compute the
60/// corresponding min/max values for `UnixSeconds`.
61pub(crate) type Year = ri16<-9999, 9999>;
62
63/// The range of CE years supported by jiff.
64pub(crate) type YearCE = ri16<1, { Year::MAX }>;
65
66/// The range of BCE years supported by jiff.
67pub(crate) type YearBCE = ri16<1, { Year::MAX + 1 }>;
68
69/// The range of Unix seconds supported by Jiff.
70///
71/// This range should correspond to the first second of `Year::MIN` up through
72/// (and including) the last second of `Year::MAX`. Actually computing that is
73/// non-trivial, however, it can be computed easily enough using Unix programs
74/// like `date`:
75///
76/// ```text
77/// $ TZ=0 date -d 'Mon Jan  1 12:00:00 AM  -9999' +'%s'
78/// date: invalid date ‘Mon Jan  1 12:00:00 AM  -9999’
79/// $ TZ=0 date -d 'Fri Dec 31 23:59:59  9999' +'%s'
80/// 253402300799
81/// ```
82///
83/// Well, almost easily enough. `date` apparently doesn't support negative
84/// years. But it does support negative timestamps:
85///
86/// ```text
87/// $ TZ=0 date -d '@-377705116800'
88/// Mon Jan  1 12:00:00 AM  -9999
89/// $ TZ=0 date -d '@253402300799'
90/// Fri Dec 31 11:59:59 PM  9999
91/// ```
92///
93/// With that said, we actually end up restricting the range a bit more than
94/// what's above. Namely, what's above is what we support for civil datetimes.
95/// Because of time zones, we need to choose whether all `Timestamp` values
96/// can be infallibly converted to `civil::DateTime` values, or whether all
97/// `civil::DateTime` values can be infallibly converted to `Timestamp` values.
98/// I chose the former because getting a civil datetime is important for
99/// formatting. If I didn't choose the former, there would be some instants
100/// that could not be formatted. Thus, we make room by shrinking the range of
101/// allowed instants by precisely the maximum supported time zone offset.
102pub(crate) type UnixSeconds = ri64<
103    { -377705116800 - SpanZoneOffset::MIN },
104    { 253402300799 - SpanZoneOffset::MAX },
105>;
106
107/// Like UnixSeconds, but expressed in units of milliseconds.
108pub(crate) type UnixMilliseconds = ri64<
109    { UnixSeconds::MIN * MILLIS_PER_SECOND.bound() },
110    {
111        (UnixSeconds::MAX * MILLIS_PER_SECOND.bound())
112            + (FractionalNanosecond::MAX / NANOS_PER_MILLI.bound())
113    },
114>;
115
116/// Like UnixSeconds, but expressed in units of microseconds.
117pub(crate) type UnixMicroseconds = ri64<
118    { UnixSeconds::MIN * MICROS_PER_SECOND.bound() },
119    {
120        (UnixSeconds::MAX * MICROS_PER_SECOND.bound())
121            + (FractionalNanosecond::MAX / NANOS_PER_MICRO.bound())
122    },
123>;
124
125/// Like UnixSeconds, but expressed in units of nanoseconds.
126pub(crate) type UnixNanoseconds = ri128<
127    { UnixSeconds::MIN * NANOS_PER_SECOND.bound() },
128    {
129        UnixSeconds::MAX * NANOS_PER_SECOND.bound() + FractionalNanosecond::MAX
130    },
131>;
132
133/// The range of possible month values.
134pub(crate) type Month = ri8<1, 12>;
135
136/// The range of a weekday, offset from zero.
137pub(crate) type WeekdayZero = ri8<0, 6>;
138
139/// The range of a weekday, offset from one.
140pub(crate) type WeekdayOne = ri8<1, 7>;
141
142/// The range of possible day values.
143///
144/// Obviously this range is not valid for every month. Therefore, code working
145/// with days needs to be careful to check that it is valid for whatever month
146/// is being used.
147pub(crate) type Day = ri8<1, 31>;
148
149pub(crate) type DayOfYear = ri16<1, 366>;
150
151pub(crate) type ISOYear = ri16<-9999, 9999>;
152
153pub(crate) type ISOWeek = ri8<1, 53>;
154
155pub(crate) type WeekNum = ri8<0, 53>;
156
157/// The range of possible hour values.
158pub(crate) type Hour = ri8<0, 23>;
159
160/// The range of possible minute values.
161pub(crate) type Minute = ri8<0, 59>;
162
163/// The range of possible second values not accounting for leap seconds.
164pub(crate) type Second = ri8<0, 59>;
165
166/// The range of possible millisecond values.
167pub(crate) type Millisecond = ri16<0, 999>;
168
169/// The range of possible microsecond values.
170pub(crate) type Microsecond = ri16<0, 999>;
171
172/// The range of possible nanosecond values.
173pub(crate) type Nanosecond = ri16<0, 999>;
174
175/// The range of possible nanosecond values.
176pub(crate) type SubsecNanosecond = ri32<0, { NANOS_PER_SECOND.bound() - 1 }>;
177
178/// A range representing each possible second in a single civil day.
179pub(crate) type CivilDaySecond =
180    ri32<0, { SECONDS_PER_CIVIL_DAY.bound() - 1 }>;
181
182/// A range representing each possible nanosecond in a single civil day.
183pub(crate) type CivilDayNanosecond =
184    ri64<0, { NANOS_PER_CIVIL_DAY.bound() - 1 }>;
185
186/// The number of seconds permitted in a single day.
187///
188/// This is mostly just a "sensible" cap on what is possible. We allow one day
189/// to span up to 7 civil days.
190///
191/// It must also be at least 1 second long.
192pub(crate) type ZonedDaySeconds =
193    ri64<1, { 7 * SECONDS_PER_CIVIL_DAY.bound() }>;
194
195/// The number of nanoseconds permitted in a single day.
196///
197/// This is mostly just a "sensible" cap on what is possible. We allow one day
198/// to span up to 7 civil days.
199///
200/// It must also be at least 1 second long.
201pub(crate) type ZonedDayNanoseconds = ri64<
202    { ZonedDaySeconds::MIN * NANOS_PER_SECOND.bound() },
203    { ZonedDaySeconds::MAX * NANOS_PER_SECOND.bound() },
204>;
205
206/// The number of days from the Unix epoch for the Gregorian calendar.
207///
208/// The range supported is based on the range of Unix timestamps that we
209/// support.
210///
211/// While I had originally used the "rate die" concept from Calendrical
212/// Calculations, I found [Howard Hinnant's formulation][date-algorithms]
213/// much more straight-forward. And while I didn't benchmark them, it also
214/// appears faster.
215///
216/// [date-algorithms]: http://howardhinnant.github.io/date_algorithms.html
217pub(crate) type UnixEpochDay = ri32<
218    {
219        (UnixSeconds::MIN + SpanZoneOffset::MIN)
220            .div_euclid(SECONDS_PER_CIVIL_DAY.bound())
221    },
222    {
223        (UnixSeconds::MAX + SpanZoneOffset::MAX)
224            .div_euclid(SECONDS_PER_CIVIL_DAY.bound())
225    },
226>;
227
228/// A precise min/max of the allowed range of a duration in years.
229pub(crate) type SpanYears = ri16<{ -(Year::LEN - 1) }, { Year::LEN - 1 }>;
230
231/// A precise min/max of the allowed range of a duration in months.
232pub(crate) type SpanMonths = ri32<
233    { SpanYears::MIN * MONTHS_PER_YEAR.bound() },
234    { SpanYears::MAX * MONTHS_PER_YEAR.bound() },
235>;
236
237/// A range of the allowed number of weeks.
238///
239/// This is an upper bound and not actually a precise maximum. I believe a
240/// precise max could be fractional and not an integer.
241pub(crate) type SpanWeeks = ri32<{ SpanDays::MIN / 7 }, { SpanDays::MAX / 7 }>;
242
243/// A range of the allowed number of days.
244pub(crate) type SpanDays =
245    ri32<{ SpanHours::MIN / 24 }, { SpanHours::MAX / 24 }>;
246
247/// A range of the allowed number of hours.
248///
249/// Like days, this is an upper bound because some days (because of DST) have
250/// 25 hours.
251pub(crate) type SpanHours =
252    ri32<{ SpanMinutes::MIN / 60 }, { SpanMinutes::MAX / 60 }>;
253
254/// A range of the allowed number of minutes.
255pub(crate) type SpanMinutes =
256    ri64<{ SpanSeconds::MIN / 60 }, { SpanSeconds::MAX / 60 }>;
257
258/// The maximum number of seconds that can be expressed with a span.
259///
260/// All of our span types (except for years and months, since they have
261/// variable length even in civil datetimes) are defined in terms of this
262/// constant. The way it's defined is a little odd, so let's break it down.
263///
264/// Firstly, a span of seconds should be able to represent at least
265/// the complete span supported by `Timestamp`. Thus, it's based off of
266/// `UnixSeconds::LEN`. That is, a span should be able to represent the value
267/// `UnixSeconds::MAX - UnixSeconds::MIN`.
268///
269/// Secondly, a span should also be able to account for any amount of possible
270/// time that a time zone offset might add or subtract to an `Timestamp`. This
271/// also means it can account for any difference between two `civil::DateTime`
272/// values.
273///
274/// Thirdly, we would like our span to be divisible by `SECONDS_PER_CIVIL_DAY`.
275/// This isn't strictly required, but it makes defining boundaries a little
276/// smoother. If it weren't divisible, then the lower bounds on some types
277/// would need to be adjusted by one.
278///
279/// Note that neither the existence of this constant nor defining our spans
280/// based on it impacts the correctness of doing arithmetic on zoned instants.
281/// Artihemetic on zoned instants still uses "civil" spans, but the length
282/// of time for some units (like a day) might vary. The arithmetic for zoned
283/// instants accounts for this explicitly. But it still must obey the limits
284/// set here.
285const SPAN_CIVIL_SECONDS: i128 = next_multiple_of(
286    UnixSeconds::LEN + SpanZoneOffset::MAX + SECONDS_PER_CIVIL_DAY.bound(),
287    SECONDS_PER_CIVIL_DAY.bound(),
288);
289
290/// A range of the allowed number of seconds.
291pub(crate) type SpanSeconds =
292    ri64<{ -SPAN_CIVIL_SECONDS }, SPAN_CIVIL_SECONDS>;
293
294/// A range of the allowed number of milliseconds.
295pub(crate) type SpanMilliseconds =
296    ri64<{ SpanSeconds::MIN * 1_000 }, { SpanSeconds::MAX * 1_000 }>;
297
298/// A range of the allowed number of microseconds.
299pub(crate) type SpanMicroseconds =
300    ri64<{ SpanMilliseconds::MIN * 1_000 }, { SpanMilliseconds::MAX * 1_000 }>;
301
302/// A range of the allowed number of nanoseconds.
303///
304/// For this, we cannot cover the full span of supported time instants since
305/// `UnixSeconds::MAX * NANOSECONDS_PER_SECOND` cannot fit into 64-bits. We
306/// could use a `i128`, but it doesn't seem worth it.
307///
308/// Also note that our min is equal to -max, so that the total number of values
309/// in this range is one less than the number of distinct `i64` values. We do
310/// that so that the absolute value is always defined.
311pub(crate) type SpanNanoseconds =
312    ri64<{ (i64::MIN + 1) as i128 }, { i64::MAX as i128 }>;
313
314/// The range of allowable fractional milliseconds.
315///
316/// That is, this corresponds to the range of milliseconds allowable within a
317/// single second. It can be either positive or negative.
318pub(crate) type FractionalMillisecond = ri32<
319    { -(MILLIS_PER_SECOND.bound() - 1) },
320    { MILLIS_PER_SECOND.bound() - 1 },
321>;
322
323/// The range of allowable fractional microseconds.
324///
325/// That is, this corresponds to the range of microseconds allowable within a
326/// single second. It can be either positive or negative.
327pub(crate) type FractionalMicrosecond = ri32<
328    { -(MICROS_PER_SECOND.bound() - 1) },
329    { MICROS_PER_SECOND.bound() - 1 },
330>;
331
332/// The range of allowable fractional nanoseconds.
333///
334/// That is, this corresponds to the range of nanoseconds allowable within a
335/// single second. It can be either positive or negative.
336pub(crate) type FractionalNanosecond = ri32<
337    { -(NANOS_PER_SECOND.bound() - 1) },
338    { NANOS_PER_SECOND.bound() - 1 },
339>;
340
341/// The range of allowable seconds and lower in a span, in units of seconds.
342///
343/// This corresponds to when the min/max of seconds, milliseconds, microseconds
344/// and nanoseconds are added together in a span. This is useful for describing
345/// the limit on the total number of possible seconds when all of these units
346/// are combined. This is necessary as part of printing/parsing spans because
347/// the ISO 8601 duration format doesn't support individual millisecond,
348/// microsecond and nanosecond components. So they all need to be smushed into
349/// seconds and a possible fractional part.
350pub(crate) type SpanSecondsOrLower = ri64<
351    {
352        SpanSeconds::MIN
353            + (SpanMilliseconds::MIN / MILLIS_PER_SECOND.bound())
354            + (SpanMicroseconds::MIN / MICROS_PER_SECOND.bound())
355            + (SpanNanoseconds::MIN / NANOS_PER_SECOND.bound())
356    },
357    {
358        SpanSeconds::MAX
359            + (SpanMilliseconds::MAX / MILLIS_PER_SECOND.bound())
360            + (SpanMicroseconds::MAX / MICROS_PER_SECOND.bound())
361            + (SpanNanoseconds::MAX / NANOS_PER_SECOND.bound())
362    },
363>;
364
365/// The range of allowable seconds and lower in a span, in units of
366/// nanoseconds.
367///
368/// See `SpanSecondsOrLower`. This exists for the same reason. Namely, when
369/// serializing a `Span` to an ISO 8601 duration string, we need to combine
370/// seconds and lower into a single fractional seconds value.
371pub(crate) type SpanSecondsOrLowerNanoseconds = ri128<
372    {
373        (SpanSeconds::MIN * NANOS_PER_SECOND.bound())
374            + (SpanMilliseconds::MIN * NANOS_PER_MILLI.bound())
375            + (SpanMicroseconds::MIN * NANOS_PER_MICRO.bound())
376            + SpanNanoseconds::MIN
377    },
378    {
379        (SpanSeconds::MAX * NANOS_PER_SECOND.bound())
380            + (SpanMilliseconds::MAX * NANOS_PER_MILLI.bound())
381            + (SpanMicroseconds::MAX * NANOS_PER_MICRO.bound())
382            + SpanNanoseconds::MAX
383    },
384>;
385
386/// The span of seconds permitted for expressing the offset of a time zone.
387pub(crate) type SpanZoneOffset =
388    ri32<{ -SPAN_ZONE_OFFSET_TOTAL_SECONDS }, SPAN_ZONE_OFFSET_TOTAL_SECONDS>;
389
390/// The max number of seconds that can be expressed in a time zone offset.
391///
392/// This is computed here based on the span offset types below for convenience
393/// use in the `SpanZoneOffset` definition above.
394const SPAN_ZONE_OFFSET_TOTAL_SECONDS: i128 =
395    (SpanZoneOffsetHours::MAX * 60 * 60)
396        + (SpanZoneOffsetMinutes::MAX * 60)
397        + SpanZoneOffsetSeconds::MAX;
398
399/// The number of hours allowed in a time zone offset.
400///
401/// This number was somewhat arbitrarily chosen. In part because it's
402/// bigger than any current offset by a wide margin, and in part because
403/// POSIX `TZ` strings require the ability to store offsets in the range
404/// `-24:59:59..=25:59:59`. Note though that we make the range a little bigger
405/// with `-25:59:59..=25:59:59` so that negating an offset always produces a
406/// valid offset.
407///
408/// Note that RFC 8536 actually allows offsets to be much bigger, namely, in
409/// the range `(-2^31, 2^31)`, where both ends are _exclusive_ (`-2^31` is
410/// explicitly disallowed, and `2^31` overflows a signed 32-bit integer). But
411/// RFC 8536 does say that it *should* be in the range `[-89999, 93599]`, which
412/// matches POSIX. In order to keep our offset small, we stick roughly to what
413/// POSIX requires.
414pub(crate) type SpanZoneOffsetHours = ri8<-25, 25>;
415
416/// The number of minutes allowed in a time zone offset.
417pub(crate) type SpanZoneOffsetMinutes = ri8<-59, 59>;
418
419/// The number of seconds allowed in a time zone offset.
420pub(crate) type SpanZoneOffsetSeconds = ri8<-59, 59>;
421
422/// The number of months in a year.
423pub(crate) const MONTHS_PER_YEAR: Constant = Constant(12);
424
425/// The number of days in a week.
426pub(crate) const DAYS_PER_CIVIL_WEEK: Constant = Constant(7);
427
428/// The number of whole hours in one day.
429pub(crate) const HOURS_PER_CIVIL_DAY: Constant = Constant(24);
430
431/// The number of minutes in a civil day.
432pub(crate) const MINUTES_PER_CIVIL_DAY: Constant =
433    Constant(HOURS_PER_CIVIL_DAY.value() * MINUTES_PER_HOUR.value());
434
435/// The number of minutes in an hour.
436pub(crate) const MINUTES_PER_HOUR: Constant = Constant(60);
437
438/// The number of seconds in a civil week.
439///
440/// Some weeks will have more or less seconds because of DST transitions. But
441/// such things are ignored when dealing with civil time, and so this constant
442/// is still useful.
443pub(crate) const SECONDS_PER_CIVIL_WEEK: Constant = Constant(
444    DAYS_PER_CIVIL_WEEK.value()
445        * HOURS_PER_CIVIL_DAY.value()
446        * SECONDS_PER_HOUR.value(),
447);
448
449/// The number of seconds in a civil day.
450///
451/// Some days will have more or less seconds because of DST transitions. But
452/// such things are ignored when dealing with civil time, and so this constant
453/// is still useful.
454pub(crate) const SECONDS_PER_CIVIL_DAY: Constant =
455    Constant(HOURS_PER_CIVIL_DAY.value() * SECONDS_PER_HOUR.value());
456
457/// The number of seconds in a single hour.
458pub(crate) const SECONDS_PER_HOUR: Constant =
459    Constant(SECONDS_PER_MINUTE.value() * 60);
460
461/// The number of seconds in a single minute.
462pub(crate) const SECONDS_PER_MINUTE: Constant = Constant(60);
463
464/// The number of microseconds in a civil day.
465pub(crate) const MILLIS_PER_CIVIL_DAY: Constant =
466    Constant(SECONDS_PER_CIVIL_DAY.value() * MILLIS_PER_SECOND.value());
467
468/// The number of milliseconds in a single second.
469pub(crate) const MILLIS_PER_SECOND: Constant = Constant(1_000);
470
471/// The number of microseconds in a civil day.
472pub(crate) const MICROS_PER_CIVIL_DAY: Constant =
473    Constant(SECONDS_PER_CIVIL_DAY.value() * MICROS_PER_SECOND.value());
474
475/// The number of microseconds in a single second.
476pub(crate) const MICROS_PER_SECOND: Constant = Constant(1_000_000);
477
478/// The number of microseconds in a single millisecond.
479pub(crate) const MICROS_PER_MILLI: Constant = Constant(1_000);
480
481/// The number of nanoseconds in a civil week.
482///
483/// Some weeks will have more or less seconds because of DST transitions. But
484/// such things are ignored when dealing with civil time, and so this constant
485/// is still useful.
486pub(crate) const NANOS_PER_CIVIL_WEEK: Constant =
487    Constant(SECONDS_PER_CIVIL_WEEK.value() * NANOS_PER_SECOND.value());
488
489/// The number of nanoseconds in a civil day.
490///
491/// Some days will have more or less seconds because of DST transitions. But
492/// such things are ignored when dealing with civil time, and so this constant
493/// is still useful.
494pub(crate) const NANOS_PER_CIVIL_DAY: Constant =
495    Constant(SECONDS_PER_CIVIL_DAY.value() * NANOS_PER_SECOND.value());
496
497/// The number of nanoseconds in a single hour.
498pub(crate) const NANOS_PER_HOUR: Constant =
499    Constant(SECONDS_PER_HOUR.value() * NANOS_PER_SECOND.value());
500
501/// The number of nanoseconds in a single minute.
502pub(crate) const NANOS_PER_MINUTE: Constant =
503    Constant(SECONDS_PER_MINUTE.value() * NANOS_PER_SECOND.value());
504
505/// The number of nanoseconds in a single second.
506pub(crate) const NANOS_PER_SECOND: Constant = Constant(1_000_000_000);
507
508/// The number of nanoseconds in a single millisecond.
509pub(crate) const NANOS_PER_MILLI: Constant = Constant(1_000_000);
510
511/// The number of nanoseconds in a single microsecond.
512pub(crate) const NANOS_PER_MICRO: Constant = Constant(1_000);
513
514pub(crate) fn sign<T: Ord>(t1: T, t2: T) -> Sign {
515    use core::cmp::Ordering::*;
516    match t1.cmp(&t2) {
517        Less => Sign::N::<-1>(),
518        Equal => Sign::N::<0>(),
519        Greater => Sign::N::<1>(),
520    }
521}
522
523/// A constant value for use in arithmetic in this crate.
524///
525/// This type is basically a bunch of shenanigans to make constants work in
526/// a sensible way with our range integers. Essentially, we really want
527/// constants to satisfy the following criteria:
528///
529/// 1. Defined in one place.
530/// 2. Composable in that we can define constants in terms of other constants.
531/// 3. Easy to use with any kind of range integer type.
532/// 4. Specially constructed when used with ranged integers. That is, a ranged
533/// integer value build from a constant should have computed min/max bounds
534/// equivalent to the constant itself. (Normally, a `rN::new` will set the
535/// computed min/max bounds to the MIN/MAX bounds overall, since it is assumed
536/// that `rN::new` accepts a value that can vary to any legal value in the
537/// range. But a constant needs tight bounds because, well, it can literally
538/// never vary.)
539///
540/// # Trait implementations
541///
542/// It'd be nice to impl `Add/Sub/Mul/Div` for `Constant` itself, but they
543/// can't be used in a const context... which is where it would be most useful.
544/// Otherwise, we just define `Add/Sub/Mul/Div` impls for all of the ranged
545/// integer types so that constants can be used on the left-hand side of
546/// arithmetic expressions. (The ranged integer types have impls that are
547/// generic enough to support arithmetic with constants on the right hand
548/// side.)
549///
550/// We do a similar thing for the `Partial{Eq,Ord}` traits. The ranged integers
551/// already have impls for `Constant` on the right-hand side. Below are the
552/// impls for `Constant` on the left-hand side.
553///
554/// All of the trait impls that deal with constants and ranged integers are
555/// implemented with the ranged integer types.
556#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
557pub(crate) struct Constant(pub(crate) i64);
558
559/// A short-hand creating a generic `Constant` value as a ranged integer.
560///
561/// Callers do need to ensure that the `MIN` and `MAX` bounds are specified (or
562/// more likely inferred), but otherwise, the `ri64` returned will be usable
563/// in most contexts even with other ranged integers (like `ri8`).
564#[allow(non_snake_case)]
565pub(crate) fn C(
566    constant: i64,
567) -> ri64<{ i64::MIN as i128 }, { i64::MAX as i128 }> {
568    Constant(constant).rinto()
569}
570
571#[allow(non_snake_case)]
572pub(crate) fn C128(constant: i64) -> ri128<{ i128::MIN }, { i128::MAX }> {
573    Constant(constant).rinto()
574}
575
576impl Constant {
577    /// Return the primitive value of this constant.
578    pub(crate) const fn value(self) -> i64 {
579        self.0
580    }
581
582    /// Return this constant as a bound intended to be used in const generics.
583    pub(crate) const fn bound(self) -> i128 {
584        self.value() as i128
585    }
586}
587
588impl core::ops::Neg for Constant {
589    type Output = Constant;
590
591    fn neg(self) -> Constant {
592        Constant(-self.0)
593    }
594}
595
596impl From<Constant> for i8 {
597    fn from(c: Constant) -> i8 {
598        #[cfg(not(debug_assertions))]
599        {
600            c.value() as i8
601        }
602        #[cfg(debug_assertions)]
603        {
604            i8::try_from(c.value()).unwrap_or_else(|_| {
605                panic!("{c:?} is out of range {:?}..={:?}", i8::MIN, i8::MAX);
606            })
607        }
608    }
609}
610
611impl From<Constant> for i16 {
612    fn from(c: Constant) -> i16 {
613        #[cfg(not(debug_assertions))]
614        {
615            c.value() as i16
616        }
617        #[cfg(debug_assertions)]
618        {
619            i16::try_from(c.value()).unwrap_or_else(|_| {
620                panic!(
621                    "{c:?} is out of range {:?}..={:?}",
622                    i16::MIN,
623                    i16::MAX
624                );
625            })
626        }
627    }
628}
629
630impl From<Constant> for i32 {
631    fn from(c: Constant) -> i32 {
632        #[cfg(not(debug_assertions))]
633        {
634            c.value() as i32
635        }
636        #[cfg(debug_assertions)]
637        {
638            i32::try_from(c.value()).unwrap_or_else(|_| {
639                panic!(
640                    "{c:?} is out of range {:?}..={:?}",
641                    i32::MIN,
642                    i32::MAX
643                );
644            })
645        }
646    }
647}
648
649impl From<Constant> for i64 {
650    fn from(c: Constant) -> i64 {
651        c.value()
652    }
653}
654
655impl From<Constant> for i128 {
656    fn from(c: Constant) -> i128 {
657        i128::from(c.value())
658    }
659}
660
661/// Computes the next multiple of `rhs` that is greater than or equal to `lhs`.
662///
663/// Taken from:
664/// https://github.com/rust-lang/rust/blob/eff958c59e8c07ba0515e164b825c9001b242294/library/core/src/num/int_macros.rs
665const fn next_multiple_of(lhs: i128, rhs: i128) -> i128 {
666    // This would otherwise fail when calculating `r` when self == T::MIN.
667    if rhs == -1 {
668        return lhs;
669    }
670
671    let r = lhs % rhs;
672    let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { r + rhs } else { r };
673    if m == 0 {
674        lhs
675    } else {
676        lhs + (rhs - m)
677    }
678}
679
680#[cfg(test)]
681mod tests {
682    use super::*;
683
684    #[test]
685    fn divisible() {
686        // We requires that our span of seconds is divisible by an even number
687        // of days. When it's not divisible, some of the boundary conditions
688        // get a little trickier, but I do not believe it's necessary for
689        // correctness. Without this assertion, some of the minimum values for
690        // our range types above need to be one less. (I believe.)
691        assert_eq!(0, SpanSeconds::MAX_REPR % 86_400);
692    }
693}