summaryrefslogtreecommitdiff
path: root/vendor/time/src/internal_macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/time/src/internal_macros.rs')
-rw-r--r--vendor/time/src/internal_macros.rs209
1 files changed, 209 insertions, 0 deletions
diff --git a/vendor/time/src/internal_macros.rs b/vendor/time/src/internal_macros.rs
new file mode 100644
index 00000000..74205ac4
--- /dev/null
+++ b/vendor/time/src/internal_macros.rs
@@ -0,0 +1,209 @@
+//! 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 {
+ ($self:expr, $rhs:expr) => {
+ match ($self, $rhs) {
+ (this, rhs) => {
+ let d = this / rhs;
+ let r = this % rhs;
+
+ // If the remainder is non-zero, we need to subtract one if the
+ // signs of self and rhs differ, as this means we rounded upwards
+ // instead of downwards. We do this branchlessly by creating a mask
+ // which is all-ones iff the signs differ, and 0 otherwise. Then by
+ // adding this mask (which corresponds to the signed value -1), we
+ // get our correction.
+ let correction = (this ^ rhs) >> ($crate::size_of_val(&this) * 8 - 1);
+ if r != 0 {
+ d + correction
+ } else {
+ d
+ }
+ }
+ }
+ };
+}
+
+/// 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 i64,
+ maximum: $type::MAX.get() as i64,
+ value: $value as i64,
+ conditional_message: None,
+ });
+ }
+ }
+ };
+
+ ($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 i64,
+ conditional_message: None,
+ });
+ }
+ },
+ 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 i64,
+ conditional_message: None,
+ });
+ }
+ }
+ };
+}
+
+/// 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.
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+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)?)
+ }
+}
+
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+pub(crate) use bug;
+pub(crate) use {
+ __impl_assign, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt,
+ impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
+};