#![allow(dead_code)]
use crate::{Error, SignedDuration};
pub(crate) const DAYS_PER_WEEK: i64 = 7;
pub(crate) const HOURS_PER_CIVIL_DAY: i64 = 24;
pub(crate) const MINS_PER_CIVIL_DAY: i64 = HOURS_PER_CIVIL_DAY * MINS_PER_HOUR;
pub(crate) const MINS_PER_HOUR: i64 = 60;
pub(crate) const SECS_PER_WEEK: i64 = DAYS_PER_WEEK * SECS_PER_CIVIL_DAY;
pub(crate) const SECS_PER_CIVIL_DAY: i64 = HOURS_PER_CIVIL_DAY * SECS_PER_HOUR;
pub(crate) const SECS_PER_HOUR: i64 = SECS_PER_MIN * MINS_PER_HOUR;
pub(crate) const SECS_PER_MIN: i64 = 60;
pub(crate) const MILLIS_PER_CIVIL_DAY: i64 =
SECS_PER_CIVIL_DAY * MILLIS_PER_SEC;
pub(crate) const MILLIS_PER_SEC: i64 = 1_000;
pub(crate) const MICROS_PER_CIVIL_DAY: i64 =
SECS_PER_CIVIL_DAY * MICROS_PER_SEC;
pub(crate) const MICROS_PER_SEC: i64 = MILLIS_PER_SEC * MICROS_PER_MILLI;
pub(crate) const MICROS_PER_MILLI: i64 = 1_000;
pub(crate) const NANOS_PER_WEEK: i64 = DAYS_PER_WEEK * NANOS_PER_CIVIL_DAY;
pub(crate) const NANOS_PER_CIVIL_DAY: i64 =
HOURS_PER_CIVIL_DAY * NANOS_PER_HOUR;
pub(crate) const NANOS_PER_HOUR: i64 = MINS_PER_HOUR * NANOS_PER_MIN;
pub(crate) const NANOS_PER_MIN: i64 = SECS_PER_MIN * NANOS_PER_SEC;
pub(crate) const NANOS_PER_SEC: i64 = MILLIS_PER_SEC * NANOS_PER_MILLI;
pub(crate) const NANOS_PER_MILLI: i64 = MICROS_PER_MILLI * NANOS_PER_MICRO;
pub(crate) const NANOS_PER_MICRO: i64 = 1_000;
pub(crate) const DAYS_PER_WEEK_32: i32 = 7;
pub(crate) const HOURS_PER_CIVIL_DAY_32: i32 = 24;
pub(crate) const MINS_PER_HOUR_32: i32 = 60;
pub(crate) const SECS_PER_CIVIL_DAY_32: i32 =
HOURS_PER_CIVIL_DAY_32 * SECS_PER_HOUR_32;
pub(crate) const SECS_PER_HOUR_32: i32 = SECS_PER_MIN_32 * MINS_PER_HOUR_32;
pub(crate) const SECS_PER_MIN_32: i32 = 60;
pub(crate) const MILLIS_PER_SEC_32: i32 = 1_000;
pub(crate) const MICROS_PER_SEC_32: i32 =
MILLIS_PER_SEC_32 * MICROS_PER_MILLI_32;
pub(crate) const MICROS_PER_MILLI_32: i32 = 1_000;
pub(crate) const NANOS_PER_SEC_32: i32 =
MILLIS_PER_SEC_32 * NANOS_PER_MILLI_32;
pub(crate) const NANOS_PER_MILLI_32: i32 =
MICROS_PER_MILLI_32 * NANOS_PER_MICRO_32;
pub(crate) const NANOS_PER_MICRO_32: i32 = 1_000;
macro_rules! define_bounds {
($((
// The name of the boundary type.
$name:ident,
// The underlying primitive type. This is usually, but not always,
// the smallest signed primitive integer type that can represent both
// the minimum and maximum boundary values.
$ty:ident,
// A short human readable description that appears in error messages
// when the boundaries of this type are violated.
$what:expr,
// The minimum value.
$min:expr,
// The maximum value.
$max:expr $(,)?
)),* $(,)?) => {
$(
pub(crate) struct $name(());
impl Bounds for $name {
const WHAT: &'static str = $what;
const MIN: Self::Primitive = $min;
const MAX: Self::Primitive = $max;
type Primitive = $ty;
#[cold]
#[inline(never)]
fn error() -> BoundsError {
BoundsError::$name(RawBoundsError::new())
}
}
impl $name {
pub(crate) const MIN: $ty = <$name as Bounds>::MIN;
pub(crate) const MAX: $ty = <$name as Bounds>::MAX;
const LEN: i128 = Self::MAX as i128 - Self::MIN as i128 + 1;
#[cold]
pub(crate) const fn error() -> BoundsError {
BoundsError::$name(RawBoundsError::new())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn check(n: impl Into<i64>) -> Result<$ty, BoundsError> {
<$name as Bounds>::check(n)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) const fn checkc(n: i64) -> Result<$ty, BoundsError> {
match self::checkc::$ty(n) {
Ok(n) => Ok(n),
Err(err) => Err(BoundsError::$name(err)),
}
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn check128(n: impl Into<i128>) -> Result<$ty, BoundsError> {
<$name as Bounds>::check128(n)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn parse(bytes: &[u8]) -> Result<$ty, Error> {
<$name as Bounds>::parse(bytes)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn checked_add(n1: $ty, n2: $ty) -> Result<$ty, BoundsError> {
<$name as Bounds>::checked_add(n1, n2)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn checked_sub(n1: $ty, n2: $ty) -> Result<$ty, BoundsError> {
<$name as Bounds>::checked_sub(n1, n2)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn checked_mul(n1: $ty, n2: $ty) -> Result<$ty, BoundsError> {
<$name as Bounds>::checked_mul(n1, n2)
}
#[cfg(test)]
pub(crate) fn arbitrary(g: &mut quickcheck::Gen) -> $ty {
use quickcheck::Arbitrary;
let mut n: $ty = <$ty>::arbitrary(g);
n = n.wrapping_rem_euclid(Self::LEN as $ty);
n += Self::MIN;
n
}
}
)*
#[derive(Clone, Debug)]
pub(crate) enum BoundsError {
$($name(RawBoundsError<$name>),)*
}
impl core::fmt::Display for BoundsError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match *self {
$(BoundsError::$name(ref err) => err.fmt(f),)*
}
}
}
}
}
define_bounds! {
(Century, i8, "century", 0, 99),
(
CivilDayNanosecond,
i64,
"nanoseconds (in one civil day)",
0,
NANOS_PER_CIVIL_DAY - 1,
),
(
CivilDaySecond,
i32,
"seconds (in one civil day)",
0,
SECS_PER_CIVIL_DAY_32 - 1,
),
(Day, i8, "day", 1, 31),
(DayOfYear, i16, "day-of-year", 1, 366),
(Hour, i8, "hour", 0, 23),
(Hour12, i8, "hour (12 hour clock)", 1, 12),
(ISOWeek, i8, "iso-week", 1, 53),
(ISOYear, i16, "iso-year", -9999, 9999),
(Increment, i64, "rounding increment", 1, 1_000_000_000),
(Increment32, i32, "rounding increment", 1, 1_000_000_000),
(LeapSecond, i8, "second", 0, 60),
(Microsecond, i16, "microsecond", 0, 999),
(Millisecond, i16, "millisecond", 0, 999),
(Minute, i8, "minute", 0, 59),
(Month, i8, "month", 1, 12),
(Nanosecond, i16, "nanosecond", 0, 999),
(NthWeekday, i32, "nth weekday", SpanWeeks::MIN, SpanWeeks::MAX),
(OffsetHours, i8, "time zone offset hours", -25, 25),
(OffsetMinutes, i8, "time zone offset minutes", -59, 59),
(OffsetSeconds, i8, "time zone offset seconds", -59, 59),
(
OffsetTotalSeconds,
i32,
"time zone offset total seconds",
-Self::MAX,
(OffsetHours::MAX as i32 * SECS_PER_HOUR_32)
+ (OffsetMinutes::MAX as i32 * MINS_PER_HOUR_32)
+ OffsetSeconds::MAX as i32,
),
(Second, i8, "second", 0, 59),
(SignedDurationSeconds, i64, "signed duration seconds", i64::MIN, i64::MAX),
(SpanYears, i16, "years", -Self::MAX, (Year::LEN - 1) as i16),
(SpanMonths, i32, "months", -Self::MAX, SpanYears::MAX as i32 * 12),
(SpanWeeks, i32, "weeks", -Self::MAX, SpanDays::MAX / DAYS_PER_WEEK_32),
(SpanDays, i32, "days", -Self::MAX, SpanHours::MAX / HOURS_PER_CIVIL_DAY_32),
(SpanHours, i32, "hours", -Self::MAX, (SpanMinutes::MAX / MINS_PER_HOUR) as i32),
(SpanMinutes, i64, "minutes", -Self::MAX, SpanSeconds::MAX / SECS_PER_MIN),
(
SpanSeconds,
i64,
"seconds",
-Self::MAX,
next_multiple_of(
UnixSeconds::LEN as i64
+ OffsetTotalSeconds::MAX as i64
+ SECS_PER_CIVIL_DAY,
SECS_PER_CIVIL_DAY,
),
),
(
SpanMilliseconds,
i64,
"milliseconds",
-Self::MAX,
SpanSeconds::MAX * MILLIS_PER_SEC,
),
(
SpanMicroseconds,
i64,
"microseconds",
-Self::MAX,
SpanMilliseconds::MAX * MICROS_PER_MILLI,
),
(SpanMultiple, i64, "span multiple", i64::MIN + 1, i64::MAX),
(SpanNanoseconds, i64, "nanoseconds", i64::MIN + 1, i64::MAX),
(SubsecNanosecond, i32, "subsecond nanosecond", 0, NANOS_PER_SEC_32 - 1),
(
SignedSubsecNanosecond,
i32,
"subsecond nanosecond",
-SubsecNanosecond::MAX,
SubsecNanosecond::MAX,
),
(
UnixEpochDays,
i32,
"Unix epoch days",
(UnixSeconds::MIN+ OffsetTotalSeconds::MIN as i64).div_euclid(SECS_PER_CIVIL_DAY) as i32,
(UnixSeconds::MAX + OffsetTotalSeconds::MAX as i64).div_euclid(SECS_PER_CIVIL_DAY) as i32,
),
(
UnixMilliseconds,
i64,
"Unix timestamp milliseconds",
UnixSeconds::MIN * MILLIS_PER_SEC,
UnixSeconds::MAX * MILLIS_PER_SEC,
),
(
UnixMicroseconds,
i64,
"Unix timestamp microseconds",
UnixMilliseconds::MIN * MICROS_PER_MILLI,
UnixMilliseconds::MAX * MICROS_PER_MILLI,
),
(
UnixSeconds,
i64,
"Unix timestamp seconds",
-377705116800 - OffsetTotalSeconds::MIN as i64,
253402300799 - OffsetTotalSeconds::MAX as i64,
),
(WeekNum, i8, "week-number", 0, 53),
(WeekdayMondayZero, i8, "weekday (Monday 0-indexed)", 0, 6),
(WeekdayMondayOne, i8, "weekday (Monday 1-indexed)", 1, 7),
(WeekdaySundayZero, i8, "weekday (Sunday 0-indexed)", 0, 6),
(WeekdaySundayOne, i8, "weekday (Sunday 1-indexed)", 1, 7),
(Year, i16, "year", -9999, 9999),
(YearCE, i16, "CE year", 1, Year::MAX),
(YearBCE, i16, "BCE year", 1, Year::MAX + 1),
(YearTwoDigit, i16, "year (2 digits)", 0, 99),
(
ZonedDayNanoseconds,
i64,
"nanoseconds (in one zoned datetime day)",
ZonedDaySeconds::MIN as i64 * NANOS_PER_SEC,
ZonedDaySeconds::MAX as i64 * NANOS_PER_SEC,
),
(
ZonedDaySeconds,
i32,
"seconds (in one zoned datetime day)",
1,
7 * SECS_PER_CIVIL_DAY_32,
),
}
pub(crate) trait Bounds: Sized {
const WHAT: &'static str;
const MIN: Self::Primitive;
const MAX: Self::Primitive;
type Primitive: Primitive;
fn error() -> BoundsError;
#[cfg_attr(feature = "perf-inline", inline(always))]
fn check(n: impl Into<i64>) -> Result<Self::Primitive, BoundsError> {
debug_assert!((i128::from(i64::MIN)..=i128::from(i64::MAX))
.contains(&Self::MIN.as_i128()));
debug_assert!((i128::from(i64::MIN)..=i128::from(i64::MAX))
.contains(&Self::MAX.as_i128()));
let n = n.into();
if !(Self::MIN.as_i64() <= n && n <= Self::MAX.as_i64()) {
return Err(Self::error());
}
Ok(Self::Primitive::from_i64(n))
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn check128(n: impl Into<i128>) -> Result<Self::Primitive, BoundsError> {
let n = n.into();
if !(Self::MIN.as_i128() <= n && n <= Self::MAX.as_i128()) {
return Err(Self::error());
}
Ok(Self::Primitive::from_i128(n))
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn check_self(n: Self::Primitive) -> Result<Self::Primitive, BoundsError> {
if !(Self::MIN <= n && n <= Self::MAX) {
return Err(Self::error());
}
Ok(n)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn parse(bytes: &[u8]) -> Result<Self::Primitive, Error> {
Ok(Self::check(crate::util::parse::i64(bytes)?)?)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn checked_add(
n1: Self::Primitive,
n2: Self::Primitive,
) -> Result<Self::Primitive, BoundsError> {
Self::check_self(n1.checked_add(n2).ok_or_else(Self::error)?)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn checked_sub(
n1: Self::Primitive,
n2: Self::Primitive,
) -> Result<Self::Primitive, BoundsError> {
Self::check_self(n1.checked_sub(n2).ok_or_else(Self::error)?)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn checked_mul(
n1: Self::Primitive,
n2: Self::Primitive,
) -> Result<Self::Primitive, BoundsError> {
Self::check_self(n1.checked_mul(n2).ok_or_else(Self::error)?)
}
}
pub(crate) trait Primitive:
Clone
+ Copy
+ Eq
+ PartialEq
+ PartialOrd
+ Ord
+ core::fmt::Debug
+ core::fmt::Display
{
fn as_i8(self) -> i8;
fn as_i16(self) -> i16;
fn as_i32(self) -> i32;
fn as_i64(self) -> i64;
fn as_i128(self) -> i128;
fn from_i8(n: i8) -> Self;
fn from_i16(n: i16) -> Self;
fn from_i32(n: i32) -> Self;
fn from_i64(n: i64) -> Self;
fn from_i128(n: i128) -> Self;
fn checked_add(self, n: Self) -> Option<Self>;
fn checked_sub(self, n: Self) -> Option<Self>;
fn checked_mul(self, n: Self) -> Option<Self>;
}
macro_rules! impl_primitive {
($($intty:ty),*) => {
$(
impl Primitive for $intty {
fn as_i8(self) -> i8 { self as i8 }
fn as_i16(self) -> i16 { self as i16 }
fn as_i32(self) -> i32 { self as i32 }
fn as_i64(self) -> i64 { self as i64 }
fn as_i128(self) -> i128 { self as i128 }
fn from_i8(n: i8) -> Self { n as $intty }
fn from_i16(n: i16) -> Self { n as $intty }
fn from_i32(n: i32) -> Self { n as $intty }
fn from_i64(n: i64) -> Self { n as $intty }
fn from_i128(n: i128) -> Self { n as $intty }
fn checked_add(self, n: $intty) -> Option<$intty> {
<$intty>::checked_add(self, n)
}
fn checked_sub(self, n: $intty) -> Option<$intty> {
<$intty>::checked_sub(self, n)
}
fn checked_mul(self, n: $intty) -> Option<$intty> {
<$intty>::checked_mul(self, n)
}
}
)*
}
}
impl_primitive!(i8, i16, i32, i64, i128);
impl From<BoundsError> for Error {
fn from(err: BoundsError) -> Error {
Error::bounds(err)
}
}
impl crate::error::IntoError for BoundsError {
fn into_error(self) -> Error {
self.into()
}
}
pub(crate) struct RawBoundsError<B>(core::marker::PhantomData<B>);
impl<B> RawBoundsError<B> {
const fn new() -> RawBoundsError<B> {
RawBoundsError(core::marker::PhantomData)
}
}
impl<B> Clone for RawBoundsError<B> {
fn clone(&self) -> RawBoundsError<B> {
RawBoundsError::new()
}
}
impl<B, P> core::fmt::Debug for RawBoundsError<B>
where
B: Bounds<Primitive = P>,
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("RawBoundsError")
.field("what", &B::WHAT)
.field("min", &B::MIN)
.field("max", &B::MAX)
.finish()
}
}
impl<B, P> core::fmt::Display for RawBoundsError<B>
where
B: Bounds<Primitive = P>,
P: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"parameter '{what}' is not in the required range of {min}..={max}",
what = B::WHAT,
min = B::MIN,
max = B::MAX,
)
}
}
#[derive(Clone, Debug)]
pub(crate) enum SpecialBoundsError {
UnixNanoseconds,
SignedDurationFloatOutOfRangeF32,
SignedDurationFloatOutOfRangeF64,
SignedToUnsignedDuration,
}
impl core::fmt::Display for SpecialBoundsError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use self::SpecialBoundsError::*;
let (what, min, max) = match *self {
UnixNanoseconds => (
"Unix timestamp nanoseconds",
UnixMicroseconds::MIN as i128 * (NANOS_PER_MICRO as i128),
UnixMicroseconds::MAX as i128 * (NANOS_PER_MICRO as i128),
),
SignedToUnsignedDuration => {
return f.write_str(
"negative signed durations cannot be converted \
to an unsigned duration",
);
}
SignedDurationFloatOutOfRangeF32 => {
return write!(
f,
"parameter 'floating point seconds' is not in \
the required range of {min}..={max}",
min = i64::MIN as f32,
max = i64::MAX as f32,
);
}
SignedDurationFloatOutOfRangeF64 => {
return write!(
f,
"parameter 'floating point seconds' is not in \
the required range of {min}..={max}",
min = i64::MIN as f64,
max = i64::MAX as f64,
);
}
};
write!(
f,
"parameter '{what}' is not in the required range of {min}..={max}",
)
}
}
impl From<SpecialBoundsError> for Error {
fn from(err: SpecialBoundsError) -> Error {
Error::special_bounds(err)
}
}
impl crate::error::IntoError for SpecialBoundsError {
fn into_error(self) -> Error {
self.into()
}
}
#[derive(
Clone, Copy, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord,
)]
#[repr(i8)]
pub(crate) enum Sign {
#[default]
Zero = 0,
Positive = 1,
Negative = -1,
}
impl Sign {
pub(crate) fn is_zero(self) -> bool {
matches!(self, Sign::Zero)
}
pub(crate) fn is_positive(self) -> bool {
matches!(self, Sign::Positive)
}
pub(crate) fn is_negative(self) -> bool {
matches!(self, Sign::Negative)
}
pub(crate) fn signum(self) -> i8 {
self.as_i8()
}
pub(crate) fn as_i8(self) -> i8 {
self as i8
}
pub(crate) fn as_i16(self) -> i16 {
i16::from(self.as_i8())
}
pub(crate) fn as_i32(self) -> i32 {
i32::from(self.as_i8())
}
pub(crate) fn as_i64(self) -> i64 {
i64::from(self.as_i8())
}
pub(crate) fn as_i128(self) -> i128 {
i128::from(self.as_i8())
}
pub(crate) fn from_ordinals<T: Ord>(t1: T, t2: T) -> Sign {
use core::cmp::Ordering::*;
match t1.cmp(&t2) {
Less => Sign::Negative,
Equal => Sign::Zero,
Greater => Sign::Positive,
}
}
}
impl core::ops::Neg for Sign {
type Output = Sign;
fn neg(self) -> Sign {
match self {
Sign::Positive => Sign::Negative,
Sign::Zero => Sign::Zero,
Sign::Negative => Sign::Positive,
}
}
}
impl From<i8> for Sign {
fn from(n: i8) -> Sign {
Sign::from(i64::from(n))
}
}
impl From<i16> for Sign {
fn from(n: i16) -> Sign {
Sign::from(i64::from(n))
}
}
impl From<i32> for Sign {
fn from(n: i32) -> Sign {
Sign::from(i64::from(n))
}
}
impl From<i64> for Sign {
fn from(n: i64) -> Sign {
if n == 0 {
Sign::Zero
} else if n > 0 {
Sign::Positive
} else {
Sign::Negative
}
}
}
impl From<i128> for Sign {
fn from(n: i128) -> Sign {
if n == 0 {
Sign::Zero
} else if n > 0 {
Sign::Positive
} else {
Sign::Negative
}
}
}
impl From<f64> for Sign {
fn from(n: f64) -> Sign {
use core::num::FpCategory::*;
if matches!(n.classify(), Nan | Zero) {
Sign::Zero
} else if n.is_sign_positive() {
Sign::Positive
} else {
Sign::Negative
}
}
}
impl From<SignedDuration> for Sign {
fn from(n: SignedDuration) -> Sign {
if n.is_zero() {
Sign::Zero
} else if n.is_positive() {
Sign::Positive
} else {
Sign::Negative
}
}
}
impl core::ops::Mul<Sign> for Sign {
type Output = Sign;
fn mul(self, rhs: Sign) -> Sign {
match (self, rhs) {
(Sign::Zero, _) | (_, Sign::Zero) => Sign::Zero,
(Sign::Positive, Sign::Positive) => Sign::Positive,
(Sign::Negative, Sign::Negative) => Sign::Positive,
(Sign::Positive, Sign::Negative) => Sign::Negative,
(Sign::Negative, Sign::Positive) => Sign::Negative,
}
}
}
impl core::ops::Mul<i8> for Sign {
type Output = i8;
fn mul(self, n: i8) -> i8 {
self.as_i8() * n
}
}
impl core::ops::Mul<Sign> for i8 {
type Output = i8;
fn mul(self, n: Sign) -> i8 {
self * n.as_i8()
}
}
impl core::ops::Mul<i16> for Sign {
type Output = i16;
fn mul(self, n: i16) -> i16 {
self.as_i16() * n
}
}
impl core::ops::Mul<Sign> for i16 {
type Output = i16;
fn mul(self, n: Sign) -> i16 {
self * n.as_i16()
}
}
impl core::ops::Mul<i32> for Sign {
type Output = i32;
fn mul(self, n: i32) -> i32 {
self.as_i32() * n
}
}
impl core::ops::Mul<Sign> for i32 {
type Output = i32;
fn mul(self, n: Sign) -> i32 {
self * n.as_i32()
}
}
impl core::ops::Mul<i64> for Sign {
type Output = i64;
fn mul(self, n: i64) -> i64 {
self.as_i64() * n
}
}
impl core::ops::Mul<Sign> for i64 {
type Output = i64;
fn mul(self, n: Sign) -> i64 {
self * n.as_i64()
}
}
impl core::ops::Mul<i128> for Sign {
type Output = i128;
fn mul(self, n: i128) -> i128 {
self.as_i128() * n
}
}
impl core::ops::Mul<Sign> for i128 {
type Output = i128;
fn mul(self, n: Sign) -> i128 {
self * n.as_i128()
}
}
impl core::fmt::Display for Sign {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
if self.is_negative() {
f.write_str("-")
} else {
Ok(())
}
}
}
mod checkc {
use super::{Bounds, RawBoundsError};
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(super) const fn i8<B>(n: i64) -> Result<i8, RawBoundsError<B>>
where
B: Bounds<Primitive = i8>,
{
debug_assert!(
(i64::MIN as i128) <= (B::MIN as i128)
&& (B::MIN as i128) <= (i64::MAX as i128),
);
debug_assert!(
(i64::MIN as i128) <= (B::MAX as i128)
&& (B::MAX as i128) <= (i64::MAX as i128),
);
if !((B::MIN as i64) <= n && n <= (B::MAX as i64)) {
return Err(RawBoundsError::new());
}
Ok(n as i8)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(super) const fn i16<B>(n: i64) -> Result<i16, RawBoundsError<B>>
where
B: Bounds<Primitive = i16>,
{
debug_assert!(
(i64::MIN as i128) <= (B::MIN as i128)
&& (B::MIN as i128) <= (i64::MAX as i128),
);
debug_assert!(
(i64::MIN as i128) <= (B::MAX as i128)
&& (B::MAX as i128) <= (i64::MAX as i128),
);
if !((B::MIN as i64) <= n && n <= (B::MAX as i64)) {
return Err(RawBoundsError::new());
}
Ok(n as i16)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(super) const fn i32<B>(n: i64) -> Result<i32, RawBoundsError<B>>
where
B: Bounds<Primitive = i32>,
{
debug_assert!(
(i64::MIN as i128) <= (B::MIN as i128)
&& (B::MIN as i128) <= (i64::MAX as i128),
);
debug_assert!(
(i64::MIN as i128) <= (B::MAX as i128)
&& (B::MAX as i128) <= (i64::MAX as i128),
);
if !((B::MIN as i64) <= n && n <= (B::MAX as i64)) {
return Err(RawBoundsError::new());
}
Ok(n as i32)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(super) const fn i64<B>(n: i64) -> Result<i64, RawBoundsError<B>>
where
B: Bounds<Primitive = i64>,
{
debug_assert!(
(i64::MIN as i128) <= (B::MIN as i128)
&& (B::MIN as i128) <= (i64::MAX as i128),
);
debug_assert!(
(i64::MIN as i128) <= (B::MAX as i128)
&& (B::MAX as i128) <= (i64::MAX as i128),
);
if !(B::MIN <= n && n <= B::MAX) {
return Err(RawBoundsError::new());
}
Ok(n)
}
}
const fn next_multiple_of(lhs: i64, rhs: i64) -> i64 {
if rhs == -1 {
return lhs;
}
let r = lhs % rhs;
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { r + rhs } else { r };
if m == 0 {
lhs
} else {
lhs + (rhs - m)
}
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
use super::*;
#[test]
fn size_of_bounds_error() {
assert_eq!(1, core::mem::size_of::<BoundsError>());
}
#[test]
fn basic_error_functionality() {
let err = Year::check(10_000).unwrap_err();
assert_eq!(
err.to_string(),
"parameter 'year' is not in the required range of -9999..=9999",
);
}
}