gst/Signed: impl div & mul

This commit is contained in:
François Laignel 2022-09-19 17:05:48 +02:00 committed by François Laignel
parent 1411c9e35e
commit 2b4fcb131e
3 changed files with 330 additions and 6 deletions

View file

@ -225,6 +225,7 @@ impl From<ClockTime> for Duration {
} }
impl_common_ops_for_newtype_uint!(ClockTime, u64); impl_common_ops_for_newtype_uint!(ClockTime, u64);
impl_signed_div_mul!(ClockTime, u64);
// rustdoc-stripper-ignore-next // rustdoc-stripper-ignore-next
/// Tell [`pad_clocktime`] what kind of time we're formatting /// Tell [`pad_clocktime`] what kind of time we're formatting
@ -492,7 +493,30 @@ mod tests {
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!(N_CT_2 - N_CT_3, P_CT_1);
assert_eq!(P_CT_1 * 2i64, P_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, P_CT_2);
assert_eq!(P_CT_1 * 2u64, P_CT_2);
assert_eq!(N_CT_1 * 2u64, N_CT_2);
assert_eq!(P_CT_2 / 2i64, P_CT_1);
assert_eq!(P_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!(P_CT_2 / 2u64, P_CT_1);
assert_eq!(N_CT_2 / 2u64, N_CT_1);
assert_eq!(P_CT_3 % 2i64, P_CT_1);
assert_eq!(P_CT_3 % -2i64, P_CT_1);
assert_eq!(N_CT_3 % 2i64, N_CT_1);
assert_eq!(N_CT_3 % -2i64, N_CT_1);
assert_eq!(P_CT_3 % 2u64, P_CT_1);
assert_eq!(N_CT_3 % 2u64, N_CT_1);
} }
#[test] #[test]
@ -537,6 +561,24 @@ mod tests {
Some(CT_1).opt_checked_sub(CT_2), Some(CT_1).opt_checked_sub(CT_2),
Err(opt_ops::Error::Overflow) Err(opt_ops::Error::Overflow)
); );
assert_eq!(CT_1.checked_mul(2), Some(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!(N_CT_1.checked_mul(2), Some(N_CT_2));
assert_eq!(N_CT_1.checked_mul(-2), 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!(CT_3.checked_div(3), Some(CT_1));
assert_eq!(P_CT_3.checked_div(3), Some(P_CT_1));
assert_eq!(P_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!(P_CT_3.checked_div_unsigned(3u64), Some(P_CT_1));
assert_eq!(N_CT_3.checked_div_unsigned(3u64), Some(N_CT_1));
} }
#[test] #[test]
@ -584,6 +626,7 @@ mod tests {
#[test] #[test]
fn saturating_ops() { fn saturating_ops() {
let p_ct_max: Signed<ClockTime> = ClockTime::MAX.into_positive(); let p_ct_max: Signed<ClockTime> = ClockTime::MAX.into_positive();
let n_ct_max: Signed<ClockTime> = ClockTime::MAX.into_negative();
assert_eq!(CT_1.saturating_add(CT_2), CT_3); assert_eq!(CT_1.saturating_add(CT_2), CT_3);
assert_eq!(P_CT_1.saturating_add(P_CT_2), P_CT_3); assert_eq!(P_CT_1.saturating_add(P_CT_2), P_CT_3);
@ -625,6 +668,20 @@ mod tests {
assert_eq!(CT_1.saturating_mul(2), CT_2); assert_eq!(CT_1.saturating_mul(2), CT_2);
assert_eq!(ClockTime::MAX.saturating_mul(2), ClockTime::MAX); assert_eq!(ClockTime::MAX.saturating_mul(2), ClockTime::MAX);
assert_eq!(P_CT_1.saturating_mul(2), P_CT_2);
assert_eq!(P_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!(P_CT_1.saturating_mul_unsigned(2u64), P_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!(n_ct_max.saturating_mul(2), n_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);
} }
#[test] #[test]

View file

@ -235,13 +235,16 @@ pub trait UnsignedIntoSigned: Copy + Sized {
} }
impl_unsigned_int_into_signed!(u64); impl_unsigned_int_into_signed!(u64);
impl_signed_ops!(u64, 0); impl_signed_ops!(u64);
impl_signed_div_mul!(u64);
impl_unsigned_int_into_signed!(usize); impl_unsigned_int_into_signed!(usize);
impl_signed_ops!(usize, 0); 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, 0); impl_signed_ops!(u32);
impl_signed_div_mul!(u32);
impl From<i64> for Signed<u64> { impl From<i64> for Signed<u64> {
fn from(val: i64) -> Signed<u64> { fn from(val: i64) -> Signed<u64> {
@ -796,6 +799,7 @@ impl UnsignedIntoSigned for GenericFormattedValue {
} }
impl_common_ops_for_newtype_uint!(Default, u64); impl_common_ops_for_newtype_uint!(Default, u64);
impl_signed_div_mul!(Default, u64);
impl_format_value_traits!(Default, Default, Default, u64); impl_format_value_traits!(Default, Default, Default, u64);
option_glib_newtype_from_to!(Default, u64::MAX); option_glib_newtype_from_to!(Default, u64::MAX);
glib_newtype_display!( glib_newtype_display!(
@ -806,6 +810,7 @@ glib_newtype_display!(
); );
impl_common_ops_for_newtype_uint!(Bytes, u64); impl_common_ops_for_newtype_uint!(Bytes, u64);
impl_signed_div_mul!(Bytes, u64);
impl_format_value_traits!(Bytes, Bytes, Bytes, u64); impl_format_value_traits!(Bytes, Bytes, Bytes, u64);
option_glib_newtype_from_to!(Bytes, u64::MAX); option_glib_newtype_from_to!(Bytes, u64::MAX);
glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes"); glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes");
@ -813,6 +818,7 @@ glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes");
impl_format_value_traits!(ClockTime, Time, Time, u64); impl_format_value_traits!(ClockTime, Time, Time, u64);
impl_common_ops_for_newtype_uint!(Buffers, u64); impl_common_ops_for_newtype_uint!(Buffers, u64);
impl_signed_div_mul!(Buffers, u64);
impl_format_value_traits!(Buffers, Buffers, Buffers, u64); impl_format_value_traits!(Buffers, Buffers, Buffers, u64);
option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE); option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE);
glib_newtype_display!( glib_newtype_display!(
@ -919,6 +925,7 @@ impl From<Undefined> for Signed<u64> {
glib_newtype_display!(Undefined, DisplayableUndefined, "(Undefined)"); glib_newtype_display!(Undefined, DisplayableUndefined, "(Undefined)");
impl_common_ops_for_newtype_uint!(Percent, u32); impl_common_ops_for_newtype_uint!(Percent, u32);
impl_signed_div_mul!(Percent, u32);
glib_newtype_display!(Percent, DisplayablePercent, DisplayableOptionPercent, "%"); glib_newtype_display!(Percent, DisplayablePercent, DisplayableOptionPercent, "%");
impl FormattedValue for Option<Percent> { impl FormattedValue for Option<Percent> {

View file

@ -158,6 +158,12 @@ macro_rules! impl_non_trait_op_inner_type(
} }
} }
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub const fn saturating_div(self, rhs: $inner_type) -> Self {
Self(self.0.saturating_div(rhs))
}
#[must_use = "this returns the result of the operation, without modifying the original"] #[must_use = "this returns the result of the operation, without modifying the original"]
#[inline] #[inline]
pub const fn checked_mul(self, rhs: $inner_type) -> Option<Self> { pub const fn checked_mul(self, rhs: $inner_type) -> Option<Self> {
@ -266,7 +272,7 @@ macro_rules! impl_common_ops_for_newtype_uint(
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);
impl_signed_ops!($name, $name::ZERO); impl_signed_ops!($name, $inner_type, $name::ZERO);
impl<ND: Borrow<$inner_type>> MulDiv<ND> for $name { impl<ND: Borrow<$inner_type>> MulDiv<ND> for $name {
type Output = $name; type Output = $name;
@ -423,7 +429,19 @@ macro_rules! impl_common_ops_for_newtype_uint(
); );
macro_rules! impl_signed_ops( macro_rules! impl_signed_ops(
($type:ty, $zero:expr) => { (u64) => {
impl_signed_ops!(u64, u64, 0);
};
(usize) => {
impl_signed_ops!(usize, usize, 0);
};
(u32) => {
impl_signed_ops!(u32, u32, 0);
};
($type:ty, $inner_type:ty, $zero:expr) => {
impl crate::Signed<$type> { impl crate::Signed<$type> {
// rustdoc-stripper-ignore-next // rustdoc-stripper-ignore-next
/// Returns the signum for this `Signed`. /// Returns the signum for this `Signed`.
@ -615,6 +633,248 @@ macro_rules! impl_signed_ops(
}; };
); );
macro_rules! impl_signed_div_mul(
(u64) => {
impl_signed_div_mul!(u64, u64, i64);
};
(usize) => {
impl_signed_div_mul!(usize, usize, isize);
};
(u32) => {
impl_signed_div_mul!(u32, u32, i32);
};
($type:ty, u64) => {
impl_signed_div_mul!($type, u64, i64);
};
($type:ty, usize) => {
impl_signed_div_mul!($type, usize, isize);
};
($type:ty, u32) => {
impl_signed_div_mul!($type, u32, i32);
};
($type:ty, $inner_type:ty, $signed_rhs:ty) => {
impl crate::Signed<$type> {
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn checked_div(self, rhs:$signed_rhs) -> Option<Self> {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => {
if rhs.is_positive() {
lhs.checked_div(rhs as $inner_type).map(<$type>::into_positive)
} else {
lhs.checked_div(-rhs as $inner_type).map(<$type>::into_negative)
}
}
Negative(lhs) => {
if rhs.is_positive() {
lhs.checked_div(rhs as $inner_type).map(<$type>::into_negative)
} else {
lhs.checked_div(-rhs as $inner_type).map(<$type>::into_positive)
}
}
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn checked_div_unsigned(self, rhs:$inner_type) -> Option<Self> {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => lhs.checked_div(rhs).map(<$type>::into_positive),
Negative(lhs) => lhs.checked_div(rhs).map(<$type>::into_negative),
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn checked_rem(self, rhs:$signed_rhs) -> Option<Self> {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => {
if rhs.is_positive() {
lhs.checked_rem(rhs as $inner_type).map(<$type>::into_positive)
} else {
lhs.checked_rem(-rhs as $inner_type).map(<$type>::into_positive)
}
}
Negative(lhs) => {
if rhs.is_positive() {
lhs.checked_rem(rhs as $inner_type).map(<$type>::into_negative)
} else {
lhs.checked_rem(-rhs as $inner_type).map(<$type>::into_negative)
}
}
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn checked_rem_unsigned(self, rhs:$inner_type) -> Option<Self> {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => lhs.checked_rem(rhs).map(<$type>::into_positive),
Negative(lhs) => lhs.checked_rem(rhs).map(<$type>::into_negative),
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn checked_mul(self, rhs:$signed_rhs) -> Option<Self> {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => {
if rhs.is_positive() {
lhs.checked_mul(rhs as $inner_type).map(<$type>::into_positive)
} else {
lhs.checked_mul(-rhs as $inner_type).map(<$type>::into_negative)
}
}
Negative(lhs) => {
if rhs.is_positive() {
lhs.checked_mul(rhs as $inner_type).map(<$type>::into_negative)
} else {
lhs.checked_mul(-rhs as $inner_type).map(<$type>::into_positive)
}
}
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn checked_mul_unsigned(self, rhs:$inner_type) -> Option<Self> {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => lhs.checked_mul(rhs).map(<$type>::into_positive),
Negative(lhs) => lhs.checked_mul(rhs).map(<$type>::into_negative),
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_mul(self, rhs:$signed_rhs) -> Self {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => {
if rhs.is_positive() {
lhs.saturating_mul(rhs as $inner_type).into_positive()
} else {
lhs.saturating_mul(-rhs as $inner_type).into_negative()
}
}
Negative(lhs) => {
if rhs.is_positive() {
lhs.saturating_mul(rhs as $inner_type).into_negative()
} else {
lhs.saturating_mul(-rhs as $inner_type).into_positive()
}
}
}
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_mul_unsigned(self, rhs:$inner_type) -> Self {
use crate::UnsignedIntoSigned;
use crate::Signed::*;
match self {
Positive(lhs) => lhs.saturating_mul(rhs).into_positive(),
Negative(lhs) => lhs.saturating_mul(rhs).into_negative(),
}
}
}
impl std::ops::Div<$signed_rhs> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn div(self, rhs: $signed_rhs) -> crate::Signed<$type> {
self.checked_div(rhs).expect("division overflowed")
}
}
impl std::ops::DivAssign<$signed_rhs> for crate::Signed<$type> {
fn div_assign(&mut self, rhs: $signed_rhs) {
*self = std::ops::Div::div(*self, rhs);
}
}
impl std::ops::Div<$inner_type> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn div(self, rhs: $inner_type) -> crate::Signed<$type> {
self.checked_div_unsigned(rhs).expect("division overflowed")
}
}
impl std::ops::DivAssign<$inner_type> for crate::Signed<$type> {
fn div_assign(&mut self, rhs: $inner_type) {
*self = std::ops::Div::div(*self, rhs);
}
}
impl std::ops::Rem<$signed_rhs> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn rem(self, rhs: $signed_rhs) -> crate::Signed<$type> {
self.checked_rem(rhs).expect("division overflowed")
}
}
impl std::ops::RemAssign<$signed_rhs> for crate::Signed<$type> {
fn rem_assign(&mut self, rhs: $signed_rhs) {
*self = std::ops::Rem::rem(*self, rhs);
}
}
impl std::ops::Rem<$inner_type> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn rem(self, rhs: $inner_type) -> crate::Signed<$type> {
self.checked_rem_unsigned(rhs).expect("division overflowed")
}
}
impl std::ops::RemAssign<$inner_type> for crate::Signed<$type> {
fn rem_assign(&mut self, rhs: $inner_type) {
*self = std::ops::Rem::rem(*self, rhs);
}
}
impl std::ops::Mul<$signed_rhs> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn mul(self, rhs: $signed_rhs) -> crate::Signed<$type> {
self.checked_mul(rhs).expect("multiplication overflowed")
}
}
impl std::ops::MulAssign<$signed_rhs> for crate::Signed<$type> {
fn mul_assign(&mut self, rhs: $signed_rhs) {
*self = std::ops::Mul::mul(*self, rhs);
}
}
impl std::ops::Mul<$inner_type> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn mul(self, rhs: $inner_type) -> crate::Signed<$type> {
self.checked_mul_unsigned(rhs).expect("multiplication overflowed")
}
}
impl std::ops::MulAssign<$inner_type> for crate::Signed<$type> {
fn mul_assign(&mut self, rhs: $inner_type) {
*self = std::ops::Mul::mul(*self, rhs);
}
}
};
);
macro_rules! impl_format_value_traits( macro_rules! impl_format_value_traits(
($name:ident, $format:ident, $format_value:ident, $inner_type:ty) => { ($name:ident, $format:ident, $format_value:ident, $inner_type:ty) => {
impl FormattedValue for Option<$name> { impl FormattedValue for Option<$name> {