From deb22b264eaff38cbdb0f81171ff821521bf2817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= Date: Tue, 5 Oct 2021 19:41:11 +0200 Subject: [PATCH] format, clock_time: gather macros together The modules format and clock_time share common macros which are scattered between each modules. This cross reference makes it difficult to maintain the macros. This commit also make it possible to use macro impl_common_ops_for_newtype_uint for Percent. --- gstreamer/src/clock_time.rs | 201 +---------------- gstreamer/src/format.rs | 241 +-------------------- gstreamer/src/lib.rs | 4 +- gstreamer/src/macros.rs | 416 ++++++++++++++++++++++++++++++++++++ 4 files changed, 437 insertions(+), 425 deletions(-) create mode 100644 gstreamer/src/macros.rs diff --git a/gstreamer/src/clock_time.rs b/gstreamer/src/clock_time.rs index f354e63f1..f862b7ed1 100644 --- a/gstreamer/src/clock_time.rs +++ b/gstreamer/src/clock_time.rs @@ -2,10 +2,13 @@ use glib::translate::*; use glib::StaticType; +use muldiv::MulDiv; use num_integer::div_rem; use opt_ops::prelude::*; +use std::borrow::Borrow; use std::convert::{From, TryFrom}; use std::io::{self, prelude::*}; +use std::ops; use std::time::Duration; use std::{cmp, fmt, str}; @@ -64,38 +67,6 @@ impl ClockTime { } } -macro_rules! option_glib_newtype_from_to { - ($type_:ident, $none_value:expr) => { - #[doc(hidden)] - impl IntoGlib for $type_ { - type GlibType = u64; - - fn into_glib(self) -> u64 { - self.0 - } - } - - #[doc(hidden)] - impl OptionIntoGlib for $type_ { - const GLIB_NONE: u64 = $none_value; - } - - #[doc(hidden)] - impl TryFromGlib for $type_ { - type Error = GlibNoneError; - #[inline] - unsafe fn try_from_glib(val: u64) -> Result { - skip_assert_initialized!(); - if val == $none_value { - return Err(GlibNoneError); - } - - Ok($type_(val)) - } - } - }; -} - option_glib_newtype_from_to!(ClockTime, ffi::GST_CLOCK_TIME_NONE); impl glib::value::ValueType for ClockTime { @@ -204,176 +175,22 @@ impl From for Duration { } } -macro_rules! impl_common_ops_for_newtype_u64( - ($name:ident) => { - impl $name { - pub const ZERO: Self = Self(0); - pub const NONE: Option = None; - - pub const fn is_zero(self) -> bool { - self.0 == Self::ZERO.0 - } - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - pub const fn checked_add(self, rhs: Self) -> Option { - match self.0.checked_add(rhs.0) { - Some(res) if res <= Self::MAX.0 => Some(Self(res)), - _ => None, - } - } - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - let res = self.0.saturating_add(rhs.0); - if res < Self::MAX.0 { - Self(res) - } else { - Self::MAX - } - } - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let self_u128 = self.0 as u128; - let rhs_128 = rhs.0 as u128; - let res_u128 = self_u128 + rhs_128; - if res_u128 <= Self::MAX.0 as u128 { - (TryFrom::try_from(res_u128 as u64).unwrap(), false) - } else { - (TryFrom::try_from((res_u128 - Self::MAX.0 as u128 - 1) as u64).unwrap(), true) - } - } - - // FIXME add overflowing_add - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - pub fn wrapping_add(self, rhs: Self) -> Self { - self.overflowing_add(rhs).0 - } - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - // FIXME Can't use `map` in a `const fn` as of rustc 1.53.0-beta.2 - #[allow(clippy::manual_map)] - pub const fn checked_sub(self, rhs: Self) -> Option { - match self.0.checked_sub(rhs.0) { - Some(res) => Some(Self(res)), - None => None, - } - } - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - Self(self.0.saturating_sub(rhs.0)) - } - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - if self.0 >= rhs.0 { - (Self(self.0 - rhs.0), false) - } else { - (Self(Self::MAX.0 - rhs.0 + self.0 + 1), true) - } - } - - #[must_use = "this returns the result of the operation, without modifying the original"] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - self.overflowing_sub(rhs).0 - } - } - - impl OptionOperations for $name {} - - impl OptionCheckedAdd for $name { - type Output = Self; - - fn opt_checked_add( - self, - rhs: Self, - ) -> Result, opt_ops::CheckedError> { - self.checked_add(rhs) - .ok_or(opt_ops::CheckedError::Overflow) - .map(Some) - } - } - - impl OptionSaturatingAdd for $name { - type Output = Self; - fn opt_saturating_add(self, rhs: Self) -> Option { - Some(self.saturating_add(rhs)) - } - } - - impl OptionOverflowingAdd for $name { - type Output = Self; - fn opt_overflowing_add(self, rhs: Self) -> Option<(Self::Output, bool)> { - let res = self.overflowing_add(rhs); - Some((res.0, res.1)) - } - } - - impl OptionWrappingAdd for $name { - type Output = Self; - fn opt_wrapping_add(self, rhs: Self) -> Option { - Some(self.wrapping_add(rhs)) - } - } - - impl OptionCheckedSub for $name { - type Output = Self; - fn opt_checked_sub( - self, - rhs: Self, - ) -> Result, opt_ops::CheckedError> { - self.checked_sub(rhs) - .ok_or(opt_ops::CheckedError::Overflow) - .map(Some) - } - } - - impl OptionSaturatingSub for $name { - type Output = Self; - fn opt_saturating_sub(self, rhs: Self) -> Option { - Some(self.saturating_sub(rhs)) - } - } - - impl OptionOverflowingSub for $name { - type Output = Self; - fn opt_overflowing_sub(self, rhs: Self) -> Option<(Self::Output, bool)> { - let res = self.overflowing_sub(rhs); - Some((res.0, res.1)) - } - } - - impl OptionWrappingSub for $name { - type Output = Self; - fn opt_wrapping_sub(self, rhs: Self) -> Option { - Some(self.wrapping_sub(rhs)) - } - } - }; -); - -impl_common_ops_for_newtype_u64!(ClockTime); +impl_common_ops_for_newtype_uint!(ClockTime, u64); +// rustdoc-stripper-ignore-next /// Tell [`pad_clocktime`] what kind of time we're formatting enum Sign { + // rustdoc-stripper-ignore-next /// An undefined time (`None`) Undefined, + // rustdoc-stripper-ignore-next /// A non-negative time (zero or greater) NonNegative, // For a future ClockTimeDiff formatting #[allow(dead_code)] + // rustdoc-stripper-ignore-next /// A negative time (below zero) Negative, } @@ -383,6 +200,7 @@ enum Sign { // TODO: Would be useful for formatting ClockTimeDiff // if it was a new type instead of an alias for i64 // +// rustdoc-stripper-ignore-next /// Performs the correct padding for a clock time which has already been /// emitted into a str, as by [`write_clocktime`]. The str should *not* /// contain the sign; that will be added by this method. @@ -449,6 +267,7 @@ fn pad_clocktime(f: &mut fmt::Formatter<'_>, sign: Sign, buf: &str) -> fmt::Resu Ok(()) } +// rustdoc-stripper-ignore-next /// Writes an unpadded, signless clocktime string with the given precision fn write_clocktime( mut writer: W, diff --git a/gstreamer/src/format.rs b/gstreamer/src/format.rs index c264ca88a..59e357379 100644 --- a/gstreamer/src/format.rs +++ b/gstreamer/src/format.rs @@ -172,245 +172,20 @@ impl FormattedValueIntrinsic for GenericFormattedValue { type FormattedValueType = GenericFormattedValue; } -macro_rules! impl_op_same( - ($name:ident, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { - impl> ops::$op for $name { - type Output = Self; - - fn $op_name(self, rhs: RHS) -> Self::Output { - Self(self.0.$op_name(rhs.borrow().0)) - } - } - - impl> ops::$op for &$name { - type Output = $name; - - fn $op_name(self, rhs: RHS) -> Self::Output { - (*self).$op_name(rhs) - } - } - - impl> ops::$op_assign for $name { - fn $op_assign_name(&mut self, rhs: RHS) { - self.0.$op_assign_name(rhs.borrow().0) - } - } - }; -); - -macro_rules! impl_op_u64( - ($name:ident, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { - impl ops::$op for $name { - type Output = $name; - - fn $op_name(self, rhs: u64) -> Self::Output { - $name(self.0.$op_name(rhs)) - } - } - - impl ops::$op for &$name { - type Output = $name; - - fn $op_name(self, rhs: u64) -> Self::Output { - (*self).$op_name(rhs) - } - } - - impl ops::$op<$name> for u64 { - type Output = $name; - - fn $op_name(self, rhs: $name) -> $name { - $name(self.$op_name(rhs.0)) - } - } - - impl ops::$op<&$name> for u64 { - type Output = $name; - - fn $op_name(self, rhs: &$name) -> $name { - self.$op_name(*rhs) - } - } - - impl ops::$op_assign for $name { - fn $op_assign_name(&mut self, rhs: u64) { - self.0.$op_assign_name(rhs) - } - } - }; -); - -macro_rules! impl_format_value_traits( - ($name:ident, $format:ident, $format_value:ident) => { - impl FormattedValue for Option<$name> { - fn default_format() -> Format { - Format::$format - } - - fn format(&self) -> Format { - Format::$format - } - - unsafe fn from_raw(format: Format, value: i64) -> Option<$name> { - debug_assert_eq!(format, Format::$format); - FromGlib::from_glib(value as u64) - } - - unsafe fn into_raw_value(self) -> i64 { - IntoGlib::into_glib(self) as i64 - } - } - - impl From> for GenericFormattedValue { - fn from(v: Option<$name>) -> Self { - skip_assert_initialized!(); - Self::$format_value(v) - } - } - - impl From<$name> for GenericFormattedValue { - fn from(v: $name) -> Self { - skip_assert_initialized!(); - Self::$format_value(Some(v)) - } - } - - impl FormattedValueIntrinsic for $name { - type FormattedValueType = Option<$name>; - } - - impl TryFrom for Option<$name> { - type Error = TryFromGenericFormattedValueError; - - fn try_from(v: GenericFormattedValue) -> Result, Self::Error> { - skip_assert_initialized!(); - if let GenericFormattedValue::$format_value(v) = v { - Ok(v) - } else { - Err(TryFromGenericFormattedValueError(())) - } - } - } - - impl TryFrom for $name { - type Error = GlibNoneError; - - fn try_from(v: u64) -> Result<$name, GlibNoneError> { - skip_assert_initialized!(); - unsafe { Self::try_from_glib(v) } - } - } - - impl TryFromGlib for $name { - type Error = GlibNoneError; - #[inline] - unsafe fn try_from_glib(val: i64) -> Result { - skip_assert_initialized!(); - <$name as TryFromGlib>::try_from_glib(val as u64) - } - } - - impl SpecificFormattedValue for Option<$name> {} - impl SpecificFormattedValueIntrinsic for $name {} - - impl ops::Deref for $name { - type Target = u64; - - fn deref(&self) -> &u64 { - &self.0 - } - } - - impl ops::DerefMut for $name { - fn deref_mut(&mut self) -> &mut u64 { - &mut self.0 - } - } - - impl AsRef for $name { - fn as_ref(&self) -> &u64 { - &self.0 - } - } - - impl AsMut for $name { - fn as_mut(&mut self) -> &mut u64 { - &mut self.0 - } - } - - impl_op_same!($name, Add, add, AddAssign, add_assign); - impl_op_same!($name, Sub, sub, SubAssign, sub_assign); - impl_op_same!($name, Mul, mul, MulAssign, mul_assign); - impl_op_same!($name, Div, div, DivAssign, div_assign); - impl_op_same!($name, Rem, rem, RemAssign, rem_assign); - - impl_op_u64!($name, Mul, mul, MulAssign, mul_assign); - impl_op_u64!($name, Div, div, DivAssign, div_assign); - impl_op_u64!($name, Rem, rem, RemAssign, rem_assign); - - impl> MulDiv for $name { - type Output = $name; - - fn mul_div_floor(self, num: ND, denom: ND) -> Option { - self.0 - .mul_div_floor(*num.borrow(), *denom.borrow()) - .map($name) - } - - fn mul_div_round(self, num: ND, denom: ND) -> Option { - self.0 - .mul_div_round(*num.borrow(), *denom.borrow()) - .map($name) - } - - fn mul_div_ceil(self, num: ND, denom: ND) -> Option { - self.0 - .mul_div_ceil(*num.borrow(), *denom.borrow()) - .map($name) - } - } - }; -); - -macro_rules! option_glib_newtype_display { - ($name:ident, $unit:expr) => { - impl crate::utils::Displayable for Option<$name> { - type DisplayImpl = String; - - fn display(self) -> String { - if let Some(val) = self { - val.display() - } else { - format!("undef. {}", $unit) - } - } - } - - impl crate::utils::Displayable for $name { - type DisplayImpl = String; - - fn display(self) -> String { - format!("{} {}", self.0, $unit) - } - } - }; -} - -impl_common_ops_for_newtype_u64!(Default); -impl_format_value_traits!(Default, Default, Default); +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_u64!(Bytes); -impl_format_value_traits!(Bytes, Bytes, Bytes); +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); +impl_format_value_traits!(ClockTime, Time, Time, u64); -impl_common_ops_for_newtype_u64!(Buffers); -impl_format_value_traits!(Buffers, Buffers, Buffers); +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"); @@ -517,7 +292,7 @@ impl crate::utils::Displayable for Undefined { } } -impl_common_ops_for_newtype_u64!(Percent); +impl_common_ops_for_newtype_uint!(Percent, u32); option_glib_newtype_display!(Percent, "%"); impl FormattedValue for Option { diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 88cd17054..e2035c33d 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -35,6 +35,9 @@ mod auto; pub use crate::auto::functions::*; pub use crate::auto::*; +#[macro_use] +mod macros; + #[macro_use] mod log; pub use crate::log::*; @@ -152,7 +155,6 @@ mod bus_unix; mod bus_windows; mod child_proxy; -#[macro_use] mod clock_time; #[cfg(feature = "ser_de")] mod clock_time_serde; diff --git a/gstreamer/src/macros.rs b/gstreamer/src/macros.rs new file mode 100644 index 000000000..f6cb79a2b --- /dev/null +++ b/gstreamer/src/macros.rs @@ -0,0 +1,416 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +macro_rules! impl_op_same( + ($name:ident, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { + impl> ops::$op for $name { + type Output = Self; + + fn $op_name(self, rhs: RHS) -> Self::Output { + Self(self.0.$op_name(rhs.borrow().0)) + } + } + + impl> ops::$op for &$name { + type Output = $name; + + fn $op_name(self, rhs: RHS) -> Self::Output { + (*self).$op_name(rhs) + } + } + + impl> ops::$op_assign for $name { + fn $op_assign_name(&mut self, rhs: RHS) { + self.0.$op_assign_name(rhs.borrow().0) + } + } + }; +); + +macro_rules! impl_op_inner_type( + ($name:ident, $inner_type:ty, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { + impl ops::$op<$inner_type> for $name { + type Output = $name; + + fn $op_name(self, rhs: $inner_type) -> Self::Output { + $name(self.0.$op_name(rhs)) + } + } + + impl ops::$op<$inner_type> for &$name { + type Output = $name; + + fn $op_name(self, rhs: $inner_type) -> Self::Output { + (*self).$op_name(rhs) + } + } + + impl ops::$op<$name> for $inner_type { + type Output = $name; + + fn $op_name(self, rhs: $name) -> $name { + $name(self.$op_name(rhs.0)) + } + } + + impl ops::$op<&$name> for $inner_type { + type Output = $name; + + fn $op_name(self, rhs: &$name) -> $name { + self.$op_name(*rhs) + } + } + + impl ops::$op_assign<$inner_type> for $name { + fn $op_assign_name(&mut self, rhs: $inner_type) { + self.0.$op_assign_name(rhs) + } + } + }; +); + +macro_rules! impl_common_ops_for_newtype_uint( + ($name:ident, $inner_type:ty) => { + impl $name { + pub const ZERO: Self = Self(0); + pub const NONE: Option = None; + + pub const fn is_zero(self) -> bool { + self.0 == Self::ZERO.0 + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_add(self, rhs: Self) -> Option { + match self.0.checked_add(rhs.0) { + Some(res) if res <= Self::MAX.0 => Some(Self(res)), + _ => None, + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + let res = self.0.saturating_add(rhs.0); + if res < Self::MAX.0 { + Self(res) + } else { + Self::MAX + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let self_u128 = self.0 as u128; + let rhs_128 = rhs.0 as u128; + let res_u128 = self_u128 + rhs_128; + if res_u128 <= Self::MAX.0 as u128 { + (Self(<$inner_type>::try_from(res_u128).unwrap()), false) + } else { + (Self(<$inner_type>::try_from((res_u128 - Self::MAX.0 as u128 - 1) as u64).unwrap()), true) + } + } + + // FIXME add overflowing_add + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub fn wrapping_add(self, rhs: Self) -> Self { + self.overflowing_add(rhs).0 + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + // FIXME Can't use `map` in a `const fn` as of rustc 1.53.0-beta.2 + #[allow(clippy::manual_map)] + pub const fn checked_sub(self, rhs: Self) -> Option { + match self.0.checked_sub(rhs.0) { + Some(res) => Some(Self(res)), + None => None, + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + Self(self.0.saturating_sub(rhs.0)) + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + if self.0 >= rhs.0 { + (Self(self.0 - rhs.0), false) + } else { + (Self(Self::MAX.0 - rhs.0 + self.0 + 1), true) + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + self.overflowing_sub(rhs).0 + } + } + + impl_op_same!($name, Add, add, AddAssign, add_assign); + impl_op_same!($name, Sub, sub, SubAssign, sub_assign); + impl_op_same!($name, Mul, mul, MulAssign, mul_assign); + impl_op_same!($name, Div, div, DivAssign, div_assign); + impl_op_same!($name, Rem, rem, RemAssign, rem_assign); + + impl_op_inner_type!($name, $inner_type, Mul, mul, MulAssign, mul_assign); + impl_op_inner_type!($name, $inner_type, Div, div, DivAssign, div_assign); + impl_op_inner_type!($name, $inner_type, Rem, rem, RemAssign, rem_assign); + + impl> MulDiv for $name { + type Output = $name; + + fn mul_div_floor(self, num: ND, denom: ND) -> Option { + self.0 + .mul_div_floor(*num.borrow(), *denom.borrow()) + .map($name) + } + + fn mul_div_round(self, num: ND, denom: ND) -> Option { + self.0 + .mul_div_round(*num.borrow(), *denom.borrow()) + .map($name) + } + + fn mul_div_ceil(self, num: ND, denom: ND) -> Option { + self.0 + .mul_div_ceil(*num.borrow(), *denom.borrow()) + .map($name) + } + } + + impl OptionOperations for $name {} + + impl OptionCheckedAdd for $name { + type Output = Self; + + fn opt_checked_add( + self, + rhs: Self, + ) -> Result, opt_ops::CheckedError> { + self.checked_add(rhs) + .ok_or(opt_ops::CheckedError::Overflow) + .map(Some) + } + } + + impl OptionSaturatingAdd for $name { + type Output = Self; + fn opt_saturating_add(self, rhs: Self) -> Option { + Some(self.saturating_add(rhs)) + } + } + + impl OptionOverflowingAdd for $name { + type Output = Self; + fn opt_overflowing_add(self, rhs: Self) -> Option<(Self::Output, bool)> { + let res = self.overflowing_add(rhs); + Some((res.0, res.1)) + } + } + + impl OptionWrappingAdd for $name { + type Output = Self; + fn opt_wrapping_add(self, rhs: Self) -> Option { + Some(self.wrapping_add(rhs)) + } + } + + impl OptionCheckedSub for $name { + type Output = Self; + fn opt_checked_sub( + self, + rhs: Self, + ) -> Result, opt_ops::CheckedError> { + self.checked_sub(rhs) + .ok_or(opt_ops::CheckedError::Overflow) + .map(Some) + } + } + + impl OptionSaturatingSub for $name { + type Output = Self; + fn opt_saturating_sub(self, rhs: Self) -> Option { + Some(self.saturating_sub(rhs)) + } + } + + impl OptionOverflowingSub for $name { + type Output = Self; + fn opt_overflowing_sub(self, rhs: Self) -> Option<(Self::Output, bool)> { + let res = self.overflowing_sub(rhs); + Some((res.0, res.1)) + } + } + + impl OptionWrappingSub for $name { + type Output = Self; + fn opt_wrapping_sub(self, rhs: Self) -> Option { + Some(self.wrapping_sub(rhs)) + } + } + }; +); + +macro_rules! impl_format_value_traits( + ($name:ident, $format:ident, $format_value:ident, $inner_type:ty) => { + impl FormattedValue for Option<$name> { + fn default_format() -> Format { + Format::$format + } + + fn format(&self) -> Format { + Format::$format + } + + unsafe fn from_raw(format: Format, value: i64) -> Option<$name> { + debug_assert_eq!(format, Format::$format); + FromGlib::from_glib(value as u64) + } + + unsafe fn into_raw_value(self) -> i64 { + IntoGlib::into_glib(self) as i64 + } + } + + impl From> for GenericFormattedValue { + fn from(v: Option<$name>) -> Self { + skip_assert_initialized!(); + Self::$format_value(v) + } + } + + impl From<$name> for GenericFormattedValue { + fn from(v: $name) -> Self { + skip_assert_initialized!(); + Self::$format_value(Some(v)) + } + } + + impl FormattedValueIntrinsic for $name { + type FormattedValueType = Option<$name>; + } + + impl TryFrom for Option<$name> { + type Error = TryFromGenericFormattedValueError; + + fn try_from(v: GenericFormattedValue) -> Result, Self::Error> { + skip_assert_initialized!(); + if let GenericFormattedValue::$format_value(v) = v { + Ok(v) + } else { + Err(TryFromGenericFormattedValueError(())) + } + } + } + + impl TryFrom<$inner_type> for $name { + type Error = GlibNoneError; + + fn try_from(v: $inner_type) -> Result<$name, GlibNoneError> { + skip_assert_initialized!(); + unsafe { Self::try_from_glib(v as i64) } + } + } + + impl TryFromGlib for $name { + type Error = GlibNoneError; + #[inline] + unsafe fn try_from_glib(val: i64) -> Result { + skip_assert_initialized!(); + <$name as TryFromGlib>::try_from_glib(val as u64) + } + } + + impl SpecificFormattedValue for Option<$name> {} + impl SpecificFormattedValueIntrinsic for $name {} + + impl ops::Deref for $name { + type Target = $inner_type; + + fn deref(&self) -> &$inner_type { + &self.0 + } + } + + impl ops::DerefMut for $name { + fn deref_mut(&mut self) -> &mut $inner_type { + &mut self.0 + } + } + + impl AsRef<$inner_type> for $name { + fn as_ref(&self) -> &$inner_type { + &self.0 + } + } + + impl AsMut<$inner_type> for $name { + fn as_mut(&mut self) -> &mut $inner_type { + &mut self.0 + } + } + }; +); + +macro_rules! option_glib_newtype_from_to { + ($type_:ident, $none_value:expr) => { + #[doc(hidden)] + impl IntoGlib for $type_ { + type GlibType = u64; + + fn into_glib(self) -> u64 { + self.0 + } + } + + #[doc(hidden)] + impl OptionIntoGlib for $type_ { + const GLIB_NONE: u64 = $none_value; + } + + #[doc(hidden)] + impl TryFromGlib for $type_ { + type Error = GlibNoneError; + #[inline] + unsafe fn try_from_glib(val: u64) -> Result { + skip_assert_initialized!(); + if val == $none_value { + return Err(GlibNoneError); + } + + Ok($type_(val)) + } + } + }; +} + +macro_rules! option_glib_newtype_display { + ($name:ident, $unit:expr) => { + impl crate::utils::Displayable for Option<$name> { + type DisplayImpl = String; + + fn display(self) -> String { + if let Some(val) = self { + val.display() + } else { + format!("undef. {}", $unit) + } + } + } + + impl crate::utils::Displayable for $name { + type DisplayImpl = String; + + fn display(self) -> String { + format!("{} {}", self.0, $unit) + } + } + }; +}