gst/Signed: impl MulDiv

This commit is contained in:
François Laignel 2022-09-19 18:38:19 +02:00 committed by François Laignel
parent 2b4fcb131e
commit 183a399d1d
3 changed files with 199 additions and 12 deletions

View file

@ -711,6 +711,48 @@ mod tests {
); );
} }
#[test]
fn mul_div_ops() {
assert_eq!(CT_1.mul_div_floor(7, 3), Some(CT_2));
assert_eq!(P_CT_1.mul_div_floor(7u64, 3), Some(P_CT_2));
assert_eq!(P_CT_1.mul_div_floor(-7i64, 3), Some(N_CT_2));
assert_eq!(P_CT_1.mul_div_floor(7i64, -3), Some(N_CT_2));
assert_eq!(P_CT_1.mul_div_floor(-7i64, -3), Some(P_CT_2));
assert_eq!(N_CT_1.mul_div_floor(7u64, 3), Some(N_CT_2));
assert_eq!(N_CT_1.mul_div_floor(-7i64, 3), Some(P_CT_2));
assert_eq!(N_CT_1.mul_div_floor(7i64, -3), Some(P_CT_2));
assert_eq!(N_CT_1.mul_div_floor(-7i64, -3), Some(N_CT_2));
assert_eq!(CT_1.mul_div_round(10, 3), Some(CT_3));
assert_eq!(CT_1.mul_div_round(8, 3), Some(CT_3));
assert_eq!(P_CT_1.mul_div_round(10u64, 3), Some(P_CT_3));
assert_eq!(P_CT_1.mul_div_round(8u64, 3), Some(P_CT_3));
assert_eq!(P_CT_1.mul_div_round(-10i64, 3), Some(N_CT_3));
assert_eq!(P_CT_1.mul_div_round(-8i64, 3), Some(N_CT_3));
assert_eq!(P_CT_1.mul_div_round(10i64, -3), Some(N_CT_3));
assert_eq!(P_CT_1.mul_div_round(-10i64, -3), Some(P_CT_3));
assert_eq!(N_CT_1.mul_div_round(10u64, 3), Some(N_CT_3));
assert_eq!(N_CT_1.mul_div_round(-10i64, 3), Some(P_CT_3));
assert_eq!(N_CT_1.mul_div_round(10i64, -3), Some(P_CT_3));
assert_eq!(N_CT_1.mul_div_round(-10i64, -3), Some(N_CT_3));
assert_eq!(CT_1.mul_div_ceil(7, 3), Some(CT_3));
assert_eq!(P_CT_1.mul_div_ceil(7u64, 3), Some(P_CT_3));
assert_eq!(P_CT_1.mul_div_ceil(-7i64, 3), Some(N_CT_3));
assert_eq!(P_CT_1.mul_div_ceil(7i64, -3), Some(N_CT_3));
assert_eq!(P_CT_1.mul_div_ceil(-7i64, -3), Some(P_CT_3));
assert_eq!(N_CT_1.mul_div_ceil(7u64, 3), Some(N_CT_3));
assert_eq!(N_CT_1.mul_div_ceil(-7i64, 3), Some(P_CT_3));
assert_eq!(N_CT_1.mul_div_ceil(7i64, -3), Some(P_CT_3));
assert_eq!(N_CT_1.mul_div_ceil(-7i64, -3), Some(N_CT_3));
}
#[test] #[test]
#[allow(clippy::nonminimal_bool)] #[allow(clippy::nonminimal_bool)]
fn comp() { fn comp() {

View file

@ -1003,6 +1003,19 @@ impl TryFromGlib<i64> for Percent {
} }
} }
impl TryFrom<u32> for Percent {
type Error = FormattedValueError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
skip_assert_initialized!();
if value > ffi::GST_FORMAT_PERCENT_MAX as u32 {
Err(FormattedValueError(Format::Percent))
} else {
Ok(Percent(value))
}
}
}
impl TryFrom<GenericFormattedValue> for Option<Percent> { impl TryFrom<GenericFormattedValue> for Option<Percent> {
type Error = FormattedValueError; type Error = FormattedValueError;

View file

@ -635,30 +635,31 @@ macro_rules! impl_signed_ops(
macro_rules! impl_signed_div_mul( macro_rules! impl_signed_div_mul(
(u64) => { (u64) => {
impl_signed_div_mul!(u64, u64, i64); impl_signed_div_mul!(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); impl_signed_div_mul!(usize, usize, isize, |val: usize| val);
// `MulDiv` not available for usize
}; };
(u32) => { (u32) => {
impl_signed_div_mul!(u32, u32, i32); impl_signed_div_mul!(u32, u32, i32, |val: u32| val);
impl_signed_div_mul_trait!(u32, u32, i32, |val: u32| val);
}; };
($type:ty, u64) => { ($new_type:ty, u64) => {
impl_signed_div_mul!($type, u64, i64); impl_signed_div_mul!($new_type, u64, i64, |val: $new_type| *val);
impl_signed_div_mul_trait!($new_type, u64, i64, |val: $new_type| *val);
}; };
($type:ty, usize) => { ($new_type:ty, u32) => {
impl_signed_div_mul!($type, usize, isize); impl_signed_div_mul!($new_type, u32, i32, |val: $new_type| *val);
impl_signed_div_mul_trait!($new_type, u32, i32, |val: $new_type| *val);
}; };
($type:ty, u32) => { ($type:ty, $inner_type:ty, $signed_rhs:ty, $into_inner:expr) => {
impl_signed_div_mul!($type, u32, i32);
};
($type:ty, $inner_type:ty, $signed_rhs:ty) => {
impl crate::Signed<$type> { impl crate::Signed<$type> {
#[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"]
pub fn checked_div(self, rhs:$signed_rhs) -> Option<Self> { pub fn checked_div(self, rhs:$signed_rhs) -> Option<Self> {
@ -875,6 +876,137 @@ macro_rules! impl_signed_div_mul(
}; };
); );
macro_rules! impl_signed_div_mul_trait(
($type:ty, $inner_type:ty, $signed_rhs:ty, $into_inner:expr) => {
impl crate::Signed<$type> {
fn signed_from_inner(val: $inner_type, sign: $signed_rhs) -> Option<crate::Signed<$type>> {
skip_assert_initialized!();
if sign.is_positive() {
Self::positive_from_inner(val)
} else {
Self::negative_from_inner(val)
}
}
fn positive_from_inner(val: $inner_type) -> Option<crate::Signed<$type>> {
skip_assert_initialized!();
use crate::UnsignedIntoSigned;
<$type>::try_from(val).ok().map(<$type>::into_positive)
}
fn negative_from_inner(val: $inner_type) -> Option<crate::Signed<$type>> {
skip_assert_initialized!();
use crate::UnsignedIntoSigned;
<$type>::try_from(val).ok().map(<$type>::into_negative)
}
}
impl MulDiv<$signed_rhs> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn mul_div_floor(self, num: $signed_rhs, denom: $signed_rhs) -> Option<Self::Output> {
use crate::Signed::*;
match self {
Positive(lhs) => {
$into_inner(lhs)
.mul_div_floor(num.abs() as $inner_type, denom.abs() as $inner_type)
.and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum()))
}
Negative(lhs) => {
$into_inner(lhs)
.mul_div_floor(num.abs() as $inner_type, denom.abs() as $inner_type)
.and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum()))
}
}
}
fn mul_div_round(self, num: $signed_rhs, denom: $signed_rhs) -> Option<Self::Output> {
use crate::Signed::*;
match self {
Positive(lhs) => {
$into_inner(lhs)
.mul_div_round(num.abs() as $inner_type, denom.abs() as $inner_type)
.and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum()))
}
Negative(lhs) => {
$into_inner(lhs)
.mul_div_round(num.abs() as $inner_type, denom.abs() as $inner_type)
.and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum()))
}
}
}
fn mul_div_ceil(self, num: $signed_rhs, denom: $signed_rhs) -> Option<Self::Output> {
use crate::Signed::*;
match self {
Positive(lhs) => {
$into_inner(lhs)
.mul_div_ceil(num.abs() as $inner_type, denom.abs() as $inner_type)
.and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum()))
}
Negative(lhs) => {
$into_inner(lhs)
.mul_div_ceil(num.abs() as $inner_type, denom.abs() as $inner_type)
.and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum()))
}
}
}
}
impl MulDiv<$inner_type> for crate::Signed<$type> {
type Output = crate::Signed<$type>;
fn mul_div_floor(self, num: $inner_type, denom: $inner_type) -> Option<Self::Output> {
use crate::Signed::*;
match self {
Positive(lhs) => {
$into_inner(lhs)
.mul_div_floor(num, denom)
.and_then(Self::positive_from_inner)
}
Negative(lhs) => {
$into_inner(lhs)
.mul_div_floor(num, denom)
.and_then(Self::negative_from_inner)
}
}
}
fn mul_div_round(self, num: $inner_type, denom: $inner_type) -> Option<Self::Output> {
use crate::Signed::*;
match self {
Positive(lhs) => {
$into_inner(lhs)
.mul_div_round(num, denom)
.and_then(Self::positive_from_inner)
}
Negative(lhs) => {
$into_inner(lhs)
.mul_div_round(num, denom)
.and_then(Self::negative_from_inner)
}
}
}
fn mul_div_ceil(self, num: $inner_type, denom: $inner_type) -> Option<Self::Output> {
use crate::Signed::*;
match self {
Positive(lhs) => {
$into_inner(lhs)
.mul_div_ceil(num, denom)
.and_then(Self::positive_from_inner)
}
Negative(lhs) => {
$into_inner(lhs)
.mul_div_ceil(num, denom)
.and_then(Self::negative_from_inner)
}
}
}
}
};
);
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> {