use crate::ClockTime;
use crate::Format;
use muldiv::MulDiv;
use std::convert::TryFrom;
use std::ops;
use thiserror::Error;
use std::cmp;
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
#[cfg_attr(feature = "ser_de", derive(serde::Serialize, serde::Deserialize))]
pub enum GenericFormattedValue {
Undefined(Undefined),
Default(Default),
Bytes(Bytes),
Time(ClockTime),
Buffers(Buffers),
Percent(Percent),
Other(Format, i64),
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
pub struct Undefined(pub i64);
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Default)]
pub struct Default(pub Option<u64>);
impl_common_ops_for_opt_int!(Default);
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Default)]
pub struct Bytes(pub Option<u64>);
impl_common_ops_for_opt_int!(Bytes);
pub type Time = ClockTime;
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Default)]
pub struct Buffers(pub Option<u64>);
impl_common_ops_for_opt_int!(Buffers);
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Default)]
pub struct Percent(pub Option<u32>);
impl_common_ops_for_opt_int!(Percent);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Error)]
#[error("invalid generic value format")]
pub struct TryFromGenericFormattedValueError(());
pub trait FormattedValue: Copy + Clone + Sized + Into<GenericFormattedValue> + 'static {
#[doc(alias = "get_default_format")]
fn default_format() -> Format;
#[doc(alias = "get_format")]
fn format(&self) -> Format;
unsafe fn from_raw(format: Format, value: i64) -> Self;
unsafe fn to_raw_value(&self) -> i64;
}
pub trait SpecificFormattedValue: FormattedValue + TryFrom<GenericFormattedValue> {}
impl FormattedValue for GenericFormattedValue {
fn default_format() -> Format {
Format::Undefined
}
fn format(&self) -> Format {
self.format()
}
unsafe fn from_raw(format: Format, value: i64) -> Self {
GenericFormattedValue::new(format, value)
}
unsafe fn to_raw_value(&self) -> i64 {
self.value()
}
}
impl GenericFormattedValue {
pub fn new(format: Format, value: i64) -> Self {
skip_assert_initialized!();
match format {
Format::Undefined => Self::Undefined(Undefined(value)),
Format::Default => Self::Default(if value == -1 {
Default(None)
} else {
Default(Some(value as u64))
}),
Format::Bytes => Self::Bytes(if value == -1 {
Bytes(None)
} else {
Bytes(Some(value as u64))
}),
Format::Time => Self::Time(if value == -1 {
ClockTime::none()
} else {
ClockTime::from_nseconds(value as u64)
}),
Format::Buffers => Self::Buffers(if value == -1 {
Buffers(None)
} else {
Buffers(Some(value as u64))
}),
Format::Percent => Self::Percent(unsafe { Percent::from_raw(format, value) }),
Format::__Unknown(_) => Self::Other(format, value),
}
}
#[doc(alias = "get_format")]
pub fn format(&self) -> Format {
match *self {
Self::Undefined(_) => Format::Undefined,
Self::Default(_) => Format::Default,
Self::Bytes(_) => Format::Bytes,
Self::Time(_) => Format::Time,
Self::Buffers(_) => Format::Buffers,
Self::Percent(_) => Format::Percent,
Self::Other(f, _) => f,
}
}
#[doc(alias = "get_value")]
pub fn value(&self) -> i64 {
match *self {
Self::Undefined(v) => v.0,
Self::Default(v) => v.map(|v| v as i64).unwrap_or(-1),
Self::Bytes(v) => v.map(|v| v as i64).unwrap_or(-1),
Self::Time(v) => v.map(|v| v as i64).unwrap_or(-1),
Self::Buffers(v) => v.map(|v| v as i64).unwrap_or(-1),
Self::Percent(v) => v.map(i64::from).unwrap_or(-1),
Self::Other(_, v) => v,
}
}
}
macro_rules! impl_op_same(
($name:ident, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident, $e:expr) => {
impl ops::$op<$name> for $name {
type Output = $name;
fn $op_name(self, other: $name) -> Self::Output {
match (self.0, other.0) {
(Some(a), Some(b)) => $name($e(a, b)),
_ => $name(None),
}
}
}
impl<'a> ops::$op<&'a $name> for $name {
type Output = $name;
fn $op_name(self, other: &'a $name) -> Self::Output {
self.$op_name(*other)
}
}
impl<'a> ops::$op<$name> for &'a $name {
type Output = $name;
fn $op_name(self, other: $name) -> Self::Output {
(*self).$op_name(other)
}
}
impl<'a, 'b> ops::$op<&'a $name> for &'b $name {
type Output = $name;
fn $op_name(self, other: &'a $name) -> Self::Output {
(*self).$op_name(*other)
}
}
impl ops::$op_assign<$name> for $name {
fn $op_assign_name(&mut self, other: $name) {
match (self.0, other.0) {
(Some(a), Some(b)) => self.0 = $e(a, b),
_ => self.0 = None,
}
}
}
impl<'a> ops::$op_assign<&'a $name> for $name {
fn $op_assign_name(&mut self, other: &'a $name) {
self.$op_assign_name(*other)
}
}
};
);
macro_rules! impl_op_u64(
($name:ident, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident, $e:expr) => {
impl ops::$op<u64> for $name {
type Output = $name;
fn $op_name(self, other: u64) -> Self::Output {
match self.0 {
Some(a) => $name($e(a, other)),
_ => $name(None),
}
}
}
impl<'a> ops::$op<&'a u64> for $name {
type Output = $name;
fn $op_name(self, other: &'a u64) -> Self::Output {
self.$op_name(*other)
}
}
impl<'a> ops::$op<u64> for &'a $name {
type Output = $name;
fn $op_name(self, other: u64) -> Self::Output {
(*self).$op_name(other)
}
}
impl<'a, 'b> ops::$op<&'a u64> for &'b $name {
type Output = $name;
fn $op_name(self, other: &'a u64) -> Self::Output {
self.$op_name(*other)
}
}
impl ops::$op<$name> for u64 {
type Output = $name;
fn $op_name(self, other: $name) -> $name {
other.$op_name(self)
}
}
impl<'a> ops::$op<&'a $name> for u64 {
type Output = $name;
fn $op_name(self, other: &'a $name) -> $name {
(*other).$op_name(self)
}
}
impl<'a> ops::$op<$name> for &'a u64 {
type Output = $name;
fn $op_name(self, other: $name) -> $name {
other.$op_name(*self)
}
}
impl<'a, 'b> ops::$op<&'a $name> for &'b u64 {
type Output = $name;
fn $op_name(self, other: &'a $name) -> $name {
(*other).$op_name(*self)
}
}
impl ops::$op_assign<u64> for $name {
fn $op_assign_name(&mut self, other: u64) {
match self.0 {
Some(a) => self.0 = $e(a, other),
_ => self.0 = None,
}
}
}
impl<'a> ops::$op_assign<&'a u64> for $name {
fn $op_assign_name(&mut self, other: &'a u64) {
self.$op_assign_name(*other)
}
}
};
);
macro_rules! impl_format_value_traits(
($name:ident, $format:ident, $format_value:ident) => {
impl FormattedValue for $name {
fn default_format() -> Format {
Format::$format
}
fn format(&self) -> Format {
Format::$format
}
unsafe fn from_raw(format: Format, value: i64) -> Self {
debug_assert_eq!(format, Format::$format);
if value == -1 {
$name(None)
} else {
$name(Some(value as u64))
}
}
unsafe fn to_raw_value(&self) -> i64 {
self.0.map(|v| v as i64).unwrap_or(-1)
}
}
impl From<$name> for GenericFormattedValue {
fn from(v: $name) -> Self {
skip_assert_initialized!();
GenericFormattedValue::$format_value(v)
}
}
impl TryFrom<GenericFormattedValue> for $name {
type Error = TryFromGenericFormattedValueError;
fn try_from(v: GenericFormattedValue) -> Result<$name, Self::Error> {
skip_assert_initialized!();
if let GenericFormattedValue::$format_value(v) = v {
Ok(v)
} else {
Err(TryFromGenericFormattedValueError(()))
}
}
}
impl SpecificFormattedValue for $name { }
impl From<u64> for $name {
fn from(v: u64) -> Self {
skip_assert_initialized!();
$name(Some(v))
}
}
impl From<Option<u64>> for $name {
fn from(v: Option<u64>) -> Self {
skip_assert_initialized!();
$name(v)
}
}
impl From<$name> for Option<u64> {
fn from(v: $name) -> Self {
skip_assert_initialized!();
v.0
}
}
impl ops::Deref for $name {
type Target = Option<u64>;
fn deref(&self) -> &Option<u64> {
&self.0
}
}
impl ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Option<u64> {
&mut self.0
}
}
impl AsRef<Option<u64>> for $name {
fn as_ref(&self) -> &Option<u64> {
&self.0
}
}
impl AsMut<Option<u64>> for $name {
fn as_mut(&mut self) -> &mut Option<u64> {
&mut self.0
}
}
impl_op_same!($name, Add, add, AddAssign, add_assign, |a: u64, b: u64| a.checked_add(b));
impl_op_same!($name, Sub, sub, SubAssign, sub_assign, |a: u64, b: u64| a.checked_sub(b));
impl_op_same!($name, Mul, mul, MulAssign, mul_assign, |a: u64, b: u64| a.checked_mul(b));
impl_op_same!($name, Div, div, DivAssign, div_assign, |a: u64, b: u64| a.checked_div(b));
impl_op_same!($name, Rem, rem, RemAssign, rem_assign, |a: u64, b: u64| a.checked_rem(b));
impl_op_u64!($name, Mul, mul, MulAssign, mul_assign, |a: u64, b: u64| a.checked_mul(b));
impl_op_u64!($name, Div, div, DivAssign, div_assign, |a: u64, b: u64| a.checked_div(b));
impl_op_u64!($name, Rem, rem, RemAssign, rem_assign, |a: u64, b: u64| a.checked_rem(b));
impl MulDiv<$name> for $name {
type Output = $name;
fn mul_div_floor(self, num: $name, denom: $name) -> Option<Self::Output> {
match (self.0, num.0, denom.0) {
(Some(s), Some(n), Some(d)) => s.mul_div_floor(n, d).map(|v| $name(Some(v))),
_ => Some($name(None)),
}
}
fn mul_div_round(self, num: $name, denom: $name) -> Option<Self::Output> {
match (self.0, num.0, denom.0) {
(Some(s), Some(n), Some(d)) => s.mul_div_round(n, d).map(|v| $name(Some(v))),
_ => Some($name(None)),
}
}
fn mul_div_ceil(self, num: $name, denom: $name) -> Option<Self::Output> {
match (self.0, num.0, denom.0) {
(Some(s), Some(n), Some(d)) => s.mul_div_ceil(n, d).map(|v| $name(Some(v))),
_ => Some($name(None)),
}
}
}
impl<'a> MulDiv<&'a $name> for $name {
type Output = $name;
fn mul_div_floor(self, num: &$name, denom: &$name) -> Option<Self::Output> {
self.mul_div_floor(*num, *denom)
}
fn mul_div_round(self, num: &$name, denom: &$name) -> Option<Self::Output> {
self.mul_div_round(*num, *denom)
}
fn mul_div_ceil(self, num: &$name, denom: &$name) -> Option<Self::Output> {
self.mul_div_ceil(*num, *denom)
}
}
impl<'a> MulDiv<$name> for &'a $name {
type Output = $name;
fn mul_div_floor(self, num: $name, denom: $name) -> Option<Self::Output> {
(*self).mul_div_floor(num, denom)
}
fn mul_div_round(self, num: $name, denom: $name) -> Option<Self::Output> {
(*self).mul_div_round(num, denom)
}
fn mul_div_ceil(self, num: $name, denom: $name) -> Option<Self::Output> {
(*self).mul_div_ceil(num, denom)
}
}
impl<'a, 'b> MulDiv<&'b $name> for &'a $name {
type Output = $name;
fn mul_div_floor(self, num: &$name, denom: &$name) -> Option<Self::Output> {
(*self).mul_div_floor(*num, *denom)
}
fn mul_div_round(self, num: &$name, denom: &$name) -> Option<Self::Output> {
(*self).mul_div_round(*num, *denom)
}
fn mul_div_ceil(self, num: &$name, denom: &$name) -> Option<Self::Output> {
(*self).mul_div_ceil(*num, *denom)
}
}
impl<'a> MulDiv<u64> for $name {
type Output = $name;
fn mul_div_floor(self, num: u64, denom: u64) -> Option<Self::Output> {
self.mul_div_floor($name(Some(num)), $name(Some(denom)))
}
fn mul_div_round(self, num: u64, denom: u64) -> Option<Self::Output> {
self.mul_div_round($name(Some(num)), $name(Some(denom)))
}
fn mul_div_ceil(self, num: u64, denom: u64) -> Option<Self::Output> {
self.mul_div_ceil($name(Some(num)), $name(Some(denom)))
}
}
impl<'a> MulDiv<&'a u64> for $name {
type Output = $name;
fn mul_div_floor(self, num: &u64, denom: &u64) -> Option<Self::Output> {
self.mul_div_floor(*num, *denom)
}
fn mul_div_round(self, num: &u64, denom: &u64) -> Option<Self::Output> {
self.mul_div_round(*num, *denom)
}
fn mul_div_ceil(self, num: &u64, denom: &u64) -> Option<Self::Output> {
self.mul_div_ceil(*num, *denom)
}
}
impl<'a> MulDiv<u64> for &'a $name {
type Output = $name;
fn mul_div_floor(self, num: u64, denom: u64) -> Option<Self::Output> {
(*self).mul_div_floor(num, denom)
}
fn mul_div_round(self, num: u64, denom: u64) -> Option<Self::Output> {
(*self).mul_div_round(num, denom)
}
fn mul_div_ceil(self, num: u64, denom: u64) -> Option<Self::Output> {
(*self).mul_div_ceil(num, denom)
}
}
impl<'a, 'b> MulDiv<&'a u64> for &'b $name {
type Output = $name;
fn mul_div_floor(self, num: &u64, denom: &u64) -> Option<Self::Output> {
(*self).mul_div_floor(*num, *denom)
}
fn mul_div_round(self, num: &u64, denom: &u64) -> Option<Self::Output> {
(*self).mul_div_round(*num, *denom)
}
fn mul_div_ceil(self, num: &u64, denom: &u64) -> Option<Self::Output> {
(*self).mul_div_ceil(*num, *denom)
}
}
};
);
impl_format_value_traits!(Default, Default, Default);
impl_format_value_traits!(Bytes, Bytes, Bytes);
impl_format_value_traits!(ClockTime, Time, Time);
impl_format_value_traits!(Buffers, Buffers, Buffers);
impl FormattedValue for Undefined {
fn default_format() -> Format {
Format::Undefined
}
fn format(&self) -> Format {
Format::Undefined
}
unsafe fn from_raw(format: Format, value: i64) -> Self {
debug_assert_eq!(format, Format::Undefined);
Undefined(value)
}
unsafe fn to_raw_value(&self) -> i64 {
self.0
}
}
impl From<Undefined> for GenericFormattedValue {
fn from(v: Undefined) -> Self {
skip_assert_initialized!();
GenericFormattedValue::Undefined(v)
}
}
impl TryFrom<GenericFormattedValue> for Undefined {
type Error = TryFromGenericFormattedValueError;
fn try_from(v: GenericFormattedValue) -> Result<Undefined, TryFromGenericFormattedValueError> {
skip_assert_initialized!();
if let GenericFormattedValue::Undefined(v) = v {
Ok(v)
} else {
Err(TryFromGenericFormattedValueError(()))
}
}
}
impl SpecificFormattedValue for Undefined {}
impl From<i64> for Undefined {
fn from(v: i64) -> Self {
skip_assert_initialized!();
Undefined(v)
}
}
impl From<Undefined> for i64 {
fn from(u: Undefined) -> Self {
skip_assert_initialized!();
u.0
}
}
impl ops::Deref for Undefined {
type Target = i64;
fn deref(&self) -> &i64 {
&self.0
}
}
impl ops::DerefMut for Undefined {
fn deref_mut(&mut self) -> &mut i64 {
&mut self.0
}
}
impl AsRef<i64> for Undefined {
fn as_ref(&self) -> &i64 {
&self.0
}
}
impl AsMut<i64> for Undefined {
fn as_mut(&mut self) -> &mut i64 {
&mut self.0
}
}
impl FormattedValue for Percent {
fn default_format() -> Format {
Format::Percent
}
fn format(&self) -> Format {
Format::Percent
}
unsafe fn from_raw(format: Format, value: i64) -> Self {
debug_assert_eq!(format, Format::Percent);
if value < 0 || value > ffi::GST_FORMAT_PERCENT_MAX {
Percent(None)
} else {
Percent(Some(value as u32))
}
}
unsafe fn to_raw_value(&self) -> i64 {
self.0.map(|v| v as i64).unwrap_or(-1)
}
}
impl From<Percent> for GenericFormattedValue {
fn from(v: Percent) -> Self {
skip_assert_initialized!();
GenericFormattedValue::Percent(v)
}
}
impl TryFrom<GenericFormattedValue> for Percent {
type Error = TryFromGenericFormattedValueError;
fn try_from(v: GenericFormattedValue) -> Result<Percent, TryFromGenericFormattedValueError> {
skip_assert_initialized!();
if let GenericFormattedValue::Percent(v) = v {
Ok(v)
} else {
Err(TryFromGenericFormattedValueError(()))
}
}
}
impl SpecificFormattedValue for Percent {}
impl ops::Deref for Percent {
type Target = Option<u32>;
fn deref(&self) -> &Option<u32> {
&self.0
}
}
impl ops::DerefMut for Percent {
fn deref_mut(&mut self) -> &mut Option<u32> {
&mut self.0
}
}
impl AsRef<Option<u32>> for Percent {
fn as_ref(&self) -> &Option<u32> {
&self.0
}
}
impl AsMut<Option<u32>> for Percent {
fn as_mut(&mut self) -> &mut Option<u32> {
&mut self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Error)]
#[error("value out of range")]
pub struct TryPercentFromFloatError(());
impl TryFrom<f64> for Percent {
type Error = TryPercentFromFloatError;
fn try_from(v: f64) -> Result<Self, Self::Error> {
skip_assert_initialized!();
if v < 0.0 || v > 1.0 {
Err(TryPercentFromFloatError(()))
} else {
Ok(Percent(Some(
(v * ffi::GST_FORMAT_PERCENT_SCALE as f64).round() as u32,
)))
}
}
}
impl TryFrom<f32> for Percent {
type Error = TryPercentFromFloatError;
fn try_from(v: f32) -> Result<Self, Self::Error> {
skip_assert_initialized!();
if v < 0.0 || v > 1.0 {
Err(TryPercentFromFloatError(()))
} else {
Ok(Percent(Some(
(v * ffi::GST_FORMAT_PERCENT_SCALE as f32).round() as u32,
)))
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_clock_time() {
crate::init().unwrap();
let t1 = crate::SECOND;
let t2 = 2 * t1;
let t3 = &t1 * 2;
let mut t4 = t2 + t3;
t4 += &t1;
assert_eq!(t4.nanoseconds(), Some(5_000_000_000));
let t5 = t4 - 6 * crate::SECOND;
assert!(t5.is_none());
}
}