//! Macros for use within the library. They are not publicly available. /// Helper macro for easily implementing `OpAssign`. macro_rules! __impl_assign { ($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$( #[allow(unused_qualifications)] $(#[$attr])* impl core::ops::$op<$t> for $target { fn $fn(&mut self, rhs: $t) { *self = *self $sym rhs; } } )+}; } /// Implement `AddAssign` for the provided types. macro_rules! impl_add_assign { ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { $crate::internal_macros::__impl_assign!( + AddAssign add_assign $target : $($(#[$attr])* $t),+ ); }; } /// Implement `SubAssign` for the provided types. macro_rules! impl_sub_assign { ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { $crate::internal_macros::__impl_assign!( - SubAssign sub_assign $target : $($(#[$attr])* $t),+ ); }; } /// Implement `MulAssign` for the provided types. macro_rules! impl_mul_assign { ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { $crate::internal_macros::__impl_assign!( * MulAssign mul_assign $target : $($(#[$attr])* $t),+ ); }; } /// Implement `DivAssign` for the provided types. macro_rules! impl_div_assign { ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => { $crate::internal_macros::__impl_assign!( / DivAssign div_assign $target : $($(#[$attr])* $t),+ ); }; } /// Division of integers, rounding the resulting value towards negative infinity. macro_rules! div_floor { ($a:expr, $b:expr) => {{ let _a = $a; let _b = $b; let (_quotient, _remainder) = (_a / _b, _a % _b); if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) { _quotient - 1 } else { _quotient } }}; } /// Cascade an out-of-bounds value. macro_rules! cascade { (@ordinal ordinal) => {}; (@year year) => {}; // Cascade an out-of-bounds value from "from" to "to". ($from:ident in $min:literal.. $max:expr => $to:tt) => { #[allow(unused_comparisons, unused_assignments)] let min = $min; let max = $max; if $from >= max { $from -= max - min; $to += 1; } else if $from < min { $from += max - min; $to -= 1; } }; // Special case the ordinal-to-year cascade, as it has different behavior. ($ordinal:ident => $year:ident) => { // We need to actually capture the idents. Without this, macro hygiene causes errors. cascade!(@ordinal $ordinal); cascade!(@year $year); #[allow(unused_assignments)] if $ordinal > crate::util::days_in_year($year) as i16 { $ordinal -= crate::util::days_in_year($year) as i16; $year += 1; } else if $ordinal < 1 { $year -= 1; $ordinal += crate::util::days_in_year($year) as i16; } }; } /// Constructs a ranged integer, returning a `ComponentRange` error if the value is out of range. macro_rules! ensure_ranged { ($type:ident : $value:ident) => { match $type::new($value) { Some(val) => val, None => { #[allow(trivial_numeric_casts)] return Err(crate::error::ComponentRange { name: stringify!($value), minimum: $type::MIN.get() as _, maximum: $type::MAX.get() as _, value: $value as _, conditional_range: false, }); } } }; ($type:ident : $value:ident $(as $as_type:ident)? * $factor:expr) => { match ($value $(as $as_type)?).checked_mul($factor) { Some(val) => match $type::new(val) { Some(val) => val, None => { #[allow(trivial_numeric_casts)] return Err(crate::error::ComponentRange { name: stringify!($value), minimum: $type::MIN.get() as i64 / $factor as i64, maximum: $type::MAX.get() as i64 / $factor as i64, value: $value as _, conditional_range: false, }); } }, None => { return Err(crate::error::ComponentRange { name: stringify!($value), minimum: $type::MIN.get() as i64 / $factor as i64, maximum: $type::MAX.get() as i64 / $factor as i64, value: $value as _, conditional_range: false, }); } } }; } /// Try to unwrap an expression, returning if not possible. /// /// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is /// usable in `const` contexts. macro_rules! const_try { ($e:expr) => { match $e { Ok(value) => value, Err(error) => return Err(error), } }; } /// Try to unwrap an expression, returning if not possible. /// /// This is similar to the `?` operator, but is usable in `const` contexts. macro_rules! const_try_opt { ($e:expr) => { match $e { Some(value) => value, None => return None, } }; } /// Try to unwrap an expression, panicking if not possible. /// /// This is similar to `$e.expect($message)`, but is usable in `const` contexts. macro_rules! expect_opt { ($e:expr, $message:literal) => { match $e { Some(value) => value, None => crate::expect_failed($message), } }; } /// `unreachable!()`, but better. macro_rules! bug { () => { compile_error!("provide an error message to help fix a possible bug") }; ($descr:literal $($rest:tt)?) => { panic!(concat!("internal error: ", $descr) $($rest)?) } } pub(crate) use { __impl_assign, bug, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign, };