Coverage Report

Created: 2026-01-30 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.17/src/util/t.rs
Line
Count
Source
1
use 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.
6
pub(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.
20
pub(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.
26
pub(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`.
32
pub(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`.
38
pub(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`.
44
pub(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`.
51
pub(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`.
61
pub(crate) type Year = ri16<-9999, 9999>;
62
63
/// The range of CE years supported by jiff.
64
pub(crate) type YearCE = ri16<1, { Year::MAX }>;
65
66
/// The range of BCE years supported by jiff.
67
pub(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.
102
pub(crate) type UnixSeconds = ri64<
103
    { -377705116800 - SpanZoneOffset::MIN },
104
    { 253402300799 - SpanZoneOffset::MAX },
105
>;
106
107
/// Like UnixSeconds, but expressed in units of milliseconds.
108
pub(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.
117
pub(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.
126
pub(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.
134
pub(crate) type Month = ri8<1, 12>;
135
136
/// The range of a weekday, offset from zero.
137
pub(crate) type WeekdayZero = ri8<0, 6>;
138
139
/// The range of a weekday, offset from one.
140
pub(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.
147
pub(crate) type Day = ri8<1, 31>;
148
149
pub(crate) type DayOfYear = ri16<1, 366>;
150
151
pub(crate) type ISOYear = ri16<-9999, 9999>;
152
153
pub(crate) type ISOWeek = ri8<1, 53>;
154
155
pub(crate) type WeekNum = ri8<0, 53>;
156
157
/// The range of possible hour values.
158
pub(crate) type Hour = ri8<0, 23>;
159
160
/// The range of possible minute values.
161
pub(crate) type Minute = ri8<0, 59>;
162
163
/// The range of possible second values not accounting for leap seconds.
164
pub(crate) type Second = ri8<0, 59>;
165
166
/// The range of possible millisecond values.
167
pub(crate) type Millisecond = ri16<0, 999>;
168
169
/// The range of possible microsecond values.
170
pub(crate) type Microsecond = ri16<0, 999>;
171
172
/// The range of possible nanosecond values.
173
pub(crate) type Nanosecond = ri16<0, 999>;
174
175
/// The range of possible nanosecond values.
176
pub(crate) type SubsecNanosecond = ri32<0, { NANOS_PER_SECOND.bound() - 1 }>;
177
178
/// A range representing each possible second in a single civil day.
179
pub(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.
183
pub(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.
192
pub(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.
201
pub(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
217
pub(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.
229
pub(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.
232
pub(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.
241
pub(crate) type SpanWeeks = ri32<{ SpanDays::MIN / 7 }, { SpanDays::MAX / 7 }>;
242
243
/// A range of the allowed number of days.
244
pub(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.
251
pub(crate) type SpanHours =
252
    ri32<{ SpanMinutes::MIN / 60 }, { SpanMinutes::MAX / 60 }>;
253
254
/// A range of the allowed number of minutes.
255
pub(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.
285
const 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.
291
pub(crate) type SpanSeconds =
292
    ri64<{ -SPAN_CIVIL_SECONDS }, SPAN_CIVIL_SECONDS>;
293
294
/// A range of the allowed number of milliseconds.
295
pub(crate) type SpanMilliseconds =
296
    ri64<{ SpanSeconds::MIN * 1_000 }, { SpanSeconds::MAX * 1_000 }>;
297
298
/// A range of the allowed number of microseconds.
299
pub(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.
311
pub(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.
318
pub(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.
327
pub(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.
336
pub(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.
350
pub(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.
371
pub(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.
387
pub(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.
394
const 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.
414
pub(crate) type SpanZoneOffsetHours = ri8<-25, 25>;
415
416
/// The number of minutes allowed in a time zone offset.
417
pub(crate) type SpanZoneOffsetMinutes = ri8<-59, 59>;
418
419
/// The number of seconds allowed in a time zone offset.
420
pub(crate) type SpanZoneOffsetSeconds = ri8<-59, 59>;
421
422
/// The number of months in a year.
423
pub(crate) const MONTHS_PER_YEAR: Constant = Constant(12);
424
425
/// The number of days in a week.
426
pub(crate) const DAYS_PER_CIVIL_WEEK: Constant = Constant(7);
427
428
/// The number of whole hours in one day.
429
pub(crate) const HOURS_PER_CIVIL_DAY: Constant = Constant(24);
430
431
/// The number of minutes in a civil day.
432
pub(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.
436
pub(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.
443
pub(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.
454
pub(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.
458
pub(crate) const SECONDS_PER_HOUR: Constant =
459
    Constant(SECONDS_PER_MINUTE.value() * 60);
460
461
/// The number of seconds in a single minute.
462
pub(crate) const SECONDS_PER_MINUTE: Constant = Constant(60);
463
464
/// The number of microseconds in a civil day.
465
pub(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.
469
pub(crate) const MILLIS_PER_SECOND: Constant = Constant(1_000);
470
471
/// The number of microseconds in a civil day.
472
pub(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.
476
pub(crate) const MICROS_PER_SECOND: Constant = Constant(1_000_000);
477
478
/// The number of microseconds in a single millisecond.
479
pub(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.
486
pub(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.
494
pub(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.
498
pub(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.
502
pub(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.
506
pub(crate) const NANOS_PER_SECOND: Constant = Constant(1_000_000_000);
507
508
/// The number of nanoseconds in a single millisecond.
509
pub(crate) const NANOS_PER_MILLI: Constant = Constant(1_000_000);
510
511
/// The number of nanoseconds in a single microsecond.
512
pub(crate) const NANOS_PER_MICRO: Constant = Constant(1_000);
513
514
0
pub(crate) fn sign<T: Ord>(t1: T, t2: T) -> Sign {
515
    use core::cmp::Ordering::*;
516
0
    match t1.cmp(&t2) {
517
0
        Less => Sign::N::<-1>(),
518
0
        Equal => Sign::N::<0>(),
519
0
        Greater => Sign::N::<1>(),
520
    }
521
0
}
Unexecuted instantiation: jiff::util::t::sign::<jiff::civil::date::Date>
Unexecuted instantiation: jiff::util::t::sign::<&jiff::zoned::Zoned>
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)]
557
pub(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)]
565
0
pub(crate) fn C(
566
0
    constant: i64,
567
0
) -> ri64<{ i64::MIN as i128 }, { i64::MAX as i128 }> {
568
0
    Constant(constant).rinto()
569
0
}
570
571
#[allow(non_snake_case)]
572
0
pub(crate) fn C128(constant: i64) -> ri128<{ i128::MIN }, { i128::MAX }> {
573
0
    Constant(constant).rinto()
574
0
}
575
576
impl Constant {
577
    /// Return the primitive value of this constant.
578
0
    pub(crate) const fn value(self) -> i64 {
579
0
        self.0
580
0
    }
581
582
    /// Return this constant as a bound intended to be used in const generics.
583
0
    pub(crate) const fn bound(self) -> i128 {
584
0
        self.value() as i128
585
0
    }
586
}
587
588
impl core::ops::Neg for Constant {
589
    type Output = Constant;
590
591
0
    fn neg(self) -> Constant {
592
0
        Constant(-self.0)
593
0
    }
594
}
595
596
impl From<Constant> for i8 {
597
0
    fn from(c: Constant) -> i8 {
598
        #[cfg(not(debug_assertions))]
599
        {
600
0
            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
0
    }
609
}
610
611
impl From<Constant> for i16 {
612
0
    fn from(c: Constant) -> i16 {
613
        #[cfg(not(debug_assertions))]
614
        {
615
0
            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
0
    }
628
}
629
630
impl From<Constant> for i32 {
631
0
    fn from(c: Constant) -> i32 {
632
        #[cfg(not(debug_assertions))]
633
        {
634
0
            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
0
    }
647
}
648
649
impl From<Constant> for i64 {
650
0
    fn from(c: Constant) -> i64 {
651
0
        c.value()
652
0
    }
653
}
654
655
impl From<Constant> for i128 {
656
0
    fn from(c: Constant) -> i128 {
657
0
        i128::from(c.value())
658
0
    }
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
665
0
const fn next_multiple_of(lhs: i128, rhs: i128) -> i128 {
666
    // This would otherwise fail when calculating `r` when self == T::MIN.
667
0
    if rhs == -1 {
668
0
        return lhs;
669
0
    }
670
671
0
    let r = lhs % rhs;
672
0
    let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { r + rhs } else { r };
673
0
    if m == 0 {
674
0
        lhs
675
    } else {
676
0
        lhs + (rhs - m)
677
    }
678
0
}
679
680
#[cfg(test)]
681
mod 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
}