gst/format: fix some ops and add others

Some operations were implemented on types that wouldn't result in
the expected physical unit. E.g.:

- `ClockTime / ClockTime` results in a unit-less factor.
- `u64 / ClockTime` would result in a `1 / ClockTime`. Since we don't
  use any `Frequency` type, this operation is removed. Users should
  use the `ClockTime` accessors to compute the expected value.

This commit also adds:

- multiplications with integers as the left hand side operands.
- `Partial{Eq,Ord} for `Signed<T>` with `T` as left hand side operand.
- `opt_add` / `opt_sub` for `Signed<T>` with `T` as left or right hand
   side operands.
- missing tests for `Partial{Eq,Ord}` and `OptionOrd`.

This implementation can interfere with unrelated code and was removed:

- `Signed<usize>.` `PartialOrd` makes existing code computing the len
  of slices needing type annotation because the len is later used in
  a comparison for which the compiler is unable to determine if
  the len is `Signed<usize>` or `usize`.
This commit is contained in:
François Laignel 2022-09-29 14:22:19 +02:00
parent eb4d997f0a
commit 57d8d46ab6
4 changed files with 443 additions and 43 deletions

View file

@ -288,7 +288,7 @@ impl TryFrom<Duration> for ClockTime {
let nanos = d.as_nanos(); let nanos = d.as_nanos();
// Note: `std::u64::MAX` is `ClockTime::None`. // Note: `std::u64::MAX` is `ClockTime::NONE`.
if nanos >= std::u64::MAX as u128 { if nanos >= std::u64::MAX as u128 {
return Err(DurationError); return Err(DurationError);
} }
@ -527,6 +527,8 @@ mod tests {
const CT_20: ClockTime = ClockTime::from_nseconds(20); const CT_20: ClockTime = ClockTime::from_nseconds(20);
const CT_30: ClockTime = ClockTime::from_nseconds(30); const CT_30: ClockTime = ClockTime::from_nseconds(30);
const P_CT_0: Signed<ClockTime> = Signed::Positive(ClockTime::ZERO);
const P_CT_NONE: Option<Signed<ClockTime>> = None;
const P_CT_1: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(1)); const P_CT_1: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(1));
const P_CT_2: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(2)); const P_CT_2: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(2));
const P_CT_3: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(3)); const P_CT_3: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(3));
@ -558,6 +560,8 @@ mod tests {
assert_eq!(CT_30 - CT_30, ClockTime::ZERO); assert_eq!(CT_30 - CT_30, ClockTime::ZERO);
assert_eq!(CT_10 * 3, CT_30); assert_eq!(CT_10 * 3, CT_30);
assert_eq!(3 * CT_10, CT_30); assert_eq!(3 * CT_10, CT_30);
assert_eq!(CT_20 / 2, CT_10);
assert_eq!(CT_20 / CT_2, 10);
assert_eq!(CT_30.nseconds(), 30); assert_eq!(CT_30.nseconds(), 30);
assert_eq!(P_CT_1 + P_CT_2, P_CT_3); assert_eq!(P_CT_1 + P_CT_2, P_CT_3);
@ -567,17 +571,30 @@ mod tests {
assert_eq!(N_CT_2 + P_CT_3, P_CT_1); assert_eq!(N_CT_2 + P_CT_3, P_CT_1);
assert_eq!(N_CT_2 + N_CT_1, N_CT_3); assert_eq!(N_CT_2 + N_CT_1, N_CT_3);
assert_eq!(CT_1 + P_CT_2, P_CT_3);
assert_eq!(P_CT_1 + CT_2, P_CT_3);
assert_eq!(CT_3 + N_CT_1, P_CT_2);
assert_eq!(N_CT_1 + CT_2, P_CT_1);
assert_eq!(P_CT_3 - P_CT_2, P_CT_1); assert_eq!(P_CT_3 - P_CT_2, P_CT_1);
assert_eq!(P_CT_2 - P_CT_3, N_CT_1); assert_eq!(P_CT_2 - P_CT_3, N_CT_1);
assert_eq!(P_CT_2 - N_CT_1, P_CT_3); assert_eq!(P_CT_2 - N_CT_1, P_CT_3);
assert_eq!(N_CT_2 - P_CT_1, N_CT_3); assert_eq!(N_CT_2 - P_CT_1, N_CT_3);
assert_eq!(N_CT_3 - N_CT_1, N_CT_2); assert_eq!(N_CT_3 - N_CT_1, N_CT_2);
assert_eq!(CT_3 - P_CT_2, P_CT_1);
assert_eq!(P_CT_3 - CT_2, P_CT_1);
assert_eq!(N_CT_2 - CT_1, N_CT_3);
assert_eq!(CT_2 - N_CT_1, P_CT_3);
assert_eq!(P_CT_1 * 2i64, P_CT_2); assert_eq!(P_CT_1 * 2i64, P_CT_2);
assert_eq!(P_CT_1 * -2i64, N_CT_2); assert_eq!(P_CT_1 * -2i64, N_CT_2);
assert_eq!(N_CT_1 * 2i64, N_CT_2); assert_eq!(N_CT_1 * 2i64, N_CT_2);
assert_eq!(N_CT_1 * -2i64, P_CT_2); assert_eq!(N_CT_1 * -2i64, P_CT_2);
assert_eq!(2i64 * P_CT_1, P_CT_2);
assert_eq!(-2i64 * P_CT_1, N_CT_2);
assert_eq!(P_CT_1 * 2u64, P_CT_2); assert_eq!(P_CT_1 * 2u64, P_CT_2);
assert_eq!(N_CT_1 * 2u64, N_CT_2); assert_eq!(N_CT_1 * 2u64, N_CT_2);
@ -586,6 +603,8 @@ mod tests {
assert_eq!(N_CT_2 / 2i64, N_CT_1); assert_eq!(N_CT_2 / 2i64, N_CT_1);
assert_eq!(N_CT_2 / -2i64, P_CT_1); assert_eq!(N_CT_2 / -2i64, P_CT_1);
assert_eq!(P_CT_2 / N_CT_2, Signed::Negative(1));
assert_eq!(P_CT_2 / 2u64, P_CT_1); assert_eq!(P_CT_2 / 2u64, P_CT_1);
assert_eq!(N_CT_2 / 2u64, N_CT_1); assert_eq!(N_CT_2 / 2u64, N_CT_1);
@ -594,6 +613,8 @@ mod tests {
assert_eq!(N_CT_3 % 2i64, N_CT_1); assert_eq!(N_CT_3 % 2i64, N_CT_1);
assert_eq!(N_CT_3 % -2i64, N_CT_1); assert_eq!(N_CT_3 % -2i64, N_CT_1);
assert_eq!(N_CT_3 % N_CT_2, N_CT_1);
assert_eq!(P_CT_3 % 2u64, P_CT_1); assert_eq!(P_CT_3 % 2u64, P_CT_1);
assert_eq!(N_CT_3 % 2u64, N_CT_1); assert_eq!(N_CT_3 % 2u64, N_CT_1);
} }
@ -611,8 +632,11 @@ mod tests {
assert_eq!(CT_1.opt_checked_add(CT_1), Ok(Some(CT_2))); assert_eq!(CT_1.opt_checked_add(CT_1), Ok(Some(CT_2)));
assert_eq!(CT_1.opt_checked_add(Some(CT_1)), Ok(Some(CT_2))); assert_eq!(CT_1.opt_checked_add(Some(CT_1)), Ok(Some(CT_2)));
assert_eq!(Some(CT_1).opt_checked_add(Some(CT_1)), Ok(Some(CT_2))); assert_eq!(Some(CT_1).opt_checked_add(Some(CT_1)), Ok(Some(CT_2)));
assert_eq!(CT_1.opt_checked_add(None), Ok(None)); assert_eq!(CT_1.opt_checked_add(ClockTime::NONE), Ok(None));
assert_eq!(Some(CT_1).opt_checked_add(None), Ok(None)); assert_eq!(Some(CT_1).opt_checked_add(ClockTime::NONE), Ok(None));
assert_eq!(CT_1.opt_checked_add(P_CT_1), Ok(Some(P_CT_2)));
assert_eq!(N_CT_3.opt_checked_add(CT_1), Ok(Some(N_CT_2)));
assert!(ClockTime::MAX.checked_add(CT_1).is_none()); assert!(ClockTime::MAX.checked_add(CT_1).is_none());
assert_eq!( assert_eq!(
@ -623,8 +647,8 @@ mod tests {
assert_eq!(P_CT_1.opt_checked_add(P_CT_1), Ok(Some(P_CT_2))); assert_eq!(P_CT_1.opt_checked_add(P_CT_1), Ok(Some(P_CT_2)));
assert_eq!(P_CT_1.opt_checked_add(Some(N_CT_2)), Ok(Some(N_CT_1))); assert_eq!(P_CT_1.opt_checked_add(Some(N_CT_2)), Ok(Some(N_CT_1)));
assert_eq!(Some(P_CT_1).opt_checked_add(Some(P_CT_1)), Ok(Some(P_CT_2))); assert_eq!(Some(P_CT_1).opt_checked_add(Some(P_CT_1)), Ok(Some(P_CT_2)));
assert_eq!(P_CT_1.opt_checked_add(None), Ok(None)); assert_eq!(P_CT_1.opt_checked_add(ClockTime::NONE), Ok(None));
assert_eq!(Some(N_CT_1).opt_checked_add(None), Ok(None)); assert_eq!(Some(N_CT_1).opt_checked_add(ClockTime::NONE), Ok(None));
assert_eq!( assert_eq!(
ClockTime::MAX.into_positive().opt_checked_add(Some(P_CT_1)), ClockTime::MAX.into_positive().opt_checked_add(Some(P_CT_1)),
@ -643,8 +667,11 @@ mod tests {
assert_eq!(CT_2.opt_checked_sub(Some(CT_1)), Ok(Some(CT_1))); assert_eq!(CT_2.opt_checked_sub(Some(CT_1)), Ok(Some(CT_1)));
assert_eq!(Some(CT_2).opt_checked_sub(CT_1), Ok(Some(CT_1))); assert_eq!(Some(CT_2).opt_checked_sub(CT_1), Ok(Some(CT_1)));
assert_eq!(Some(CT_2).opt_checked_sub(Some(CT_1)), Ok(Some(CT_1))); assert_eq!(Some(CT_2).opt_checked_sub(Some(CT_1)), Ok(Some(CT_1)));
assert_eq!(CT_2.opt_checked_sub(None), Ok(None)); assert_eq!(CT_2.opt_checked_sub(ClockTime::NONE), Ok(None));
assert_eq!(Some(CT_2).opt_checked_sub(None), Ok(None)); assert_eq!(Some(CT_2).opt_checked_sub(ClockTime::NONE), Ok(None));
assert_eq!(P_CT_2.opt_checked_sub(CT_1), Ok(Some(P_CT_1)));
assert_eq!(N_CT_2.opt_checked_sub(CT_1), Ok(Some(N_CT_3)));
assert!(CT_1.checked_sub(CT_2).is_none()); assert!(CT_1.checked_sub(CT_2).is_none());
assert_eq!( assert_eq!(
@ -656,6 +683,8 @@ mod tests {
assert_eq!(Some(N_CT_2).opt_checked_sub(P_CT_1), Ok(Some(N_CT_3))); assert_eq!(Some(N_CT_2).opt_checked_sub(P_CT_1), Ok(Some(N_CT_3)));
assert_eq!(CT_1.checked_mul(2), Some(CT_2)); assert_eq!(CT_1.checked_mul(2), Some(CT_2));
assert_eq!(Some(CT_1).opt_checked_mul(2), Ok(Some(CT_2)));
assert_eq!(1u64.opt_checked_mul(Some(CT_2)), Ok(Some(CT_2)));
assert_eq!(P_CT_1.checked_mul(2), Some(P_CT_2)); assert_eq!(P_CT_1.checked_mul(2), Some(P_CT_2));
assert_eq!(P_CT_1.checked_mul(-2), Some(N_CT_2)); assert_eq!(P_CT_1.checked_mul(-2), Some(N_CT_2));
assert_eq!(N_CT_1.checked_mul(2), Some(N_CT_2)); assert_eq!(N_CT_1.checked_mul(2), Some(N_CT_2));
@ -664,6 +693,8 @@ mod tests {
assert_eq!(Some(P_CT_1).opt_checked_mul(-2i64), Ok(Some(N_CT_2))); assert_eq!(Some(P_CT_1).opt_checked_mul(-2i64), Ok(Some(N_CT_2)));
assert_eq!(N_CT_1.opt_checked_mul(2u64), Ok(Some(N_CT_2))); assert_eq!(N_CT_1.opt_checked_mul(2u64), Ok(Some(N_CT_2)));
assert_eq!((-2i64).opt_checked_mul(Some(P_CT_1)), Ok(Some(N_CT_2)));
assert_eq!(P_CT_1.checked_mul_unsigned(2u64), Some(P_CT_2)); assert_eq!(P_CT_1.checked_mul_unsigned(2u64), Some(P_CT_2));
assert_eq!(N_CT_1.checked_mul_unsigned(2u64), Some(N_CT_2)); assert_eq!(N_CT_1.checked_mul_unsigned(2u64), Some(N_CT_2));
@ -673,6 +704,8 @@ mod tests {
assert_eq!(N_CT_3.checked_div(3), Some(N_CT_1)); assert_eq!(N_CT_3.checked_div(3), Some(N_CT_1));
assert_eq!(N_CT_3.checked_div(-3), Some(P_CT_1)); assert_eq!(N_CT_3.checked_div(-3), Some(P_CT_1));
assert_eq!(Some(CT_3).opt_checked_div(CT_3), Ok(Some(1)));
assert_eq!(Some(P_CT_3).opt_checked_div(-3i64), Ok(Some(N_CT_1))); assert_eq!(Some(P_CT_3).opt_checked_div(-3i64), Ok(Some(N_CT_1)));
assert_eq!(N_CT_3.opt_checked_div(3u64), Ok(Some(N_CT_1))); assert_eq!(N_CT_3.opt_checked_div(3u64), Ok(Some(N_CT_1)));
@ -689,6 +722,7 @@ mod tests {
Some(CT_1).opt_overflowing_add(Some(CT_2)), Some(CT_1).opt_overflowing_add(Some(CT_2)),
Some((CT_3, false)) Some((CT_3, false))
); );
assert_eq!(ClockTime::NONE.opt_overflowing_add(CT_2), None); assert_eq!(ClockTime::NONE.opt_overflowing_add(CT_2), None);
assert_eq!(CT_1.opt_overflowing_add(ClockTime::NONE), None); assert_eq!(CT_1.opt_overflowing_add(ClockTime::NONE), None);
@ -737,7 +771,10 @@ mod tests {
assert_eq!(CT_1.opt_saturating_add(Some(CT_2)), Some(CT_3)); assert_eq!(CT_1.opt_saturating_add(Some(CT_2)), Some(CT_3));
assert_eq!(Some(CT_1).opt_saturating_add(Some(CT_2)), Some(CT_3)); assert_eq!(Some(CT_1).opt_saturating_add(Some(CT_2)), Some(CT_3));
assert_eq!(Some(CT_1).opt_saturating_add(None), None); assert_eq!(Some(CT_1).opt_saturating_add(ClockTime::NONE), None);
assert_eq!(P_CT_1.opt_saturating_add(Some(CT_2)), Some(P_CT_3));
assert_eq!(Some(CT_1).opt_saturating_add(P_CT_2), Some(P_CT_3));
assert_eq!(ClockTime::MAX.saturating_add(CT_1), ClockTime::MAX); assert_eq!(ClockTime::MAX.saturating_add(CT_1), ClockTime::MAX);
assert_eq!( assert_eq!(
@ -756,7 +793,10 @@ mod tests {
assert_eq!(CT_3.opt_saturating_sub(Some(CT_2)), Some(CT_1)); assert_eq!(CT_3.opt_saturating_sub(Some(CT_2)), Some(CT_1));
assert_eq!(Some(CT_3).opt_saturating_sub(Some(CT_2)), Some(CT_1)); assert_eq!(Some(CT_3).opt_saturating_sub(Some(CT_2)), Some(CT_1));
assert_eq!(Some(CT_3).opt_saturating_sub(None), None); assert_eq!(Some(CT_3).opt_saturating_sub(ClockTime::NONE), None);
assert_eq!(P_CT_2.opt_saturating_sub(Some(CT_3)), Some(N_CT_1));
assert_eq!(Some(CT_3).opt_saturating_sub(P_CT_2), Some(P_CT_1));
assert!(CT_1.saturating_sub(CT_2).is_zero()); assert!(CT_1.saturating_sub(CT_2).is_zero());
assert_eq!(P_CT_1.saturating_sub(P_CT_2), N_CT_1); assert_eq!(P_CT_1.saturating_sub(P_CT_2), N_CT_1);
@ -773,12 +813,18 @@ mod tests {
assert_eq!(N_CT_1.saturating_mul(2), N_CT_2); assert_eq!(N_CT_1.saturating_mul(2), N_CT_2);
assert_eq!(N_CT_1.saturating_mul(-2), P_CT_2); assert_eq!(N_CT_1.saturating_mul(-2), P_CT_2);
assert_eq!(Some(N_CT_1).opt_saturating_mul(-2i64), Some(P_CT_2));
assert_eq!((-2i64).opt_saturating_mul(Some(N_CT_1)), Some(P_CT_2));
assert_eq!(P_CT_1.saturating_mul_unsigned(2u64), P_CT_2); assert_eq!(P_CT_1.saturating_mul_unsigned(2u64), P_CT_2);
assert_eq!(N_CT_1.saturating_mul_unsigned(2u64), N_CT_2); assert_eq!(N_CT_1.saturating_mul_unsigned(2u64), N_CT_2);
assert_eq!(p_ct_max.saturating_mul(2), p_ct_max); assert_eq!(p_ct_max.saturating_mul(2), p_ct_max);
assert_eq!(n_ct_max.saturating_mul(2), n_ct_max); assert_eq!(n_ct_max.saturating_mul(2), n_ct_max);
assert_eq!(Some(2i64).opt_saturating_mul(p_ct_max), Some(p_ct_max));
assert_eq!(2u64.opt_saturating_mul(Some(n_ct_max)), Some(n_ct_max));
assert_eq!(p_ct_max.saturating_mul_unsigned(2u64), p_ct_max); assert_eq!(p_ct_max.saturating_mul_unsigned(2u64), p_ct_max);
assert_eq!(n_ct_max.saturating_mul_unsigned(2u64), n_ct_max); assert_eq!(n_ct_max.saturating_mul_unsigned(2u64), n_ct_max);
} }
@ -801,7 +847,7 @@ mod tests {
assert_eq!(CT_3.opt_wrapping_sub(CT_2), Some(CT_1)); assert_eq!(CT_3.opt_wrapping_sub(CT_2), Some(CT_1));
assert_eq!(Some(CT_3).opt_wrapping_sub(CT_2), Some(CT_1)); assert_eq!(Some(CT_3).opt_wrapping_sub(CT_2), Some(CT_1));
assert_eq!(Some(CT_3).opt_wrapping_sub(Some(CT_2)), Some(CT_1)); assert_eq!(Some(CT_3).opt_wrapping_sub(Some(CT_2)), Some(CT_1));
assert_eq!(Some(CT_3).opt_wrapping_sub(None), None); assert_eq!(Some(CT_3).opt_wrapping_sub(ClockTime::NONE), None);
assert_eq!(CT_1.wrapping_sub(CT_2), ClockTime::MAX); assert_eq!(CT_1.wrapping_sub(CT_2), ClockTime::MAX);
assert_eq!( assert_eq!(
@ -864,6 +910,9 @@ mod tests {
assert!(ClockTime::ZERO < CT_3); assert!(ClockTime::ZERO < CT_3);
assert!(Some(ClockTime::ZERO) < Some(CT_3)); assert!(Some(ClockTime::ZERO) < Some(CT_3));
assert_eq!(CT_2, CT_2);
assert_ne!(CT_3, CT_2);
assert!(ClockTime::ZERO.into_positive() < P_CT_1); assert!(ClockTime::ZERO.into_positive() < P_CT_1);
assert!(ClockTime::ZERO.into_positive() > N_CT_1); assert!(ClockTime::ZERO.into_positive() > N_CT_1);
assert!(P_CT_1 < P_CT_2); assert!(P_CT_1 < P_CT_2);
@ -871,11 +920,35 @@ mod tests {
assert!(N_CT_1 < P_CT_2); assert!(N_CT_1 < P_CT_2);
assert!(N_CT_3 < N_CT_2); assert!(N_CT_3 < N_CT_2);
assert!(P_CT_1 < CT_2);
assert!(CT_1 < P_CT_2);
assert!(N_CT_2 < CT_1);
assert!(CT_1 > N_CT_2);
assert_eq!(CT_2, P_CT_2);
assert_ne!(N_CT_3, CT_3);
assert_eq!(Some(CT_2).opt_lt(Some(CT_3)), Some(true)); assert_eq!(Some(CT_2).opt_lt(Some(CT_3)), Some(true));
assert_eq!(Some(CT_3).opt_lt(CT_2), Some(false)); assert_eq!(Some(CT_3).opt_lt(CT_2), Some(false));
assert_eq!(Some(CT_2).opt_le(Some(CT_3)), Some(true)); assert_eq!(Some(CT_2).opt_le(Some(CT_3)), Some(true));
assert_eq!(Some(CT_3).opt_le(CT_3), Some(true)); assert_eq!(Some(CT_3).opt_le(CT_3), Some(true));
assert_eq!(Some(P_CT_2).opt_lt(Some(P_CT_3)), Some(true));
assert_eq!(Some(P_CT_3).opt_lt(P_CT_2), Some(false));
assert_eq!(Some(P_CT_2).opt_le(Some(P_CT_3)), Some(true));
assert_eq!(Some(P_CT_3).opt_le(P_CT_3), Some(true));
assert_eq!(Some(P_CT_0).opt_lt(P_CT_NONE), None);
assert_eq!(P_CT_NONE.opt_lt(P_CT_0), None);
assert_eq!(Some(N_CT_3).opt_lt(Some(N_CT_2)), Some(true));
assert_eq!(Some(N_CT_2).opt_lt(N_CT_3), Some(false));
assert_eq!(Some(N_CT_3).opt_le(Some(N_CT_2)), Some(true));
assert_eq!(Some(N_CT_3).opt_le(N_CT_3), Some(true));
assert_eq!(Some(P_CT_2).opt_lt(N_CT_3), Some(false));
assert_eq!(Some(N_CT_3).opt_lt(Some(P_CT_2)), Some(true));
assert!(CT_3 > CT_2); assert!(CT_3 > CT_2);
assert!(Some(CT_3) > Some(CT_2)); assert!(Some(CT_3) > Some(CT_2));
assert!(CT_2 > ClockTime::ZERO); assert!(CT_2 > ClockTime::ZERO);
@ -891,6 +964,20 @@ mod tests {
assert_eq!(Some(CT_3).opt_ge(Some(CT_2)), Some(true)); assert_eq!(Some(CT_3).opt_ge(Some(CT_2)), Some(true));
assert_eq!(Some(CT_3).opt_ge(CT_3), Some(true)); assert_eq!(Some(CT_3).opt_ge(CT_3), Some(true));
assert_eq!(Some(P_CT_3).opt_gt(Some(P_CT_2)), Some(true));
assert_eq!(Some(P_CT_3).opt_ge(Some(P_CT_2)), Some(true));
assert_eq!(Some(P_CT_3).opt_ge(P_CT_3), Some(true));
assert_eq!(Some(P_CT_0).opt_gt(P_CT_NONE), None);
assert_eq!(P_CT_NONE.opt_gt(P_CT_0), None);
assert_eq!(Some(N_CT_3).opt_gt(Some(N_CT_2)), Some(false));
assert_eq!(Some(N_CT_3).opt_ge(Some(N_CT_2)), Some(false));
assert_eq!(Some(N_CT_3).opt_ge(N_CT_3), Some(true));
assert_eq!(Some(P_CT_2).opt_gt(N_CT_3), Some(true));
assert_eq!(Some(N_CT_3).opt_gt(Some(P_CT_2)), Some(false));
assert!(!(ClockTime::NONE < None)); assert!(!(ClockTime::NONE < None));
assert!(!(ClockTime::NONE > None)); assert!(!(ClockTime::NONE > None));
@ -914,11 +1001,23 @@ mod tests {
assert_eq!(ClockTime::NONE.opt_min(Some(CT_2)), None); assert_eq!(ClockTime::NONE.opt_min(Some(CT_2)), None);
assert_eq!(Some(CT_3).opt_min(ClockTime::NONE), None); assert_eq!(Some(CT_3).opt_min(ClockTime::NONE), None);
assert_eq!(P_CT_3.opt_min(P_CT_2), Some(P_CT_2));
assert_eq!(P_CT_2.opt_min(P_CT_3), Some(P_CT_2));
assert_eq!(N_CT_3.opt_min(N_CT_2), Some(N_CT_3));
assert_eq!(N_CT_2.opt_min(N_CT_3), Some(N_CT_3));
assert_eq!(P_CT_2.opt_min(N_CT_3), Some(N_CT_3));
assert_eq!(CT_3.opt_max(CT_2), Some(CT_3)); assert_eq!(CT_3.opt_max(CT_2), Some(CT_3));
assert_eq!(CT_3.opt_max(Some(CT_2)), Some(CT_3)); assert_eq!(CT_3.opt_max(Some(CT_2)), Some(CT_3));
assert_eq!(Some(CT_3).opt_max(Some(CT_2)), Some(CT_3)); assert_eq!(Some(CT_3).opt_max(Some(CT_2)), Some(CT_3));
assert_eq!(ClockTime::NONE.opt_max(Some(CT_2)), None); assert_eq!(ClockTime::NONE.opt_max(Some(CT_2)), None);
assert_eq!(Some(CT_3).opt_max(ClockTime::NONE), None); assert_eq!(Some(CT_3).opt_max(ClockTime::NONE), None);
assert_eq!(P_CT_3.opt_max(P_CT_2), Some(P_CT_3));
assert_eq!(P_CT_2.opt_max(P_CT_3), Some(P_CT_3));
assert_eq!(N_CT_3.opt_max(N_CT_2), Some(N_CT_2));
assert_eq!(N_CT_2.opt_max(N_CT_3), Some(N_CT_2));
assert_eq!(P_CT_2.opt_max(N_CT_3), Some(P_CT_2));
} }
#[test] #[test]

View file

@ -106,14 +106,6 @@ macro_rules! impl_trait_op_inner_type(
} }
} }
impl std::ops::$op<$name> for $inner_type {
type Output = $name;
fn $op_name(self, rhs: $name) -> $name {
$name(self.$op_name(rhs.0))
}
}
impl std::ops::$op_assign<$inner_type> for $name { impl std::ops::$op_assign<$inner_type> for $name {
fn $op_assign_name(&mut self, rhs: $inner_type) { fn $op_assign_name(&mut self, rhs: $inner_type) {
self.0.$op_assign_name(rhs) self.0.$op_assign_name(rhs)
@ -192,9 +184,9 @@ macro_rules! impl_non_trait_op_inner_type(
); );
macro_rules! impl_unsigned_int_into_signed( macro_rules! impl_unsigned_int_into_signed(
($name:ident) => { ($type:ty) => {
impl crate::UnsignedIntoSigned for $name { impl crate::UnsignedIntoSigned for $type {
type Signed = crate::Signed<$name>; type Signed = crate::Signed<$type>;
fn into_positive(self) -> Self::Signed { fn into_positive(self) -> Self::Signed {
crate::Signed::Positive(self) crate::Signed::Positive(self)
@ -205,8 +197,8 @@ macro_rules! impl_unsigned_int_into_signed(
} }
} }
impl crate::UnsignedIntoSigned for Option<$name> { impl crate::UnsignedIntoSigned for Option<$type> {
type Signed = Option<crate::Signed<$name>>; type Signed = Option<crate::Signed<$type>>;
fn into_positive(self) -> Self::Signed { fn into_positive(self) -> Self::Signed {
Some(self?.into_positive()) Some(self?.into_positive())
@ -217,6 +209,22 @@ macro_rules! impl_unsigned_int_into_signed(
} }
} }
}; };
($type:ty, $inner_type:ty) => {
impl_unsigned_int_into_signed!($type);
impl crate::Signed<$type> {
// rustdoc-stripper-ignore-next
/// Returns a `Signed` containing the inner type of `self`.
pub fn into_inner_signed(self) -> crate::Signed<$inner_type> {
use crate::Signed::*;
match self {
Positive(new_type) => Positive(*new_type),
Negative(new_type) => Negative(*new_type),
}
}
}
};
); );
macro_rules! impl_common_ops_for_newtype_uint( macro_rules! impl_common_ops_for_newtype_uint(
@ -235,19 +243,39 @@ macro_rules! impl_common_ops_for_newtype_uint(
impl_trait_op_same!($name, Add, add, AddAssign, add_assign); impl_trait_op_same!($name, Add, add, AddAssign, add_assign);
impl_trait_op_same!($name, Sub, sub, SubAssign, sub_assign); impl_trait_op_same!($name, Sub, sub, SubAssign, sub_assign);
impl_trait_op_same!($name, Mul, mul, MulAssign, mul_assign); impl std::ops::Div<$name> for $name {
impl_trait_op_same!($name, Div, div, DivAssign, div_assign); type Output = $inner_type;
impl_trait_op_same!($name, Rem, rem, RemAssign, rem_assign);
fn div(self, rhs: $name) -> $inner_type {
self.0.div(rhs.0)
}
}
impl std::ops::Rem<$name> for $name {
type Output = Self;
fn rem(self, rhs: Self) -> Self {
Self(self.0.rem(rhs.0))
}
}
impl_non_trait_op_same!($name, $inner_type); impl_non_trait_op_same!($name, $inner_type);
impl_trait_op_inner_type!($name, $inner_type, Mul, mul, MulAssign, mul_assign); impl_trait_op_inner_type!($name, $inner_type, Mul, mul, MulAssign, mul_assign);
impl std::ops::Mul<$name> for $inner_type {
type Output = $name;
fn mul(self, rhs: $name) -> $name {
$name(self.mul(rhs.0))
}
}
impl_trait_op_inner_type!($name, $inner_type, Div, div, DivAssign, div_assign); impl_trait_op_inner_type!($name, $inner_type, Div, div, DivAssign, div_assign);
impl_trait_op_inner_type!($name, $inner_type, Rem, rem, RemAssign, rem_assign); impl_trait_op_inner_type!($name, $inner_type, Rem, rem, RemAssign, rem_assign);
impl_non_trait_op_inner_type!($name, $inner_type); impl_non_trait_op_inner_type!($name, $inner_type);
impl_unsigned_int_into_signed!($name); impl_unsigned_int_into_signed!($name, $inner_type);
impl_signed_ops!($name, $inner_type, $name::ZERO); impl_signed_ops!($name, $inner_type, $name::ZERO);
impl muldiv::MulDiv<$inner_type> for $name { impl muldiv::MulDiv<$inner_type> for $name {
@ -314,10 +342,23 @@ macro_rules! impl_common_ops_for_newtype_uint(
if rhs == 0 { if rhs == 0 {
return Err(opt_ops::Error::DivisionByZero); return Err(opt_ops::Error::DivisionByZero);
} }
self.0 self
.checked_div(rhs) .checked_div(rhs)
.ok_or(opt_ops::Error::Overflow) .ok_or(opt_ops::Error::Overflow)
.map(|val| Some(Self(val))) .map(Some)
}
}
impl opt_ops::OptionCheckedDiv for $name {
type Output = $inner_type;
fn opt_checked_div(self, rhs: Self) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs.0 == 0 {
return Err(opt_ops::Error::DivisionByZero);
}
self.0
.checked_div(rhs.0)
.ok_or(opt_ops::Error::Overflow)
.map(Some)
} }
} }
@ -333,6 +374,18 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl opt_ops::OptionCheckedMul<$name> for $inner_type {
type Output = $name;
fn opt_checked_mul(
self,
rhs: $name,
) -> Result<Option<Self::Output>, opt_ops::Error> {
rhs.checked_mul(self)
.ok_or(opt_ops::Error::Overflow)
.map(Some)
}
}
impl opt_ops::OptionSaturatingMul<$inner_type> for $name { impl opt_ops::OptionSaturatingMul<$inner_type> for $name {
type Output = Self; type Output = Self;
fn opt_saturating_mul(self, rhs: $inner_type) -> Option<Self::Output> { fn opt_saturating_mul(self, rhs: $inner_type) -> Option<Self::Output> {
@ -340,6 +393,13 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl opt_ops::OptionSaturatingMul<$name> for $inner_type {
type Output = $name;
fn opt_saturating_mul(self, rhs: $name) -> Option<Self::Output> {
Some(rhs.saturating_mul(self))
}
}
impl opt_ops::OptionOverflowingMul<$inner_type> for $name { impl opt_ops::OptionOverflowingMul<$inner_type> for $name {
type Output = Self; type Output = Self;
fn opt_overflowing_mul(self, rhs: $inner_type) -> Option<(Self::Output, bool)> { fn opt_overflowing_mul(self, rhs: $inner_type) -> Option<(Self::Output, bool)> {
@ -348,6 +408,14 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl opt_ops::OptionOverflowingMul<$name> for $inner_type {
type Output = $name;
fn opt_overflowing_mul(self, rhs: $name) -> Option<(Self::Output, bool)> {
let res = rhs.overflowing_mul(self);
Some((res.0, res.1))
}
}
impl opt_ops::OptionWrappingMul<$inner_type> for $name { impl opt_ops::OptionWrappingMul<$inner_type> for $name {
type Output = Self; type Output = Self;
fn opt_wrapping_mul(self, rhs: $inner_type) -> Option<Self::Output> { fn opt_wrapping_mul(self, rhs: $inner_type) -> Option<Self::Output> {
@ -355,16 +423,34 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl opt_ops::OptionWrappingMul<$name> for $inner_type {
type Output = $name;
fn opt_wrapping_mul(self, rhs: $name) -> Option<Self::Output> {
Some(rhs.wrapping_mul(self))
}
}
impl opt_ops::OptionCheckedRem<$inner_type> for $name { impl opt_ops::OptionCheckedRem<$inner_type> for $name {
type Output = Self; type Output = Self;
fn opt_checked_rem(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> { fn opt_checked_rem(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs == 0 { if rhs == 0 {
return Err(opt_ops::Error::DivisionByZero); return Err(opt_ops::Error::DivisionByZero);
} }
self.0 self.checked_rem(rhs)
.checked_rem(rhs)
.ok_or(opt_ops::Error::Overflow) .ok_or(opt_ops::Error::Overflow)
.map(|val| Some(Self(val))) .map(Some)
}
}
impl opt_ops::OptionCheckedRem for $name {
type Output = Self;
fn opt_checked_rem(self, rhs: Self) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs.0 == 0 {
return Err(opt_ops::Error::DivisionByZero);
}
self.checked_rem(rhs.0)
.ok_or(opt_ops::Error::Overflow)
.map(Some)
} }
} }
@ -409,10 +495,6 @@ macro_rules! impl_signed_ops(
impl_signed_ops!(u64, u64, 0); impl_signed_ops!(u64, u64, 0);
}; };
(usize) => {
impl_signed_ops!(usize, usize, 0);
};
(u32) => { (u32) => {
impl_signed_ops!(u32, u32, 0); impl_signed_ops!(u32, u32, 0);
}; };
@ -577,6 +659,20 @@ macro_rules! impl_signed_ops(
} }
} }
impl std::ops::Add<crate::Signed<$type>> for $type {
type Output = crate::Signed<$type>;
fn add(self, other: crate::Signed<$type>) -> crate::Signed<$type> {
crate::Signed::Positive(self).checked_add(other).expect("Overflowing addition")
}
}
impl std::ops::Sub<crate::Signed<$type>> for $type {
type Output = crate::Signed<$type>;
fn sub(self, other: crate::Signed<$type>) -> crate::Signed<$type> {
crate::Signed::Positive(self).checked_sub(other).expect("Overflowing subtraction")
}
}
impl std::cmp::PartialOrd<crate::Signed<$type>> for crate::Signed<$type> { impl std::cmp::PartialOrd<crate::Signed<$type>> for crate::Signed<$type> {
fn partial_cmp(&self, other: &crate::Signed<$type>) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &crate::Signed<$type>) -> Option<std::cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
@ -589,12 +685,24 @@ macro_rules! impl_signed_ops(
} }
} }
impl std::cmp::PartialEq<crate::Signed<$type>> for $type {
fn eq(&self, other: &crate::Signed<$type>) -> bool {
crate::Signed::Positive(*self).eq(other)
}
}
impl std::cmp::PartialOrd<$type> for crate::Signed<$type> { impl std::cmp::PartialOrd<$type> for crate::Signed<$type> {
fn partial_cmp(&self, other: &$type) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &$type) -> Option<std::cmp::Ordering> {
Some(self.cmp(&crate::Signed::Positive(*other))) Some(self.cmp(&crate::Signed::Positive(*other)))
} }
} }
impl std::cmp::PartialOrd<crate::Signed<$type>> for $type {
fn partial_cmp(&self, other: &crate::Signed<$type>) -> Option<std::cmp::Ordering> {
Some(crate::Signed::Positive(*self).cmp(other))
}
}
impl std::cmp::Ord for crate::Signed<$type> { impl std::cmp::Ord for crate::Signed<$type> {
fn cmp(&self, other: &crate::Signed<$type>) -> std::cmp::Ordering { fn cmp(&self, other: &crate::Signed<$type>) -> std::cmp::Ordering {
use crate::Signed::*; use crate::Signed::*;
@ -646,32 +754,111 @@ macro_rules! impl_signed_ops(
Some(self.saturating_sub(rhs)) Some(self.saturating_sub(rhs))
} }
} }
impl opt_ops::OptionCheckedAdd<$type> for crate::Signed<$type> {
type Output = Self;
fn opt_checked_add(
self,
rhs: $type,
) -> Result<Option<Self>, opt_ops::Error> {
self.opt_checked_add(crate::Signed::Positive(rhs))
}
}
impl opt_ops::OptionSaturatingAdd<$type> for crate::Signed<$type> {
type Output = Self;
fn opt_saturating_add(self, rhs: $type) -> Option<Self> {
self.opt_saturating_add(crate::Signed::Positive(rhs))
}
}
impl opt_ops::OptionCheckedSub<$type> for crate::Signed<$type> {
type Output = Self;
fn opt_checked_sub(
self,
rhs: $type,
) -> Result<Option<Self>, opt_ops::Error> {
self.opt_checked_sub(crate::Signed::Positive(rhs))
}
}
impl opt_ops::OptionSaturatingSub<$type> for crate::Signed<$type> {
type Output = Self;
fn opt_saturating_sub(self, rhs: $type) -> Option<Self> {
self.opt_saturating_sub(crate::Signed::Positive(rhs))
}
}
impl opt_ops::OptionCheckedAdd<crate::Signed<$type>> for $type {
type Output = crate::Signed<$type>;
fn opt_checked_add(
self,
rhs: crate::Signed<$type>,
) -> Result<Option<Self::Output>, opt_ops::Error> {
crate::Signed::Positive(self).opt_checked_add(rhs)
}
}
impl opt_ops::OptionSaturatingAdd<crate::Signed<$type>> for $type {
type Output = crate::Signed<$type>;
fn opt_saturating_add(
self,
rhs: crate::Signed<$type>
) -> Option<Self::Output> {
crate::Signed::Positive(self).opt_saturating_add(rhs)
}
}
impl opt_ops::OptionCheckedSub<crate::Signed<$type>> for $type {
type Output = crate::Signed<$type>;
fn opt_checked_sub(
self,
rhs: crate::Signed<$type>,
) -> Result<Option<Self::Output>, opt_ops::Error> {
crate::Signed::Positive(self).opt_checked_sub(rhs)
}
}
impl opt_ops::OptionSaturatingSub<crate::Signed<$type>> for $type {
type Output = crate::Signed<$type>;
fn opt_saturating_sub(
self,
rhs: crate::Signed<$type>
) -> Option<Self::Output> {
crate::Signed::Positive(self).opt_saturating_sub(rhs)
}
}
}; };
); );
macro_rules! impl_signed_div_mul( macro_rules! impl_signed_div_mul(
(u64) => { (u64) => {
impl_signed_div_mul!(u64, u64, i64, |val: u64| val); impl_signed_div_mul!(u64, u64, i64, |val: u64| val);
impl_signed_extra_div_mul!(u64, i64);
impl_signed_div_mul_trait!(u64, u64, i64, |val: u64| val); impl_signed_div_mul_trait!(u64, u64, i64, |val: u64| val);
}; };
(usize) => { (usize) => {
impl_signed_div_mul!(usize, usize, isize, |val: usize| val); impl_signed_div_mul!(usize, usize, isize, |val: usize| val);
impl_signed_extra_div_mul!(usize, isize);
// `MulDiv` not available for usize // `MulDiv` not available for usize
}; };
(u32) => { (u32) => {
impl_signed_div_mul!(u32, u32, i32, |val: u32| val); impl_signed_div_mul!(u32, u32, i32, |val: u32| val);
impl_signed_extra_div_mul!(u32, i32);
impl_signed_div_mul_trait!(u32, u32, i32, |val: u32| val); impl_signed_div_mul_trait!(u32, u32, i32, |val: u32| val);
}; };
($new_type:ty, u64) => { ($new_type:ty, u64) => {
impl_signed_div_mul!($new_type, u64, i64, |val: $new_type| *val); impl_signed_div_mul!($new_type, u64, i64, |val: $new_type| *val);
impl_signed_extra_div_mul!($new_type, u64, i64);
impl_signed_div_mul_trait!($new_type, u64, i64, |val: $new_type| *val); impl_signed_div_mul_trait!($new_type, u64, i64, |val: $new_type| *val);
}; };
($new_type:ty, u32) => { ($new_type:ty, u32) => {
impl_signed_div_mul!($new_type, u32, i32, |val: $new_type| *val); impl_signed_div_mul!($new_type, u32, i32, |val: $new_type| *val);
impl_signed_extra_div_mul!($new_type, u32, i32);
impl_signed_div_mul_trait!($new_type, u32, i32, |val: $new_type| *val); impl_signed_div_mul_trait!($new_type, u32, i32, |val: $new_type| *val);
}; };
@ -972,6 +1159,124 @@ macro_rules! impl_signed_div_mul(
}; };
); );
macro_rules! impl_signed_extra_div_mul(
($type:ty, $signed:ty) => {
impl std::ops::Div for crate::Signed<$type> {
type Output = Self;
fn div(self, rhs: Self) -> Self {
match rhs {
crate::Signed::Positive(rhs) => self.div(rhs),
crate::Signed::Negative(rhs) => std::ops::Neg::neg(self.div(rhs)),
}
}
}
impl std::ops::Rem for crate::Signed<$type> {
type Output = Self;
fn rem(self, rhs: Self) -> Self {
self.rem(rhs.abs())
}
}
impl opt_ops::OptionCheckedDiv for crate::Signed<$type> {
type Output = Self;
fn opt_checked_div(self, rhs: Self) -> Result<Option<Self::Output>, opt_ops::Error> {
match rhs {
crate::Signed::Positive(rhs) => self.opt_checked_div(rhs),
crate::Signed::Negative(rhs) => {
self.opt_checked_div(rhs)
.map(|res| res.map(std::ops::Neg::neg))
}
}
}
}
impl opt_ops::OptionCheckedRem for crate::Signed<$type> {
type Output = Self;
fn opt_checked_rem(self, rhs: Self) -> Result<Option<Self::Output>, opt_ops::Error> {
self.opt_checked_rem(rhs.abs())
}
}
};
($new_type:ty, $inner_type:ty, $signed_innner_type:ty) => {
impl std::ops::Div for crate::Signed<$new_type> {
type Output = crate::Signed<$inner_type>;
fn div(self, rhs: Self) -> Self::Output {
self.into_inner_signed().div(rhs.into_inner_signed())
}
}
impl std::ops::Rem for crate::Signed<$new_type> {
type Output = crate::Signed<$new_type>;
fn rem(self, rhs: Self) -> Self::Output {
self.rem(rhs.abs().0)
}
}
impl std::ops::Mul<crate::Signed<$new_type>> for $inner_type {
type Output = crate::Signed<$new_type>;
fn mul(self, rhs: crate::Signed<$new_type>) -> Self::Output {
rhs.mul(self)
}
}
impl std::ops::Mul<crate::Signed<$new_type>> for $signed_innner_type {
type Output = crate::Signed<$new_type>;
fn mul(self, rhs: crate::Signed<$new_type>) -> Self::Output {
rhs.mul(self)
}
}
impl opt_ops::OptionCheckedDiv for crate::Signed<$new_type> {
type Output = crate::Signed<$inner_type>;
fn opt_checked_div(self, rhs: Self) -> Result<Option<Self::Output>, opt_ops::Error> {
self.into_inner_signed().opt_checked_div(rhs.into_inner_signed())
}
}
impl opt_ops::OptionCheckedRem for crate::Signed<$new_type> {
type Output = crate::Signed<$inner_type>;
fn opt_checked_rem(self, rhs: Self) -> Result<Option<Self::Output>, opt_ops::Error> {
self.into_inner_signed().opt_checked_rem(rhs.abs().0)
}
}
impl opt_ops::OptionCheckedMul<crate::Signed<$new_type>> for $signed_innner_type {
type Output = crate::Signed<$new_type>;
fn opt_checked_mul(self, rhs: crate::Signed<$new_type>) -> Result<Option<Self::Output>, opt_ops::Error> {
rhs.opt_checked_mul(self)
}
}
impl opt_ops::OptionSaturatingMul<crate::Signed<$new_type>> for $signed_innner_type {
type Output = crate::Signed<$new_type>;
fn opt_saturating_mul(self, rhs: crate::Signed<$new_type>) -> Option<Self::Output> {
rhs.opt_saturating_mul(self)
}
}
impl opt_ops::OptionCheckedMul<crate::Signed<$new_type>> for $inner_type {
type Output = crate::Signed<$new_type>;
fn opt_checked_mul(self, rhs: crate::Signed<$new_type>) -> Result<Option<Self::Output>, opt_ops::Error> {
rhs.opt_checked_mul(self)
}
}
impl opt_ops::OptionSaturatingMul<crate::Signed<$new_type>> for $inner_type {
type Output = crate::Signed<$new_type>;
fn opt_saturating_mul(self, rhs: crate::Signed<$new_type>) -> Option<Self::Output> {
rhs.opt_saturating_mul(self)
}
}
};
);
macro_rules! impl_signed_div_mul_trait( macro_rules! impl_signed_div_mul_trait(
($type:ty, $inner_type:ty, $signed_rhs:ty, $into_inner:expr) => { ($type:ty, $inner_type:ty, $signed_rhs:ty, $into_inner:expr) => {
impl crate::Signed<$type> { impl crate::Signed<$type> {

View file

@ -232,10 +232,6 @@ impl_unsigned_int_into_signed!(u64);
impl_signed_ops!(u64); impl_signed_ops!(u64);
impl_signed_div_mul!(u64); impl_signed_div_mul!(u64);
impl_unsigned_int_into_signed!(usize);
impl_signed_ops!(usize);
impl_signed_div_mul!(usize);
impl_unsigned_int_into_signed!(u32); impl_unsigned_int_into_signed!(u32);
impl_signed_ops!(u32); impl_signed_ops!(u32);
impl_signed_div_mul!(u32); impl_signed_div_mul!(u32);

View file

@ -135,11 +135,11 @@ fn tutorial_main() -> Result<(), Error> {
} else { } else {
Percent::ZERO Percent::ZERO
} / Percent::MAX; } / Percent::MAX;
if start.is_zero() && stop.is_zero() { if start == 0 && stop == 0 {
continue; continue;
} }
let start_ = *((start * GRAPH_LENGTH as u32) / (stop - start)); let start_ = (start * GRAPH_LENGTH as u32) / (stop - start);
let stop_ = *((stop * GRAPH_LENGTH as u32) / (stop - start)); let stop_ = (stop * GRAPH_LENGTH as u32) / (stop - start);
for j in start_..stop_ { for j in start_..stop_ {
graph[j as usize] = b'-'; graph[j as usize] = b'-';
} }