// Take a look at the license at the top of the repository in the LICENSE file. use crate::ClockTime; use crate::Format; use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib}; use muldiv::MulDiv; use opt_ops::prelude::*; use std::borrow::Borrow; use std::fmt; use std::ops; use thiserror::Error; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] #[cfg_attr(feature = "ser_de", derive(serde::Serialize, serde::Deserialize))] pub enum GenericFormattedValue { Undefined(Undefined), Default(Option), Bytes(Option), Time(Option), Buffers(Option), Percent(Option), Other(Format, i64), } #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Undefined(pub i64); #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Default(pub u64); impl Default { pub const MAX: Self = Self(u64::MAX - 1); } #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Bytes(pub u64); impl Bytes { pub const MAX: Self = Self(u64::MAX - 1); } pub type Time = ClockTime; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Buffers(pub u64); impl Buffers { #[doc(alias = "GST_BUFFER_OFFSET_NONE")] pub const OFFSET_NONE: u64 = ffi::GST_BUFFER_OFFSET_NONE; pub const MAX: Self = Self(Self::OFFSET_NONE - 1); } #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Percent(pub u32); impl Percent { #[doc(alias = "GST_FORMAT_PERCENT_MAX")] pub const MAX: Self = Self(ffi::GST_FORMAT_PERCENT_MAX as u32); #[doc(alias = "GST_FORMAT_PERCENT_SCALE")] pub const SCALE: u32 = ffi::GST_FORMAT_PERCENT_SCALE as u32; } impl fmt::Display for GenericFormattedValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use crate::utils::Displayable; match self { Self::Undefined(val) => val.fmt(f), Self::Default(val) => val.display().fmt(f), Self::Bytes(val) => val.display().fmt(f), Self::Time(val) => val.display().fmt(f), Self::Buffers(val) => val.display().fmt(f), Self::Percent(val) => val.display().fmt(f), Self::Other(format, val) => write!(f, "{} ({:?})", val, format), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Error)] #[error("invalid generic value format")] pub struct TryFromGenericFormattedValueError(()); pub trait FormattedValue: Copy + Clone + Sized + Into + '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 into_raw_value(self) -> i64; } // rustdoc-stripper-ignore-next /// A trait implemented on the intrinsic type of a `FormattedValue`. /// /// # Examples /// /// - `GenericFormattedValue` is the intrinsic type for `GenericFormattedValue`. /// - `Undefined` is the intrinsic type for `Undefined`. /// - `Bytes` is the intrinsic type for `Option`. pub trait FormattedValueIntrinsic: Copy + Clone + Sized + 'static { type FormattedValueType: FormattedValue; } pub trait SpecificFormattedValue: FormattedValue + TryFrom {} // rustdoc-stripper-ignore-next /// A trait implemented on the intrinsic type of a `SpecificFormattedValue`. /// /// # Examples /// /// - `Undefined` is the intrinsic type for `Undefined`. /// - `Bytes` is the intrinsic type for `Option`. pub trait SpecificFormattedValueIntrinsic: TryFromGlib + FormattedValueIntrinsic {} 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 into_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(unsafe { FromGlib::from_glib(value as u64) }), Format::Bytes => Self::Bytes(unsafe { FromGlib::from_glib(value as u64) }), Format::Time => Self::Time(unsafe { FromGlib::from_glib(value as u64) }), Format::Buffers => Self::Buffers(unsafe { FromGlib::from_glib(value as u64) }), Format::Percent => Self::Percent(unsafe { FormattedValue::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 { unsafe { match *self { Self::Undefined(v) => v.0, Self::Default(v) => v.into_raw_value(), Self::Bytes(v) => v.into_raw_value(), Self::Time(v) => v.into_raw_value(), Self::Buffers(v) => v.into_raw_value(), Self::Percent(v) => v.into_raw_value(), Self::Other(_, v) => v, } } } } impl FormattedValueIntrinsic for GenericFormattedValue { type FormattedValueType = GenericFormattedValue; } impl_common_ops_for_newtype_uint!(Default, u64); impl_format_value_traits!(Default, Default, Default, u64); option_glib_newtype_from_to!(Default, u64::MAX); option_glib_newtype_display!(Default, "(Default)"); impl_common_ops_for_newtype_uint!(Bytes, u64); impl_format_value_traits!(Bytes, Bytes, Bytes, u64); option_glib_newtype_from_to!(Bytes, u64::MAX); option_glib_newtype_display!(Bytes, "bytes"); impl_format_value_traits!(ClockTime, Time, Time, u64); impl_common_ops_for_newtype_uint!(Buffers, u64); impl_format_value_traits!(Buffers, Buffers, Buffers, u64); option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE); option_glib_newtype_display!(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 into_raw_value(self) -> i64 { self.0 } } impl From for GenericFormattedValue { fn from(v: Undefined) -> Self { skip_assert_initialized!(); GenericFormattedValue::Undefined(v) } } impl TryFrom for Undefined { type Error = TryFromGenericFormattedValueError; fn try_from(v: GenericFormattedValue) -> Result { skip_assert_initialized!(); if let GenericFormattedValue::Undefined(v) = v { Ok(v) } else { Err(TryFromGenericFormattedValueError(())) } } } impl FormattedValueIntrinsic for Undefined { type FormattedValueType = Undefined; } impl SpecificFormattedValue for Undefined {} impl SpecificFormattedValueIntrinsic for Undefined {} impl TryFromGlib for Undefined { type Error = std::convert::Infallible; #[inline] unsafe fn try_from_glib(v: i64) -> Result { skip_assert_initialized!(); Ok(Undefined(v)) } } impl From for Undefined { fn from(v: i64) -> Self { skip_assert_initialized!(); Undefined(v) } } 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 for Undefined { fn as_ref(&self) -> &i64 { &self.0 } } impl AsMut for Undefined { fn as_mut(&mut self) -> &mut i64 { &mut self.0 } } impl fmt::Display for Undefined { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} (Undefined)", self.0) } } impl crate::utils::Displayable for Undefined { type DisplayImpl = Undefined; fn display(self) -> Undefined { self } } impl_common_ops_for_newtype_uint!(Percent, u32); option_glib_newtype_display!(Percent, "%"); impl FormattedValue for Option { 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); Percent::try_from_glib(value as i64).ok() } unsafe fn into_raw_value(self) -> i64 { self.map_or(-1, |v| v.0 as i64) } } impl From> for GenericFormattedValue { fn from(v: Option) -> Self { skip_assert_initialized!(); GenericFormattedValue::Percent(v) } } impl From for GenericFormattedValue { fn from(v: Percent) -> Self { skip_assert_initialized!(); GenericFormattedValue::Percent(Some(v)) } } impl TryFrom for Percent { type Error = GlibNoneError; fn try_from(v: u64) -> Result { skip_assert_initialized!(); unsafe { Self::try_from_glib(v as i64) } } } impl TryFromGlib for Percent { type Error = GlibNoneError; #[inline] unsafe fn try_from_glib(value: i64) -> Result { skip_assert_initialized!(); if value < 0 || value > ffi::GST_FORMAT_PERCENT_MAX { Err(GlibNoneError) } else { Ok(Percent(value as u32)) } } } impl TryFrom for Option { type Error = TryFromGenericFormattedValueError; fn try_from( v: GenericFormattedValue, ) -> Result, TryFromGenericFormattedValueError> { skip_assert_initialized!(); if let GenericFormattedValue::Percent(v) = v { Ok(v) } else { Err(TryFromGenericFormattedValueError(())) } } } impl FormattedValueIntrinsic for Percent { type FormattedValueType = Option; } impl SpecificFormattedValue for Option {} impl SpecificFormattedValueIntrinsic for Percent {} impl ops::Deref for Percent { type Target = u32; fn deref(&self) -> &u32 { &self.0 } } impl ops::DerefMut for Percent { fn deref_mut(&mut self) -> &mut u32 { &mut self.0 } } impl AsRef for Percent { fn as_ref(&self) -> &u32 { &self.0 } } impl AsMut for Percent { fn as_mut(&mut self) -> &mut u32 { &mut self.0 } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Error)] #[error("value out of range")] pub struct TryPercentFromFloatError(()); impl TryFrom for Percent { type Error = TryPercentFromFloatError; fn try_from(v: f64) -> Result { skip_assert_initialized!(); if v < 0.0 || v > 1.0 { Err(TryPercentFromFloatError(())) } else { Ok(Percent( (v * ffi::GST_FORMAT_PERCENT_SCALE as f64).round() as u32 )) } } } impl TryFrom for Percent { type Error = TryPercentFromFloatError; fn try_from(v: f32) -> Result { skip_assert_initialized!(); if v < 0.0 || v > 1.0 { Err(TryPercentFromFloatError(())) } else { Ok(Percent( (v * ffi::GST_FORMAT_PERCENT_SCALE as f32).round() as u32 )) } } }