gst/format: shuffle types and traits

This commit is contained in:
François Laignel 2022-09-22 23:35:07 +02:00
parent 79377337a4
commit eb4d997f0a
8 changed files with 1229 additions and 1176 deletions

View file

@ -2,13 +2,16 @@
use glib::translate::*; use glib::translate::*;
use glib::StaticType; use glib::StaticType;
use muldiv::MulDiv;
use num_integer::div_rem; use std::fmt;
use opt_ops::prelude::*;
use std::io::{self, prelude::*}; use std::io::{self, prelude::*};
use std::ops;
use std::time::Duration; use std::time::Duration;
use std::{cmp, fmt, str};
use super::{Format, FormattedValueError, GenericFormattedValue, Signed};
use super::{
FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, FormattedValueNoneBuilder,
SpecificFormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic,
};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
pub struct ClockTime(pub(crate) u64); pub struct ClockTime(pub(crate) u64);
@ -115,6 +118,85 @@ impl ClockTime {
} }
} }
impl Signed<ClockTime> {
// rustdoc-stripper-ignore-next
/// Returns the `self` in nanoseconds.
pub fn nseconds(self) -> Signed<u64> {
match self {
Signed::Positive(val) => Signed::Positive(val.nseconds()),
Signed::Negative(val) => Signed::Negative(val.nseconds()),
}
}
// rustdoc-stripper-ignore-next
/// Creates new value from nanoseconds.
pub fn from_nseconds(val: Signed<u64>) -> Self {
skip_assert_initialized!();
match val {
Signed::Positive(val) => Signed::Positive(ClockTime::from_nseconds(val)),
Signed::Negative(val) => Signed::Negative(ClockTime::from_nseconds(val)),
}
}
// rustdoc-stripper-ignore-next
/// Returns the `self` in microseconds.
pub fn useconds(self) -> Signed<u64> {
match self {
Signed::Positive(val) => Signed::Positive(val.useconds()),
Signed::Negative(val) => Signed::Negative(val.useconds()),
}
}
// rustdoc-stripper-ignore-next
/// Creates new value from microseconds.
pub fn from_useconds(val: Signed<u64>) -> Self {
skip_assert_initialized!();
match val {
Signed::Positive(val) => Signed::Positive(ClockTime::from_useconds(val)),
Signed::Negative(val) => Signed::Negative(ClockTime::from_useconds(val)),
}
}
// rustdoc-stripper-ignore-next
/// Returns the `self` in milliseconds.
pub fn mseconds(self) -> Signed<u64> {
match self {
Signed::Positive(val) => Signed::Positive(val.mseconds()),
Signed::Negative(val) => Signed::Negative(val.mseconds()),
}
}
// rustdoc-stripper-ignore-next
/// Creates new value from milliseconds.
pub fn from_mseconds(val: Signed<u64>) -> Self {
skip_assert_initialized!();
match val {
Signed::Positive(val) => Signed::Positive(ClockTime::from_mseconds(val)),
Signed::Negative(val) => Signed::Negative(ClockTime::from_mseconds(val)),
}
}
// rustdoc-stripper-ignore-next
/// Returns the `self` in seconds.
pub fn seconds(self) -> Signed<u64> {
match self {
Signed::Positive(val) => Signed::Positive(val.seconds()),
Signed::Negative(val) => Signed::Negative(val.seconds()),
}
}
// rustdoc-stripper-ignore-next
/// Creates new value from seconds.
pub fn from_seconds(val: Signed<u64>) -> Self {
skip_assert_initialized!();
match val {
Signed::Positive(val) => Signed::Positive(ClockTime::from_seconds(val)),
Signed::Negative(val) => Signed::Negative(ClockTime::from_seconds(val)),
}
}
}
impl_format_value_traits!(ClockTime, Time, Time, u64);
option_glib_newtype_from_to!(ClockTime, ffi::GST_CLOCK_TIME_NONE); option_glib_newtype_from_to!(ClockTime, ffi::GST_CLOCK_TIME_NONE);
impl glib::value::ValueType for ClockTime { impl glib::value::ValueType for ClockTime {
@ -324,13 +406,13 @@ fn write_clocktime<W: io::Write>(
precision: usize, precision: usize,
) -> io::Result<()> { ) -> io::Result<()> {
skip_assert_initialized!(); skip_assert_initialized!();
let precision = cmp::min(9, precision); let precision = std::cmp::min(9, precision);
if let Some(ns) = clocktime.map(ClockTime::nseconds) { if let Some(ns) = clocktime.map(ClockTime::nseconds) {
// Split the time into parts // Split the time into parts
let (s, ns) = div_rem(ns, 1_000_000_000); let (s, ns) = num_integer::div_rem(ns, 1_000_000_000);
let (m, s) = div_rem(s, 60); let (m, s) = num_integer::div_rem(s, 60);
let (h, m) = div_rem(m, 60); let (h, m) = num_integer::div_rem(m, 60);
// Write HH:MM:SS // Write HH:MM:SS
write!(writer, "{}:{:02}:{:02}", h, m, s)?; write!(writer, "{}:{:02}:{:02}", h, m, s)?;
@ -340,7 +422,7 @@ fn write_clocktime<W: io::Write>(
// The value is zero-padded so always 9 digits long // The value is zero-padded so always 9 digits long
let mut buf = [0u8; 9]; let mut buf = [0u8; 9];
write!(&mut buf[..], "{:09}", ns).unwrap(); write!(&mut buf[..], "{:09}", ns).unwrap();
let buf_str = str::from_utf8(&buf[..]).unwrap(); let buf_str = std::str::from_utf8(&buf[..]).unwrap();
// Write decimal point and a prefix of the nanoseconds for more precision // Write decimal point and a prefix of the nanoseconds for more precision
write!(writer, ".{:.p$}", buf_str, p = precision)?; write!(writer, ".{:.p$}", buf_str, p = precision)?;
@ -372,7 +454,7 @@ fn fmt_opt_clock_time(ct: Option<ClockTime>, f: &mut fmt::Formatter) -> fmt::Res
let mut cursor = io::Cursor::new(&mut buf[..]); let mut cursor = io::Cursor::new(&mut buf[..]);
write_clocktime(&mut cursor, ct, precision).unwrap(); write_clocktime(&mut cursor, ct, precision).unwrap();
let pos = cursor.position() as usize; let pos = cursor.position() as usize;
let buf_str = str::from_utf8(&buf[..pos]).unwrap(); let buf_str = std::str::from_utf8(&buf[..pos]).unwrap();
let sign = if ct.is_some() { let sign = if ct.is_some() {
Sign::NonNegative Sign::NonNegative
@ -436,6 +518,7 @@ impl std::iter::Sum for ClockTime {
mod tests { mod tests {
use super::*; use super::*;
use crate::{Signed, UnsignedIntoSigned}; use crate::{Signed, UnsignedIntoSigned};
use opt_ops::prelude::*;
const CT_1: ClockTime = ClockTime::from_nseconds(1); const CT_1: ClockTime = ClockTime::from_nseconds(1);
const CT_2: ClockTime = ClockTime::from_nseconds(2); const CT_2: ClockTime = ClockTime::from_nseconds(2);
@ -729,6 +812,8 @@ mod tests {
#[test] #[test]
fn mul_div_ops() { fn mul_div_ops() {
use muldiv::MulDiv;
assert_eq!(CT_1.mul_div_floor(7, 3), Some(CT_2)); 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(7u64, 3), Some(P_CT_2));

View file

@ -0,0 +1,175 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use super::{Format, FormattedValueError, GenericFormattedValue};
use super::{FormattedValue, SpecificFormattedValue};
// rustdoc-stripper-ignore-next
/// A trait implemented on types which can hold [`FormattedValue`]s compatible with parameter `F`.
///
/// This trait is auto-implemented based on [`FormattedValue`]s additional traits
/// such as [`SpecificFormattedValue`].
///
/// # Example:
///
/// Consider the following function:
///
/// ```rust
/// # use gstreamer::{ClockTime, CompatibleFormattedValue, FormattedValue, GenericFormattedValue};
/// fn with_compatible_formats<V: FormattedValue>(
/// arg1: V,
/// arg2: impl CompatibleFormattedValue<V>,
/// ) {
/// // This is required to access arg2 as a FormattedValue:
/// let _arg2 = arg2.try_into_checked(arg1).unwrap();
/// }
///
/// // This is Ok because arg1 is a ClockTime and arg2 is
/// // an Option<ClockTime> which are compatible format-wise.
/// with_compatible_formats(ClockTime::ZERO, ClockTime::NONE);
///
/// // This is Ok because arg1 is a ClockTime and arg2 is
/// // a GenericFormattedValue which are compatible format-wise.
/// with_compatible_formats(
/// ClockTime::ZERO,
/// GenericFormattedValue::Time(None),
/// );
/// ```
///
/// Users are able to call the function with arguments:
///
/// 1. of the same type (e.g. `ClockTime`),
/// 2. of different types, but able to hold a value of the same [`Format`]
/// (e.g. `ClockTime` and `Option<ClockTime>`).
/// 3. One of a Formatted Value (specific or generic), the other being
/// a `GenericFormattedValue`.
///
/// Format compatibility for cases 1 and 2 is enforced by
/// the type system, while case 3 will be checked at runtime time.
///
/// ```compile_fail
/// # use gstreamer::{ClockTime, CompatibleFormattedValue, FormattedValue, format::Bytes};
/// # fn with_compatible_formats<V: FormattedValue>(
/// # arg1: V,
/// # arg2: impl CompatibleFormattedValue<V>,
/// # ) {}
/// // This doesn't compile because the arguments are not compatible:
/// let _ = with_compatible_formats(ClockTime::ZERO, Bytes(Some(42)));
/// ```
///
/// Note: users will not be able use `arg2` directly unless format
/// check succeeds:
///
/// ```compile_fail
/// # use gstreamer::{CompatibleFormattedValue, FormattedValue};
/// fn with_compatible_formats<V: FormattedValue>(
/// arg1: V,
/// arg2: impl CompatibleFormattedValue<V>,
/// ) {
/// // This doesn't compile because arg2 hasn't been checked:
/// let _format = arg2.format();
/// }
/// ```
pub trait CompatibleFormattedValue<V: FormattedValue> {
type Original: FormattedValue;
// rustdoc-stripper-ignore-next
/// Returns `Ok(self)` with its type restored if it is compatible with the format of `other`.
///
/// When used with compatible [`SpecificFormattedValue`]s, checks
/// are enforced by the type system, no runtime checks are performed.
///
/// When used with [`FormattedValue`] / [`GenericFormattedValue`] and
/// vice versa, a runtime format check is performed. If the check fails,
/// `Err(FormattedValueError)` is returned.
fn try_into_checked(self, other: V) -> Result<Self::Original, FormattedValueError>;
// rustdoc-stripper-ignore-next
/// Returns `Ok(self)` with its type restored if it is compatible with the format of `V`.
///
/// When possible, prefer using [`Self::try_into_checked`] which
/// reduces the risk of missuse.
///
/// When used with compatible [`SpecificFormattedValue`]s, checks
/// are enforced by the type system, no runtime checks are performed.
///
/// When used with [`SpecificFormattedValue`] as a parameter and
/// a [`GenericFormattedValue`] as `Self`, a runtime check is perfomed
/// against the default format of the parameter. If the check fails,
/// `Err(FormattedValueError)` is returned.
///
/// When used with [`GenericFormattedValue`] as a parameter and
/// a [`SpecificFormattedValue`] as `Self`, the `format` argument
/// used. If the check fails, `Err(FormattedValueError)` is returned.
fn try_into_checked_explicit(
self,
format: Format,
) -> Result<Self::Original, FormattedValueError>;
}
impl<T, V> CompatibleFormattedValue<V> for T
where
V: SpecificFormattedValue,
T: SpecificFormattedValue<FullRange = V::FullRange>,
{
type Original = Self;
fn try_into_checked(self, _other: V) -> Result<Self, FormattedValueError> {
skip_assert_initialized!();
Ok(self)
}
fn try_into_checked_explicit(
self,
_format: Format,
) -> Result<Self::Original, FormattedValueError> {
skip_assert_initialized!();
Ok(self)
}
}
impl<T: SpecificFormattedValue> CompatibleFormattedValue<GenericFormattedValue> for T {
type Original = Self;
fn try_into_checked(self, other: GenericFormattedValue) -> Result<Self, FormattedValueError> {
skip_assert_initialized!();
if self.format() == other.format() {
Ok(self)
} else {
Err(FormattedValueError(self.format()))
}
}
fn try_into_checked_explicit(
self,
format: Format,
) -> Result<Self::Original, FormattedValueError> {
skip_assert_initialized!();
if self.format() == format {
Ok(self)
} else {
Err(FormattedValueError(self.format()))
}
}
}
impl<V: SpecificFormattedValue> CompatibleFormattedValue<V> for GenericFormattedValue {
type Original = Self;
fn try_into_checked(self, _other: V) -> Result<Self, FormattedValueError> {
skip_assert_initialized!();
if self.format() == V::default_format() {
Ok(self)
} else {
Err(FormattedValueError(self.format()))
}
}
fn try_into_checked_explicit(
self,
_format: Format,
) -> Result<Self::Original, FormattedValueError> {
skip_assert_initialized!();
if self.format() == V::default_format() {
Ok(self)
} else {
Err(FormattedValueError(self.format()))
}
}
}

View file

@ -0,0 +1,202 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::FromGlib;
use std::fmt;
use crate::utils::Displayable;
use super::{
Buffers, Bytes, ClockTime, Default, Format, FormattedValueError, Percent, Signed, Undefined,
};
use super::{
CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic,
FormattedValueNoneBuilder, UnsignedIntoSigned,
};
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GenericFormattedValue {
Undefined(Undefined),
Default(Option<Default>),
Bytes(Option<Bytes>),
Time(Option<ClockTime>),
Buffers(Option<Buffers>),
Percent(Option<Percent>),
Other(Format, i64),
}
impl fmt::Display for GenericFormattedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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),
}
}
}
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 { FormattedValueFullRange::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 FormattedValue for GenericFormattedValue {
// The intrinsic value for `GenericFormattedValue` is also
// `GenericFormattedValue`. We can't dissociate the `Option`
// from the variants' inner type since they are not all `Option`s.
type FullRange = GenericFormattedValue;
fn default_format() -> Format {
Format::Undefined
}
fn format(&self) -> Format {
self.format()
}
fn is_some(&self) -> bool {
match self {
Self::Undefined(_) => true,
Self::Default(v) => v.is_some(),
Self::Bytes(v) => v.is_some(),
Self::Time(v) => v.is_some(),
Self::Buffers(v) => v.is_some(),
Self::Percent(v) => v.is_some(),
Self::Other(..) => true,
}
}
unsafe fn into_raw_value(self) -> i64 {
self.value()
}
}
impl FormattedValueFullRange for GenericFormattedValue {
unsafe fn from_raw(format: Format, value: i64) -> Self {
GenericFormattedValue::new(format, value)
}
}
impl FormattedValueIntrinsic for GenericFormattedValue {}
impl FormattedValueNoneBuilder for GenericFormattedValue {
#[track_caller]
fn none() -> Self {
panic!(concat!(
"`GenericFormattedValue` can't build `None` without knowing",
"the target format. Use `GenericFormattedValue::none_for_format`",
));
}
#[track_caller]
fn none_for_format(format: Format) -> Self {
skip_assert_initialized!();
match format {
Format::Undefined => panic!("`None` can't be represented by `Undefined`"),
Format::Default => Self::Default(None),
Format::Bytes => Self::Bytes(None),
Format::Time => Self::Time(None),
Format::Buffers => Self::Buffers(None),
Format::Percent => Self::Percent(None),
Format::__Unknown(_) => panic!("`None` can't be represented by `__Unknown`"),
}
}
}
impl UnsignedIntoSigned for GenericFormattedValue {
type Signed = Signed<GenericFormattedValue>;
#[track_caller]
fn into_positive(self) -> Signed<GenericFormattedValue> {
match self {
GenericFormattedValue::Undefined(_) => {
unimplemented!("`GenericFormattedValue::Undefined` is already signed")
}
GenericFormattedValue::Other(..) => {
unimplemented!("`GenericFormattedValue::Other` is already signed")
}
unsigned_inner => Signed::Positive(unsigned_inner),
}
}
#[track_caller]
fn into_negative(self) -> Signed<GenericFormattedValue> {
match self {
GenericFormattedValue::Undefined(_) => {
unimplemented!("`GenericFormattedValue::Undefined` is already signed")
}
GenericFormattedValue::Other(..) => {
unimplemented!("`GenericFormattedValue::Other` is already signed")
}
unsigned_inner => Signed::Negative(unsigned_inner),
}
}
}
impl CompatibleFormattedValue<GenericFormattedValue> for GenericFormattedValue {
type Original = Self;
fn try_into_checked(self, other: GenericFormattedValue) -> Result<Self, FormattedValueError> {
skip_assert_initialized!();
if self.format() == other.format() {
Ok(self)
} else {
Err(FormattedValueError(self.format()))
}
}
fn try_into_checked_explicit(
self,
format: Format,
) -> Result<Self::Original, FormattedValueError> {
skip_assert_initialized!();
if self.format() == format {
Ok(self)
} else {
Err(FormattedValueError(self.format()))
}
}
}

View file

@ -2,7 +2,7 @@
macro_rules! impl_trait_op_same( macro_rules! impl_trait_op_same(
($name:ident, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { ($name:ident, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => {
impl ops::$op<$name> for $name { impl std::ops::$op<$name> for $name {
type Output = Self; type Output = Self;
fn $op_name(self, rhs: $name) -> Self::Output { fn $op_name(self, rhs: $name) -> Self::Output {
@ -10,7 +10,7 @@ macro_rules! impl_trait_op_same(
} }
} }
impl ops::$op_assign<$name> for $name { impl std::ops::$op_assign<$name> for $name {
fn $op_assign_name(&mut self, rhs: $name) { fn $op_assign_name(&mut self, rhs: $name) {
self.0.$op_assign_name(rhs.0) self.0.$op_assign_name(rhs.0)
} }
@ -98,7 +98,7 @@ macro_rules! impl_non_trait_op_same(
macro_rules! impl_trait_op_inner_type( macro_rules! impl_trait_op_inner_type(
($name:ident, $inner_type:ty, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { ($name:ident, $inner_type:ty, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => {
impl ops::$op<$inner_type> for $name { impl std::ops::$op<$inner_type> for $name {
type Output = $name; type Output = $name;
fn $op_name(self, rhs: $inner_type) -> Self::Output { fn $op_name(self, rhs: $inner_type) -> Self::Output {
@ -106,7 +106,7 @@ macro_rules! impl_trait_op_inner_type(
} }
} }
impl ops::$op<$name> for $inner_type { impl std::ops::$op<$name> for $inner_type {
type Output = $name; type Output = $name;
fn $op_name(self, rhs: $name) -> $name { fn $op_name(self, rhs: $name) -> $name {
@ -114,7 +114,7 @@ macro_rules! impl_trait_op_inner_type(
} }
} }
impl 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)
} }
@ -250,7 +250,7 @@ macro_rules! impl_common_ops_for_newtype_uint(
impl_unsigned_int_into_signed!($name); impl_unsigned_int_into_signed!($name);
impl_signed_ops!($name, $inner_type, $name::ZERO); impl_signed_ops!($name, $inner_type, $name::ZERO);
impl MulDiv<$inner_type> for $name { impl muldiv::MulDiv<$inner_type> for $name {
type Output = $name; type Output = $name;
fn mul_div_floor(self, num: $inner_type, denom: $inner_type) -> Option<Self::Output> { fn mul_div_floor(self, num: $inner_type, denom: $inner_type) -> Option<Self::Output> {
@ -272,9 +272,9 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl OptionOperations for $name {} impl opt_ops::OptionOperations for $name {}
impl OptionCheckedAdd for $name { impl opt_ops::OptionCheckedAdd for $name {
type Output = Self; type Output = Self;
fn opt_checked_add( fn opt_checked_add(
self, self,
@ -286,14 +286,14 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl OptionSaturatingAdd for $name { impl opt_ops::OptionSaturatingAdd for $name {
type Output = Self; type Output = Self;
fn opt_saturating_add(self, rhs: Self) -> Option<Self::Output> { fn opt_saturating_add(self, rhs: Self) -> Option<Self::Output> {
Some(self.saturating_add(rhs)) Some(self.saturating_add(rhs))
} }
} }
impl OptionOverflowingAdd for $name { impl opt_ops::OptionOverflowingAdd for $name {
type Output = Self; type Output = Self;
fn opt_overflowing_add(self, rhs: Self) -> Option<(Self::Output, bool)> { fn opt_overflowing_add(self, rhs: Self) -> Option<(Self::Output, bool)> {
let res = self.overflowing_add(rhs); let res = self.overflowing_add(rhs);
@ -301,14 +301,14 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl OptionWrappingAdd for $name { impl opt_ops::OptionWrappingAdd for $name {
type Output = Self; type Output = Self;
fn opt_wrapping_add(self, rhs: Self) -> Option<Self::Output> { fn opt_wrapping_add(self, rhs: Self) -> Option<Self::Output> {
Some(self.wrapping_add(rhs)) Some(self.wrapping_add(rhs))
} }
} }
impl OptionCheckedDiv<$inner_type> for $name { impl opt_ops::OptionCheckedDiv<$inner_type> for $name {
type Output = Self; type Output = Self;
fn opt_checked_div(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> { fn opt_checked_div(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs == 0 { if rhs == 0 {
@ -321,7 +321,7 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl OptionCheckedMul<$inner_type> for $name { impl opt_ops::OptionCheckedMul<$inner_type> for $name {
type Output = Self; type Output = Self;
fn opt_checked_mul( fn opt_checked_mul(
self, self,
@ -333,14 +333,14 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl 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> {
Some(self.saturating_mul(rhs)) Some(self.saturating_mul(rhs))
} }
} }
impl 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)> {
let res = self.overflowing_mul(rhs); let res = self.overflowing_mul(rhs);
@ -348,14 +348,14 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl 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> {
Some(self.wrapping_mul(rhs)) Some(self.wrapping_mul(rhs))
} }
} }
impl 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 {
@ -368,7 +368,7 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl OptionCheckedSub for $name { impl opt_ops::OptionCheckedSub for $name {
type Output = Self; type Output = Self;
fn opt_checked_sub( fn opt_checked_sub(
self, self,
@ -380,14 +380,14 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl OptionSaturatingSub for $name { impl opt_ops::OptionSaturatingSub for $name {
type Output = Self; type Output = Self;
fn opt_saturating_sub(self, rhs: Self) -> Option<Self::Output> { fn opt_saturating_sub(self, rhs: Self) -> Option<Self::Output> {
Some(self.saturating_sub(rhs)) Some(self.saturating_sub(rhs))
} }
} }
impl OptionOverflowingSub for $name { impl opt_ops::OptionOverflowingSub for $name {
type Output = Self; type Output = Self;
fn opt_overflowing_sub(self, rhs: Self) -> Option<(Self::Output, bool)> { fn opt_overflowing_sub(self, rhs: Self) -> Option<(Self::Output, bool)> {
let res = self.overflowing_sub(rhs); let res = self.overflowing_sub(rhs);
@ -395,7 +395,7 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl OptionWrappingSub for $name { impl opt_ops::OptionWrappingSub for $name {
type Output = Self; type Output = Self;
fn opt_wrapping_sub(self, rhs: Self) -> Option<Self::Output> { fn opt_wrapping_sub(self, rhs: Self) -> Option<Self::Output> {
Some(self.wrapping_sub(rhs)) Some(self.wrapping_sub(rhs))
@ -577,25 +577,25 @@ macro_rules! impl_signed_ops(
} }
} }
impl 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))
} }
} }
impl PartialEq<$type> for crate::Signed<$type> { impl std::cmp::PartialEq<$type> for crate::Signed<$type> {
fn eq(&self, other: &$type) -> bool { fn eq(&self, other: &$type) -> bool {
self.eq(&crate::Signed::Positive(*other)) self.eq(&crate::Signed::Positive(*other))
} }
} }
impl 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 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::*;
match (self, other) { match (self, other) {
@ -607,9 +607,9 @@ macro_rules! impl_signed_ops(
} }
} }
impl OptionOperations for crate::Signed<$type> {} impl opt_ops::OptionOperations for crate::Signed<$type> {}
impl OptionCheckedAdd for crate::Signed<$type> { impl opt_ops::OptionCheckedAdd for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_checked_add( fn opt_checked_add(
self, self,
@ -621,14 +621,14 @@ macro_rules! impl_signed_ops(
} }
} }
impl OptionSaturatingAdd for crate::Signed<$type> { impl opt_ops::OptionSaturatingAdd for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_saturating_add(self, rhs: Self) -> Option<Self::Output> { fn opt_saturating_add(self, rhs: Self) -> Option<Self::Output> {
Some(self.saturating_add(rhs)) Some(self.saturating_add(rhs))
} }
} }
impl OptionCheckedSub for crate::Signed<$type> { impl opt_ops::OptionCheckedSub for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_checked_sub( fn opt_checked_sub(
self, self,
@ -640,7 +640,7 @@ macro_rules! impl_signed_ops(
} }
} }
impl OptionSaturatingSub for crate::Signed<$type> { impl opt_ops::OptionSaturatingSub for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_saturating_sub(self, rhs: Self) -> Option<Self::Output> { fn opt_saturating_sub(self, rhs: Self) -> Option<Self::Output> {
Some(self.saturating_sub(rhs)) Some(self.saturating_sub(rhs))
@ -890,7 +890,7 @@ macro_rules! impl_signed_div_mul(
} }
} }
impl OptionCheckedDiv<$signed_rhs> for crate::Signed<$type> { impl opt_ops::OptionCheckedDiv<$signed_rhs> for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_checked_div(self, rhs: $signed_rhs) -> Result<Option<Self::Output>, opt_ops::Error> { fn opt_checked_div(self, rhs: $signed_rhs) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs == 0 { if rhs == 0 {
@ -902,7 +902,7 @@ macro_rules! impl_signed_div_mul(
} }
} }
impl OptionCheckedMul<$signed_rhs> for crate::Signed<$type> { impl opt_ops::OptionCheckedMul<$signed_rhs> for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_checked_mul(self, rhs: $signed_rhs) -> Result<Option<Self::Output>, opt_ops::Error> { fn opt_checked_mul(self, rhs: $signed_rhs) -> Result<Option<Self::Output>, opt_ops::Error> {
self.checked_mul(rhs) self.checked_mul(rhs)
@ -911,14 +911,14 @@ macro_rules! impl_signed_div_mul(
} }
} }
impl OptionSaturatingMul<$signed_rhs> for crate::Signed<$type> { impl opt_ops::OptionSaturatingMul<$signed_rhs> for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_saturating_mul(self, rhs: $signed_rhs) -> Option<Self::Output> { fn opt_saturating_mul(self, rhs: $signed_rhs) -> Option<Self::Output> {
Some(self.saturating_mul(rhs)) Some(self.saturating_mul(rhs))
} }
} }
impl OptionCheckedRem<$signed_rhs> for crate::Signed<$type> { impl opt_ops::OptionCheckedRem<$signed_rhs> for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_checked_rem(self, rhs: $signed_rhs) -> Result<Option<Self::Output>, opt_ops::Error> { fn opt_checked_rem(self, rhs: $signed_rhs) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs == 0 { if rhs == 0 {
@ -930,7 +930,7 @@ macro_rules! impl_signed_div_mul(
} }
} }
impl OptionCheckedDiv<$inner_type> for crate::Signed<$type> { impl opt_ops::OptionCheckedDiv<$inner_type> for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_checked_div(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> { fn opt_checked_div(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> {
if rhs == 0 { if rhs == 0 {
@ -942,7 +942,7 @@ macro_rules! impl_signed_div_mul(
} }
} }
impl OptionCheckedMul<$inner_type> for crate::Signed<$type> { impl opt_ops::OptionCheckedMul<$inner_type> for crate::Signed<$type> {
type Output = Self; type Output = Self;
fn opt_checked_mul(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> { fn opt_checked_mul(self, rhs: $inner_type) -> Result<Option<Self::Output>, opt_ops::Error> {
self.checked_mul_unsigned(rhs) self.checked_mul_unsigned(rhs)
@ -951,14 +951,14 @@ macro_rules! impl_signed_div_mul(
} }
} }
impl OptionSaturatingMul<$inner_type> for crate::Signed<$type> { impl opt_ops::OptionSaturatingMul<$inner_type> for crate::Signed<$type> {
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> {
Some(self.saturating_mul_unsigned(rhs)) Some(self.saturating_mul_unsigned(rhs))
} }
} }
impl OptionCheckedRem<$inner_type> for crate::Signed<$type> { impl opt_ops::OptionCheckedRem<$inner_type> for crate::Signed<$type> {
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 {
@ -997,7 +997,7 @@ macro_rules! impl_signed_div_mul_trait(
} }
} }
impl MulDiv<$signed_rhs> for crate::Signed<$type> { impl muldiv::MulDiv<$signed_rhs> for crate::Signed<$type> {
type Output = crate::Signed<$type>; type Output = crate::Signed<$type>;
fn mul_div_floor(self, num: $signed_rhs, denom: $signed_rhs) -> Option<Self::Output> { fn mul_div_floor(self, num: $signed_rhs, denom: $signed_rhs) -> Option<Self::Output> {
@ -1049,7 +1049,7 @@ macro_rules! impl_signed_div_mul_trait(
} }
} }
impl MulDiv<$inner_type> for crate::Signed<$type> { impl muldiv::MulDiv<$inner_type> for crate::Signed<$type> {
type Output = crate::Signed<$type>; type Output = crate::Signed<$type>;
fn mul_div_floor(self, num: $inner_type, denom: $inner_type) -> Option<Self::Output> { fn mul_div_floor(self, num: $inner_type, denom: $inner_type) -> Option<Self::Output> {
@ -1209,7 +1209,7 @@ macro_rules! impl_format_value_traits(
} }
} }
impl ops::Deref for $name { impl std::ops::Deref for $name {
type Target = $inner_type; type Target = $inner_type;
fn deref(&self) -> &$inner_type { fn deref(&self) -> &$inner_type {
@ -1217,7 +1217,7 @@ macro_rules! impl_format_value_traits(
} }
} }
impl ops::DerefMut for $name { impl std::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut $inner_type { fn deref_mut(&mut self) -> &mut $inner_type {
&mut self.0 &mut self.0
} }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,322 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use std::fmt;
use super::{Format, FormattedValueIntrinsic, FormattedValueNoneBuilder};
use crate::utils::Displayable;
// rustdoc-stripper-ignore-next
/// A signed wrapper.
///
/// This wrapper allows representing a signed value from a type
/// which is originaly unsigned. In C APIs, this is represented
/// by a tuple with a signed integer positive or negative and
/// the absolute value.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Signed<T> {
Negative(T),
Positive(T),
}
impl<T> Signed<T> {
pub fn is_positive(self) -> bool {
matches!(self, Signed::Positive(_))
}
// rustdoc-stripper-ignore-next
/// Returns `Some(value)`, where `value` is the inner value,
/// if `self` is positive.
pub fn positive(self) -> Option<T> {
match self {
Signed::Positive(val) => Some(val),
Signed::Negative(_) => None,
}
}
// rustdoc-stripper-ignore-next
/// Transforms the `Signed<T>` into a `Result<T, E>`,
/// mapping `Positive(v)` to `Ok(v)` and `Negative(_)` to `Err(err)`.
pub fn positive_or<E>(self, err: E) -> Result<T, E> {
match self {
Signed::Positive(val) => Ok(val),
Signed::Negative(_) => Err(err),
}
}
// rustdoc-stripper-ignore-next
/// Transforms the `Signed<T>` into a `Result<T, E>`,
/// mapping `Positive(v)` to `Ok(v)` and `Negative(v)` to `Err(err(v))`.
pub fn positive_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> {
match self {
Signed::Positive(val) => Ok(val),
Signed::Negative(val) => Err(err(val)),
}
}
pub fn is_negative(self) -> bool {
matches!(self, Signed::Negative(_))
}
// rustdoc-stripper-ignore-next
/// Returns `Some(value)`, where `value` is the inner value,
/// if `self` is negative.
pub fn negative(self) -> Option<T> {
match self {
Signed::Negative(val) => Some(val),
Signed::Positive(_) => None,
}
}
// rustdoc-stripper-ignore-next
/// Transforms the `Signed<T>` into a `Result<T, E>`,
/// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err)`.
pub fn negative_or<E>(self, err: E) -> Result<T, E> {
match self {
Signed::Negative(val) => Ok(val),
Signed::Positive(_) => Err(err),
}
}
// rustdoc-stripper-ignore-next
/// Transforms the `Signed<T>` into a `Result<T, E>`,
/// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err(v))`.
pub fn negative_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> {
match self {
Signed::Negative(val) => Ok(val),
Signed::Positive(val) => Err(err(val)),
}
}
// rustdoc-stripper-ignore-next
/// Returns the multiplication factor for this `Signed`.
///
/// Returns:
///
/// - `1` if the value must be considered as positive.
/// - `-1` if the value must be considered as negative.
pub fn factor(self) -> i32 {
match self {
Signed::Positive(_) => 1i32,
Signed::Negative(_) => -1i32,
}
}
// rustdoc-stripper-ignore-next
/// Returns the absolute value of `self`.
pub fn abs(self) -> T {
match self {
Signed::Positive(val) | Signed::Negative(val) => val,
}
}
}
impl<T> std::ops::Neg for Signed<T> {
type Output = Signed<T>;
fn neg(self) -> Self {
match self {
Signed::Positive(val) => Signed::Negative(val),
Signed::Negative(val) => Signed::Positive(val),
}
}
}
impl<T> fmt::Display for Signed<T>
where
T: fmt::Display + FormattedValueIntrinsic,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::fmt::Write;
let (sign, val) = match self {
Signed::Positive(val) => ('+', val),
Signed::Negative(val) => ('-', val),
};
f.write_char(sign)?;
fmt::Display::fmt(&val, f)
}
}
impl<T> Displayable for Signed<T>
where
T: fmt::Display + FormattedValueIntrinsic,
{
type DisplayImpl = Signed<T>;
fn display(self) -> Self::DisplayImpl {
self
}
}
impl<T> Signed<Option<T>> {
// rustdoc-stripper-ignore-next
/// Transposes a `Signed` `Option` into an `Option` of a `Signed`.
///
/// Note that if the inner value was `None`, the sign is lost.
pub fn transpose(self) -> Option<Signed<T>> {
use Signed::*;
match self {
Positive(Some(val)) => Some(Positive(val)),
Negative(Some(val)) => Some(Negative(val)),
_ => None,
}
}
}
pub struct DisplayableOptionSigned<T>(Option<Signed<T>>);
impl<T> fmt::Display for DisplayableOptionSigned<T>
where
T: fmt::Display + FormattedValueIntrinsic,
Option<T>: Displayable,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
Some(ref signed) => fmt::Display::fmt(signed, f),
None => fmt::Display::fmt(&Option::<T>::None.display(), f),
}
}
}
impl<T> Displayable for Option<Signed<T>>
where
T: fmt::Display + FormattedValueIntrinsic,
Option<T>: Displayable,
{
type DisplayImpl = DisplayableOptionSigned<T>;
fn display(self) -> Self::DisplayImpl {
DisplayableOptionSigned(self)
}
}
impl<T> Displayable for Signed<Option<T>>
where
T: fmt::Display + FormattedValueIntrinsic,
Option<T>: Displayable,
{
type DisplayImpl = DisplayableOptionSigned<T>;
fn display(self) -> Self::DisplayImpl {
DisplayableOptionSigned(self.transpose())
}
}
// rustdoc-stripper-ignore-next
/// A trait implemented on unsigned types which can be converted into [`crate::Signed`]s.
pub trait UnsignedIntoSigned: Copy + Sized {
type Signed;
// rustdoc-stripper-ignore-next
/// Converts `self` into a `Signed` matching the given `sign`.
fn into_signed(self, sign: i32) -> Self::Signed {
if sign.is_positive() {
self.into_positive()
} else {
self.into_negative()
}
}
// rustdoc-stripper-ignore-next
/// Converts `self` into a `Signed::Positive`.
fn into_positive(self) -> Self::Signed;
// rustdoc-stripper-ignore-next
/// Converts `self` into a `Signed::Negative`.
fn into_negative(self) -> Self::Signed;
}
impl_unsigned_int_into_signed!(u64);
impl_signed_ops!(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_signed_ops!(u32);
impl_signed_div_mul!(u32);
impl From<i64> for Signed<u64> {
fn from(val: i64) -> Signed<u64> {
skip_assert_initialized!();
match val {
positive if positive.is_positive() => Signed::Positive(positive as u64),
i64::MIN => {
// `i64::MIN.abs()` can't be represented as an `i64`
Signed::Negative((-(i64::MIN as i128)) as u64)
}
negative => Signed::Negative((-negative) as u64),
}
}
}
impl From<isize> for Signed<usize> {
fn from(val: isize) -> Signed<usize> {
skip_assert_initialized!();
match val {
positive if positive.is_positive() => Signed::Positive(positive as usize),
isize::MIN => {
// `isize::MIN.abs()` can't be represented as an `isize`
Signed::Negative((-(isize::MIN as i128)) as usize)
}
negative => Signed::Negative((-negative) as usize),
}
}
}
// `i32::MIN.abs()` can't be represented as an `i32`
impl From<i32> for Signed<u32> {
fn from(val: i32) -> Signed<u32> {
skip_assert_initialized!();
if val.is_positive() {
Signed::Positive(val as u32)
} else {
Signed::Negative((-(val as i64)) as u32)
}
}
}
pub trait NoneSignedBuilder: FormattedValueNoneBuilder {
type Signed;
// rustdoc-stripper-ignore-next
/// Returns the `None` value for `Self` as a `Signed<FullRange>` if such a value can be represented.
///
/// See details in [`FormattedValueNoneBuilder::none`].
///
/// # Panics
///
/// Panics if `Self` is `GenericFormattedValue` in which case, the `Format` must be known.
fn none_signed() -> Self::Signed;
// rustdoc-stripper-ignore-next
/// Returns the `None` value for `Self` as a `Signed<FullRange>`, if such a value can be represented.
///
/// See details in [`FormattedValueNoneBuilder::none_for_format`].
///
/// # Panics
///
/// Panics if `None` can't be represented by `Self` for `format` or by the requested
/// `GenericFormattedValue` variant.
fn none_signed_for_format(format: Format) -> Self::Signed;
}
impl<T> NoneSignedBuilder for T
where
T: UnsignedIntoSigned + FormattedValueNoneBuilder,
{
type Signed = <T as UnsignedIntoSigned>::Signed;
fn none_signed() -> Self::Signed {
Self::none().into_positive()
}
fn none_signed_for_format(format: Format) -> Self::Signed {
skip_assert_initialized!();
Self::none_for_format(format).into_positive()
}
}

View file

@ -0,0 +1,263 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib};
use super::{
Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic,
FormattedValueNoneBuilder, GenericFormattedValue,
};
pub trait SpecificFormattedValue: FormattedValue {}
pub trait SpecificFormattedValueFullRange: FormattedValueFullRange {}
// 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<Bytes>`.
pub trait SpecificFormattedValueIntrinsic: TryFromGlib<i64> + FormattedValueIntrinsic {}
#[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);
}
impl_common_ops_for_newtype_uint!(Buffers, u64);
impl_signed_div_mul!(Buffers, u64);
impl_format_value_traits!(Buffers, Buffers, Buffers, u64);
option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE);
glib_newtype_display!(
Buffers,
DisplayableBuffers,
DisplayableOptionBuffers,
"buffers"
);
#[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);
}
impl_common_ops_for_newtype_uint!(Bytes, u64);
impl_signed_div_mul!(Bytes, u64);
impl_format_value_traits!(Bytes, Bytes, Bytes, u64);
option_glib_newtype_from_to!(Bytes, u64::MAX);
glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes");
#[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);
}
impl_common_ops_for_newtype_uint!(Default, u64);
impl_signed_div_mul!(Default, u64);
impl_format_value_traits!(Default, Default, Default, u64);
option_glib_newtype_from_to!(Default, u64::MAX);
glib_newtype_display!(
Default,
DisplayableDefault,
DisplayableOptionDefault,
"(Default)"
);
pub type Time = super::ClockTime;
#[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_common_ops_for_newtype_uint!(Percent, u32);
impl_signed_div_mul!(Percent, u32);
glib_newtype_display!(Percent, DisplayablePercent, DisplayableOptionPercent, "%");
impl FormattedValue for Option<Percent> {
type FullRange = Option<Percent>;
fn default_format() -> Format {
Format::Percent
}
fn format(&self) -> Format {
Format::Percent
}
fn is_some(&self) -> bool {
Option::is_some(self)
}
unsafe fn into_raw_value(self) -> i64 {
self.map_or(-1, |v| v.0 as i64)
}
}
impl FormattedValueFullRange for Option<Percent> {
unsafe fn from_raw(format: Format, value: i64) -> Self {
debug_assert_eq!(format, Format::Percent);
Percent::try_from_glib(value as i64).ok()
}
}
impl From<Option<Percent>> for GenericFormattedValue {
fn from(v: Option<Percent>) -> Self {
skip_assert_initialized!();
GenericFormattedValue::Percent(v)
}
}
impl From<Percent> for GenericFormattedValue {
fn from(v: Percent) -> Self {
skip_assert_initialized!();
GenericFormattedValue::Percent(Some(v))
}
}
impl FormattedValue for Percent {
type FullRange = Option<Percent>;
fn default_format() -> Format {
Format::Percent
}
fn format(&self) -> Format {
Format::Percent
}
fn is_some(&self) -> bool {
true
}
unsafe fn into_raw_value(self) -> i64 {
self.0 as i64
}
}
impl TryFrom<u64> for Percent {
type Error = GlibNoneError;
fn try_from(v: u64) -> Result<Percent, GlibNoneError> {
skip_assert_initialized!();
unsafe { Self::try_from_glib(v as i64) }
}
}
impl TryFromGlib<i64> for Percent {
type Error = GlibNoneError;
#[inline]
unsafe fn try_from_glib(value: i64) -> Result<Self, Self::Error> {
skip_assert_initialized!();
if value < 0 || value > ffi::GST_FORMAT_PERCENT_MAX {
Err(GlibNoneError)
} else {
Ok(Percent(value as u32))
}
}
}
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> {
type Error = FormattedValueError;
fn try_from(v: GenericFormattedValue) -> Result<Option<Percent>, Self::Error> {
skip_assert_initialized!();
if let GenericFormattedValue::Percent(v) = v {
Ok(v)
} else {
Err(FormattedValueError(v.format()))
}
}
}
impl FormattedValueIntrinsic for Percent {}
impl SpecificFormattedValue for Option<Percent> {}
impl SpecificFormattedValueFullRange for Option<Percent> {}
impl SpecificFormattedValueIntrinsic for Percent {}
impl FormattedValueNoneBuilder for Option<Percent> {
fn none() -> Option<Percent> {
None
}
}
impl std::ops::Deref for Percent {
type Target = u32;
fn deref(&self) -> &u32 {
&self.0
}
}
impl std::ops::DerefMut for Percent {
fn deref_mut(&mut self) -> &mut u32 {
&mut self.0
}
}
impl AsRef<u32> for Percent {
fn as_ref(&self) -> &u32 {
&self.0
}
}
impl AsMut<u32> for Percent {
fn as_mut(&mut self) -> &mut u32 {
&mut self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::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(
(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(
(v * ffi::GST_FORMAT_PERCENT_SCALE as f32).round() as u32
))
}
}
}

View file

@ -0,0 +1,111 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::TryFromGlib;
use std::ops::{Deref, DerefMut};
use super::{FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic};
use super::{FormattedValueError, GenericFormattedValue, Signed};
use crate::Format;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
pub struct Undefined(pub i64);
impl FormattedValue for Undefined {
type FullRange = Undefined;
fn default_format() -> Format {
Format::Undefined
}
fn format(&self) -> Format {
Format::Undefined
}
fn is_some(&self) -> bool {
true
}
unsafe fn into_raw_value(self) -> i64 {
self.0
}
}
impl FormattedValueFullRange for Undefined {
unsafe fn from_raw(format: Format, value: i64) -> Self {
debug_assert_eq!(format, Format::Undefined);
Undefined(value)
}
}
impl From<Undefined> for GenericFormattedValue {
fn from(v: Undefined) -> Self {
skip_assert_initialized!();
GenericFormattedValue::Undefined(v)
}
}
impl TryFrom<GenericFormattedValue> for Undefined {
type Error = FormattedValueError;
fn try_from(v: GenericFormattedValue) -> Result<Undefined, Self::Error> {
skip_assert_initialized!();
if let GenericFormattedValue::Undefined(v) = v {
Ok(v)
} else {
Err(FormattedValueError(v.format()))
}
}
}
impl FormattedValueIntrinsic for Undefined {}
impl TryFromGlib<i64> for Undefined {
type Error = std::convert::Infallible;
#[inline]
unsafe fn try_from_glib(v: i64) -> Result<Self, Self::Error> {
skip_assert_initialized!();
Ok(Undefined(v))
}
}
impl From<i64> for Undefined {
fn from(v: i64) -> Self {
skip_assert_initialized!();
Undefined(v)
}
}
impl Deref for Undefined {
type Target = i64;
fn deref(&self) -> &i64 {
&self.0
}
}
impl 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 From<Undefined> for Signed<u64> {
fn from(val: Undefined) -> Signed<u64> {
skip_assert_initialized!();
val.0.into()
}
}
glib_newtype_display!(Undefined, DisplayableUndefined, "(Undefined)");