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 nanosecond in a single civil day.
179pub(crate) type CivilDayNanosecond =
180 ri64<0, { NANOS_PER_CIVIL_DAY.bound() - 1 }>;
181
182/// The number of seconds permitted in a single day.
183///
184/// This is mostly just a "sensible" cap on what is possible. We allow one day
185/// to span up to 7 civil days.
186///
187/// It must also be at least 1 second long.
188pub(crate) type ZonedDaySeconds =
189 ri64<1, { 7 * SECONDS_PER_CIVIL_DAY.bound() }>;
190
191/// The number of nanoseconds permitted in a single day.
192///
193/// This is mostly just a "sensible" cap on what is possible. We allow one day
194/// to span up to 7 civil days.
195///
196/// It must also be at least 1 second long.
197pub(crate) type ZonedDayNanoseconds = ri64<
198 { ZonedDaySeconds::MIN * NANOS_PER_SECOND.bound() },
199 { ZonedDaySeconds::MAX * NANOS_PER_SECOND.bound() },
200>;
201
202/// The number of days from the Unix epoch for the Gregorian calendar.
203///
204/// The range supported is based on the range of Unix timestamps that we
205/// support.
206///
207/// While I had originally used the "rate die" concept from Calendrical
208/// Calculations, I found [Howard Hinnant's formulation][date-algorithms]
209/// much more straight-forward. And while I didn't benchmark them, it also
210/// appears faster.
211///
212/// [date-algorithms]: http://howardhinnant.github.io/date_algorithms.html
213pub(crate) type UnixEpochDay = ri32<
214 {
215 (UnixSeconds::MIN + SpanZoneOffset::MIN)
216 .div_euclid(SECONDS_PER_CIVIL_DAY.bound())
217 },
218 {
219 (UnixSeconds::MAX + SpanZoneOffset::MAX)
220 .div_euclid(SECONDS_PER_CIVIL_DAY.bound())
221 },
222>;
223
224/// A precise min/max of the allowed range of a duration in years.
225pub(crate) type SpanYears = ri16<{ -(Year::LEN - 1) }, { Year::LEN - 1 }>;
226
227/// A precise min/max of the allowed range of a duration in months.
228pub(crate) type SpanMonths = ri32<
229 { SpanYears::MIN * MONTHS_PER_YEAR.bound() },
230 { SpanYears::MAX * MONTHS_PER_YEAR.bound() },
231>;
232
233/// A range of the allowed number of weeks.
234///
235/// This is an upper bound and not actually a precise maximum. I believe a
236/// precise max could be fractional and not an integer.
237pub(crate) type SpanWeeks = ri32<{ SpanDays::MIN / 7 }, { SpanDays::MAX / 7 }>;
238
239/// A range of the allowed number of days.
240pub(crate) type SpanDays =
241 ri32<{ SpanHours::MIN / 24 }, { SpanHours::MAX / 24 }>;
242
243/// A range of the allowed number of hours.
244///
245/// Like days, this is an upper bound because some days (because of DST) have
246/// 25 hours.
247pub(crate) type SpanHours =
248 ri32<{ SpanMinutes::MIN / 60 }, { SpanMinutes::MAX / 60 }>;
249
250/// A range of the allowed number of minutes.
251pub(crate) type SpanMinutes =
252 ri64<{ SpanSeconds::MIN / 60 }, { SpanSeconds::MAX / 60 }>;
253
254/// The maximum number of seconds that can be expressed with a span.
255///
256/// All of our span types (except for years and months, since they have
257/// variable length even in civil datetimes) are defined in terms of this
258/// constant. The way it's defined is a little odd, so let's break it down.
259///
260/// Firstly, a span of seconds should be able to represent at least
261/// the complete span supported by `Timestamp`. Thus, it's based off of
262/// `UnixSeconds::LEN`. That is, a span should be able to represent the value
263/// `UnixSeconds::MAX - UnixSeconds::MIN`.
264///
265/// Secondly, a span should also be able to account for any amount of possible
266/// time that a time zone offset might add or subtract to an `Timestamp`. This
267/// also means it can account for any difference between two `civil::DateTime`
268/// values.
269///
270/// Thirdly, we would like our span to be divisible by `SECONDS_PER_CIVIL_DAY`.
271/// This isn't strictly required, but it makes defining boundaries a little
272/// smoother. If it weren't divisible, then the lower bounds on some types
273/// would need to be adjusted by one.
274///
275/// Note that neither the existence of this constant nor defining our spans
276/// based on it impacts the correctness of doing arithmetic on zoned instants.
277/// Artihemetic on zoned instants still uses "civil" spans, but the length
278/// of time for some units (like a day) might vary. The arithmetic for zoned
279/// instants accounts for this explicitly. But it still must obey the limits
280/// set here.
281const SPAN_CIVIL_SECONDS: i128 = next_multiple_of(
282 UnixSeconds::LEN + SpanZoneOffset::MAX + SECONDS_PER_CIVIL_DAY.bound(),
283 SECONDS_PER_CIVIL_DAY.bound(),
284);
285
286/// A range of the allowed number of seconds.
287pub(crate) type SpanSeconds =
288 ri64<{ -SPAN_CIVIL_SECONDS }, SPAN_CIVIL_SECONDS>;
289
290/// A range of the allowed number of milliseconds.
291pub(crate) type SpanMilliseconds =
292 ri64<{ SpanSeconds::MIN * 1_000 }, { SpanSeconds::MAX * 1_000 }>;
293
294/// A range of the allowed number of microseconds.
295pub(crate) type SpanMicroseconds =
296 ri64<{ SpanMilliseconds::MIN * 1_000 }, { SpanMilliseconds::MAX * 1_000 }>;
297
298/// A range of the allowed number of nanoseconds.
299///
300/// For this, we cannot cover the full span of supported time instants since
301/// `UnixSeconds::MAX * NANOSECONDS_PER_SECOND` cannot fit into 64-bits. We
302/// could use a `i128`, but it doesn't seem worth it.
303///
304/// Also note that our min is equal to -max, so that the total number of values
305/// in this range is one less than the number of distinct `i64` values. We do
306/// that so that the absolute value is always defined.
307pub(crate) type SpanNanoseconds =
308 ri64<{ (i64::MIN + 1) as i128 }, { i64::MAX as i128 }>;
309
310/// The range of allowable fractional milliseconds.
311///
312/// That is, this corresponds to the range of milliseconds allowable within a
313/// single second. It can be either positive or negative.
314pub(crate) type FractionalMillisecond = ri32<
315 { -(MILLIS_PER_SECOND.bound() - 1) },
316 { MILLIS_PER_SECOND.bound() - 1 },
317>;
318
319/// The range of allowable fractional microseconds.
320///
321/// That is, this corresponds to the range of microseconds allowable within a
322/// single second. It can be either positive or negative.
323pub(crate) type FractionalMicrosecond = ri32<
324 { -(MICROS_PER_SECOND.bound() - 1) },
325 { MICROS_PER_SECOND.bound() - 1 },
326>;
327
328/// The range of allowable fractional nanoseconds.
329///
330/// That is, this corresponds to the range of nanoseconds allowable within a
331/// single second. It can be either positive or negative.
332pub(crate) type FractionalNanosecond = ri32<
333 { -(NANOS_PER_SECOND.bound() - 1) },
334 { NANOS_PER_SECOND.bound() - 1 },
335>;
336
337/// The range of allowable seconds and lower in a span, in units of seconds.
338///
339/// This corresponds to when the min/max of seconds, milliseconds, microseconds
340/// and nanoseconds are added together in a span. This is useful for describing
341/// the limit on the total number of possible seconds when all of these units
342/// are combined. This is necessary as part of printing/parsing spans because
343/// the ISO 8601 duration format doesn't support individual millisecond,
344/// microsecond and nanosecond components. So they all need to be smushed into
345/// seconds and a possible fractional part.
346pub(crate) type SpanSecondsOrLower = ri64<
347 {
348 SpanSeconds::MIN
349 + (SpanMilliseconds::MIN / MILLIS_PER_SECOND.bound())
350 + (SpanMicroseconds::MIN / MICROS_PER_SECOND.bound())
351 + (SpanNanoseconds::MIN / NANOS_PER_SECOND.bound())
352 },
353 {
354 SpanSeconds::MAX
355 + (SpanMilliseconds::MAX / MILLIS_PER_SECOND.bound())
356 + (SpanMicroseconds::MAX / MICROS_PER_SECOND.bound())
357 + (SpanNanoseconds::MAX / NANOS_PER_SECOND.bound())
358 },
359>;
360
361/// The range of allowable seconds and lower in a span, in units of
362/// nanoseconds.
363///
364/// See `SpanSecondsOrLower`. This exists for the same reason. Namely, when
365/// serializing a `Span` to an ISO 8601 duration string, we need to combine
366/// seconds and lower into a single fractional seconds value.
367pub(crate) type SpanSecondsOrLowerNanoseconds = ri128<
368 {
369 (SpanSeconds::MIN * NANOS_PER_SECOND.bound())
370 + (SpanMilliseconds::MIN * NANOS_PER_MILLI.bound())
371 + (SpanMicroseconds::MIN * NANOS_PER_MICRO.bound())
372 + SpanNanoseconds::MIN
373 },
374 {
375 (SpanSeconds::MAX * NANOS_PER_SECOND.bound())
376 + (SpanMilliseconds::MAX * NANOS_PER_MILLI.bound())
377 + (SpanMicroseconds::MAX * NANOS_PER_MICRO.bound())
378 + SpanNanoseconds::MAX
379 },
380>;
381
382/// The span of seconds permitted for expressing the offset of a time zone.
383pub(crate) type SpanZoneOffset =
384 ri32<{ -SPAN_ZONE_OFFSET_TOTAL_SECONDS }, SPAN_ZONE_OFFSET_TOTAL_SECONDS>;
385
386/// The max number of seconds that can be expressed in a time zone offset.
387///
388/// This is computed here based on the span offset types below for convenience
389/// use in the `SpanZoneOffset` definition above.
390const SPAN_ZONE_OFFSET_TOTAL_SECONDS: i128 =
391 (SpanZoneOffsetHours::MAX * 60 * 60)
392 + (SpanZoneOffsetMinutes::MAX * 60)
393 + SpanZoneOffsetSeconds::MAX;
394
395/// The number of hours allowed in a time zone offset.
396///
397/// This number was somewhat arbitrarily chosen. In part because it's
398/// bigger than any current offset by a wide margin, and in part because
399/// POSIX `TZ` strings require the ability to store offsets in the range
400/// `-24:59:59..=25:59:59`. Note though that we make the range a little bigger
401/// with `-25:59:59..=25:59:59` so that negating an offset always produces a
402/// valid offset.
403///
404/// Note that RFC 8536 actually allows offsets to be much bigger, namely, in
405/// the range `(-2^31, 2^31)`, where both ends are _exclusive_ (`-2^31` is
406/// explicitly disallowed, and `2^31` overflows a signed 32-bit integer). But
407/// RFC 8536 does say that it *should* be in the range `[-89999, 93599]`, which
408/// matches POSIX. In order to keep our offset small, we stick roughly to what
409/// POSIX requires.
410pub(crate) type SpanZoneOffsetHours = ri8<-25, 25>;
411
412/// The number of minutes allowed in a time zone offset.
413pub(crate) type SpanZoneOffsetMinutes = ri8<-59, 59>;
414
415/// The number of seconds allowed in a time zone offset.
416pub(crate) type SpanZoneOffsetSeconds = ri8<-59, 59>;
417
418/// The number of months in a year.
419pub(crate) const MONTHS_PER_YEAR: Constant = Constant(12);
420
421/// The number of days in a week.
422pub(crate) const DAYS_PER_CIVIL_WEEK: Constant = Constant(7);
423
424/// The number of whole hours in one day.
425pub(crate) const HOURS_PER_CIVIL_DAY: Constant = Constant(24);
426
427/// The number of minutes in a civil day.
428pub(crate) const MINUTES_PER_CIVIL_DAY: Constant =
429 Constant(HOURS_PER_CIVIL_DAY.value() * MINUTES_PER_HOUR.value());
430
431/// The number of minutes in an hour.
432pub(crate) const MINUTES_PER_HOUR: Constant = Constant(60);
433
434/// The number of seconds in a civil week.
435///
436/// Some weeks will have more or less seconds because of DST transitions. But
437/// such things are ignored when dealing with civil time, and so this constant
438/// is still useful.
439pub(crate) const SECONDS_PER_CIVIL_WEEK: Constant = Constant(
440 DAYS_PER_CIVIL_WEEK.value()
441 * HOURS_PER_CIVIL_DAY.value()
442 * SECONDS_PER_HOUR.value(),
443);
444
445/// The number of seconds in a civil day.
446///
447/// Some days will have more or less seconds because of DST transitions. But
448/// such things are ignored when dealing with civil time, and so this constant
449/// is still useful.
450pub(crate) const SECONDS_PER_CIVIL_DAY: Constant =
451 Constant(HOURS_PER_CIVIL_DAY.value() * SECONDS_PER_HOUR.value());
452
453/// The number of seconds in a single hour.
454pub(crate) const SECONDS_PER_HOUR: Constant =
455 Constant(SECONDS_PER_MINUTE.value() * 60);
456
457/// The number of seconds in a single minute.
458pub(crate) const SECONDS_PER_MINUTE: Constant = Constant(60);
459
460/// The number of microseconds in a civil day.
461pub(crate) const MILLIS_PER_CIVIL_DAY: Constant =
462 Constant(SECONDS_PER_CIVIL_DAY.value() * MILLIS_PER_SECOND.value());
463
464/// The number of milliseconds in a single second.
465pub(crate) const MILLIS_PER_SECOND: Constant = Constant(1_000);
466
467/// The number of microseconds in a civil day.
468pub(crate) const MICROS_PER_CIVIL_DAY: Constant =
469 Constant(SECONDS_PER_CIVIL_DAY.value() * MICROS_PER_SECOND.value());
470
471/// The number of microseconds in a single second.
472pub(crate) const MICROS_PER_SECOND: Constant = Constant(1_000_000);
473
474/// The number of microseconds in a single millisecond.
475pub(crate) const MICROS_PER_MILLI: Constant = Constant(1_000);
476
477/// The number of nanoseconds in a civil week.
478///
479/// Some weeks will have more or less seconds because of DST transitions. But
480/// such things are ignored when dealing with civil time, and so this constant
481/// is still useful.
482pub(crate) const NANOS_PER_CIVIL_WEEK: Constant =
483 Constant(SECONDS_PER_CIVIL_WEEK.value() * NANOS_PER_SECOND.value());
484
485/// The number of nanoseconds in a civil day.
486///
487/// Some days will have more or less seconds because of DST transitions. But
488/// such things are ignored when dealing with civil time, and so this constant
489/// is still useful.
490pub(crate) const NANOS_PER_CIVIL_DAY: Constant =
491 Constant(SECONDS_PER_CIVIL_DAY.value() * NANOS_PER_SECOND.value());
492
493/// The number of nanoseconds in a single hour.
494pub(crate) const NANOS_PER_HOUR: Constant =
495 Constant(SECONDS_PER_HOUR.value() * NANOS_PER_SECOND.value());
496
497/// The number of nanoseconds in a single minute.
498pub(crate) const NANOS_PER_MINUTE: Constant =
499 Constant(SECONDS_PER_MINUTE.value() * NANOS_PER_SECOND.value());
500
501/// The number of nanoseconds in a single second.
502pub(crate) const NANOS_PER_SECOND: Constant = Constant(1_000_000_000);
503
504/// The number of nanoseconds in a single millisecond.
505pub(crate) const NANOS_PER_MILLI: Constant = Constant(1_000_000);
506
507/// The number of nanoseconds in a single microsecond.
508pub(crate) const NANOS_PER_MICRO: Constant = Constant(1_000);
509
510pub(crate) fn sign<T: Ord>(t1: T, t2: T) -> Sign {
511 use core::cmp::Ordering::*;
512 match t1.cmp(&t2) {
513 Less => Sign::N::<-1>(),
514 Equal => Sign::N::<0>(),
515 Greater => Sign::N::<1>(),
516 }
517}
518
519/// A constant value for use in arithmetic in this crate.
520///
521/// This type is basically a bunch of shenanigans to make constants work in
522/// a sensible way with our range integers. Essentially, we really want
523/// constants to satisfy the following criteria:
524///
525/// 1. Defined in one place.
526/// 2. Composable in that we can define constants in terms of other constants.
527/// 3. Easy to use with any kind of range integer type.
528/// 4. Specially constructed when used with ranged integers. That is, a ranged
529/// integer value build from a constant should have computed min/max bounds
530/// equivalent to the constant itself. (Normally, a `rN::new` will set the
531/// computed min/max bounds to the MIN/MAX bounds overall, since it is assumed
532/// that `rN::new` accepts a value that can vary to any legal value in the
533/// range. But a constant needs tight bounds because, well, it can literally
534/// never vary.)
535///
536/// # Trait implementations
537///
538/// It'd be nice to impl `Add/Sub/Mul/Div` for `Constant` itself, but they
539/// can't be used in a const context... which is where it would be most useful.
540/// Otherwise, we just define `Add/Sub/Mul/Div` impls for all of the ranged
541/// integer types so that constants can be used on the left-hand side of
542/// arithmetic expressions. (The ranged integer types have impls that are
543/// generic enough to support arithmetic with constants on the right hand
544/// side.)
545///
546/// We do a similar thing for the `Partial{Eq,Ord}` traits. The ranged integers
547/// already have impls for `Constant` on the right-hand side. Below are the
548/// impls for `Constant` on the left-hand side.
549///
550/// All of the trait impls that deal with constants and ranged integers are
551/// implemented with the ranged integer types.
552#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
553pub(crate) struct Constant(pub(crate) i64);
554
555/// A short-hand creating a generic `Constant` value as a ranged integer.
556///
557/// Callers do need to ensure that the `MIN` and `MAX` bounds are specified (or
558/// more likely inferred), but otherwise, the `ri64` returned will be usable
559/// in most contexts even with other ranged integers (like `ri8`).
560#[allow(non_snake_case)]
561pub(crate) fn C(
562 constant: i64,
563) -> ri64<{ i64::MIN as i128 }, { i64::MAX as i128 }> {
564 Constant(constant).rinto()
565}
566
567#[allow(non_snake_case)]
568pub(crate) fn C128(constant: i64) -> ri128<{ i128::MIN }, { i128::MAX }> {
569 Constant(constant).rinto()
570}
571
572impl Constant {
573 /// Return the primitive value of this constant.
574 pub(crate) const fn value(self) -> i64 {
575 self.0
576 }
577
578 /// Return this constant as a bound intended to be used in const generics.
579 pub(crate) const fn bound(self) -> i128 {
580 self.value() as i128
581 }
582}
583
584impl core::ops::Neg for Constant {
585 type Output = Constant;
586
587 fn neg(self) -> Constant {
588 Constant(-self.0)
589 }
590}
591
592impl From<Constant> for i8 {
593 fn from(c: Constant) -> i8 {
594 #[cfg(not(debug_assertions))]
595 {
596 c.value() as i8
597 }
598 #[cfg(debug_assertions)]
599 {
600 i8::try_from(c.value()).unwrap_or_else(|_| {
601 panic!("{c:?} is out of range {:?}..={:?}", i8::MIN, i8::MAX);
602 })
603 }
604 }
605}
606
607impl From<Constant> for i16 {
608 fn from(c: Constant) -> i16 {
609 #[cfg(not(debug_assertions))]
610 {
611 c.value() as i16
612 }
613 #[cfg(debug_assertions)]
614 {
615 i16::try_from(c.value()).unwrap_or_else(|_| {
616 panic!(
617 "{c:?} is out of range {:?}..={:?}",
618 i16::MIN,
619 i16::MAX
620 );
621 })
622 }
623 }
624}
625
626impl From<Constant> for i32 {
627 fn from(c: Constant) -> i32 {
628 #[cfg(not(debug_assertions))]
629 {
630 c.value() as i32
631 }
632 #[cfg(debug_assertions)]
633 {
634 i32::try_from(c.value()).unwrap_or_else(|_| {
635 panic!(
636 "{c:?} is out of range {:?}..={:?}",
637 i32::MIN,
638 i32::MAX
639 );
640 })
641 }
642 }
643}
644
645impl From<Constant> for i64 {
646 fn from(c: Constant) -> i64 {
647 c.value()
648 }
649}
650
651impl From<Constant> for i128 {
652 fn from(c: Constant) -> i128 {
653 i128::from(c.value())
654 }
655}
656
657/// Computes the next multiple of `rhs` that is greater than or equal to `lhs`.
658///
659/// Taken from:
660/// https://github.com/rust-lang/rust/blob/eff958c59e8c07ba0515e164b825c9001b242294/library/core/src/num/int_macros.rs
661const fn next_multiple_of(lhs: i128, rhs: i128) -> i128 {
662 // This would otherwise fail when calculating `r` when self == T::MIN.
663 if rhs == -1 {
664 return lhs;
665 }
666
667 let r = lhs % rhs;
668 let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { r + rhs } else { r };
669 if m == 0 {
670 lhs
671 } else {
672 lhs + (rhs - m)
673 }
674}
675
676#[cfg(test)]
677mod tests {
678 use super::*;
679
680 #[test]
681 fn divisible() {
682 // We requires that our span of seconds is divisible by an even number
683 // of days. When it's not divisible, some of the boundary conditions
684 // get a little trickier, but I do not believe it's necessary for
685 // correctness. Without this assertion, some of the minimum values for
686 // our range types above need to be one less. (I believe.)
687 assert_eq!(0, SpanSeconds::MAX_REPR % 86_400);
688 }
689}