format/Other: use u64 internally instead of i64

This commit is contained in:
François Laignel 2022-10-09 16:05:35 +02:00
parent 8a7813d04c
commit 04b6710f84
7 changed files with 293 additions and 144 deletions

View file

@ -3,31 +3,45 @@
use serde::de::{Deserialize, Deserializer}; use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
use crate::format::{Buffers, Bytes, Default, Percent, Undefined}; use crate::format::{Buffers, Bytes, Default, Other, Percent, Undefined};
// FIXME: the ser/de impl assumed `GenericFormattedValue` was always used.
// When serializing a `SpecificFormattedValue`, we loose the type and only
// serialize the inner value in parenthesis.
// Manual implementation for some types that would otherwise yield representations such as: // Manual implementation for some types that would otherwise yield representations such as:
// "Default((Some(42)))" // "Default(Some((42)))"
macro_rules! impl_serde( macro_rules! impl_serde(
($t:ident) => { ($t:ident, $inner:ty) => {
impl Serialize for $t { impl Serialize for $t {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer) use std::ops::Deref;
self.deref().serialize(serializer)
} }
} }
impl<'de> Deserialize<'de> for $t { impl<'de> Deserialize<'de> for $t {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
skip_assert_initialized!(); skip_assert_initialized!();
u64::deserialize(deserializer).map($t) <$inner>::deserialize(deserializer)
.and_then(|value| {
$t::try_from(value).map_err(|_| {
use serde::de::{Error, Unexpected};
D::Error::invalid_value(
Unexpected::Unsigned(value.into()),
&concat!("valid ", stringify!($t)),
)
})
})
} }
} }
} }
); );
impl_serde!(Buffers); impl_serde!(Buffers, u64);
impl_serde!(Bytes); impl_serde!(Bytes, u64);
impl_serde!(Default); impl_serde!(Default, u64);
impl_serde!(Other, u64);
impl_serde!(Percent, u32);
impl Serialize for Undefined { impl Serialize for Undefined {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
@ -42,22 +56,9 @@ impl<'de> Deserialize<'de> for Undefined {
} }
} }
impl Serialize for Percent {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Percent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
skip_assert_initialized!();
u32::deserialize(deserializer).map(Percent)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::format::{Buffers, Bytes, Default, Percent, Undefined}; use crate::format::{Buffers, Bytes, Default, Other, Percent, Undefined};
use crate::ClockTime; use crate::ClockTime;
use crate::Format; use crate::Format;
use crate::GenericFormattedValue; use crate::GenericFormattedValue;
@ -110,15 +111,15 @@ mod tests {
let res = serde_json::to_string(&value).unwrap(); let res = serde_json::to_string(&value).unwrap();
assert_eq!("{\"Percent\":4200}".to_owned(), res); assert_eq!("{\"Percent\":4200}".to_owned(), res);
let value = GenericFormattedValue::Other(Format::Percent, 42); let value = GenericFormattedValue::Other(Format::Percent, Other::try_from(42).ok());
let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); let res = ron::ser::to_string_pretty(&value, pretty_config.clone());
assert_eq!(Ok("Other(Percent, 42)".to_owned()), res); assert_eq!(Ok("Other(Percent, Some(42))".to_owned()), res);
let res = serde_json::to_string(&value).unwrap(); let res = serde_json::to_string(&value).unwrap();
assert_eq!("{\"Other\":[\"Percent\",42]}".to_owned(), res); assert_eq!("{\"Other\":[\"Percent\",42]}".to_owned(), res);
let value = GenericFormattedValue::Other(Format::__Unknown(7), 42); let value = GenericFormattedValue::new(Format::__Unknown(7), 42);
let res = ron::ser::to_string_pretty(&value, pretty_config); let res = ron::ser::to_string_pretty(&value, pretty_config);
assert_eq!(Ok("Other(__Unknown(7), 42)".to_owned()), res); assert_eq!(Ok("Other(__Unknown(7), Some(42))".to_owned()), res);
let res = serde_json::to_string(&value).unwrap(); let res = serde_json::to_string(&value).unwrap();
assert_eq!("{\"Other\":[{\"__Unknown\":7},42]}".to_owned(), res); assert_eq!("{\"Other\":[{\"__Unknown\":7},42]}".to_owned(), res);
} }
@ -135,13 +136,15 @@ mod tests {
let value_de: GenericFormattedValue = serde_json::from_str(value_json).unwrap(); let value_de: GenericFormattedValue = serde_json::from_str(value_json).unwrap();
assert_eq!(value_de, GenericFormattedValue::from(Default(42))); assert_eq!(value_de, GenericFormattedValue::from(Default(42)));
let value_ron = "Other(Percent, 42)"; let value_ron = "Other(Percent, Some(42))";
let gfv_value = GenericFormattedValue::Other(Format::Percent, Other::try_from(42).ok());
let value_de: GenericFormattedValue = ron::de::from_str(value_ron).unwrap(); let value_de: GenericFormattedValue = ron::de::from_str(value_ron).unwrap();
assert_eq!(value_de, GenericFormattedValue::Other(Format::Percent, 42)); assert_eq!(value_de, gfv_value);
let value_json = "{\"Other\":[\"Percent\",42]}"; let value_json = "{\"Other\":[\"Percent\",42]}";
let value_de: GenericFormattedValue = serde_json::from_str(value_json).unwrap(); let value_de: GenericFormattedValue = serde_json::from_str(value_json).unwrap();
assert_eq!(value_de, GenericFormattedValue::Other(Format::Percent, 42)); assert_eq!(value_de, gfv_value);
} }
#[test] #[test]
@ -166,7 +169,8 @@ mod tests {
test_roundrip!(GenericFormattedValue::from( test_roundrip!(GenericFormattedValue::from(
Percent::try_from(0.42).unwrap() Percent::try_from(0.42).unwrap()
)); ));
test_roundrip!(GenericFormattedValue::Other(Format::Percent, 42)); let gfv_value = GenericFormattedValue::Other(Format::Percent, Other::try_from(42).ok());
test_roundrip!(GenericFormattedValue::Other(Format::__Unknown(7), 42)); test_roundrip!(gfv_value);
test_roundrip!(GenericFormattedValue::new(Format::__Unknown(7), 42));
} }
} }

View file

@ -1,6 +1,6 @@
// Take a look at the license at the top of the repository in the LICENSE file. // Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::FromGlib; use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib};
use std::fmt; use std::fmt;
use crate::utils::Displayable; use crate::utils::Displayable;
@ -10,9 +10,37 @@ use super::{
}; };
use super::{ use super::{
CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic,
FormattedValueNoneBuilder, UnsignedIntoSigned, FormattedValueNoneBuilder, SignedIntrinsic, UnsignedIntoSigned,
}; };
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
pub struct Other(u64);
impl Other {
pub const MAX: Self = Self(u64::MAX - 1);
}
impl_common_ops_for_newtype_uint!(Other, u64);
impl_signed_div_mul!(Other, u64);
option_glib_newtype_from_to!(Other, u64::MAX);
glib_newtype_display!(Other, DisplayableOther, DisplayableOptionOther);
impl TryFrom<u64> for Other {
type Error = GlibNoneError;
fn try_from(val: u64) -> Result<Self, GlibNoneError> {
skip_assert_initialized!();
unsafe { Self::try_from_glib(val) }
}
}
impl TryFromGlib<i64> for Other {
type Error = GlibNoneError;
#[inline]
unsafe fn try_from_glib(val: i64) -> Result<Self, GlibNoneError> {
skip_assert_initialized!();
Self::try_from_glib(val as u64)
}
}
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GenericFormattedValue { pub enum GenericFormattedValue {
@ -22,7 +50,7 @@ pub enum GenericFormattedValue {
Time(Option<ClockTime>), Time(Option<ClockTime>),
Buffers(Option<Buffers>), Buffers(Option<Buffers>),
Percent(Option<Percent>), Percent(Option<Percent>),
Other(Format, i64), Other(Format, Option<Other>),
} }
impl fmt::Display for GenericFormattedValue { impl fmt::Display for GenericFormattedValue {
@ -34,24 +62,33 @@ impl fmt::Display for GenericFormattedValue {
Self::Time(val) => val.display().fmt(f), Self::Time(val) => val.display().fmt(f),
Self::Buffers(val) => val.display().fmt(f), Self::Buffers(val) => val.display().fmt(f),
Self::Percent(val) => val.display().fmt(f), Self::Percent(val) => val.display().fmt(f),
Self::Other(format, val) => write!(f, "{} ({:?})", val, format), Self::Other(format, val) => {
val.display().fmt(f)?;
fmt::Write::write_char(f, ' ')?;
fmt::Display::fmt(&format, f)
} }
} }
} }
}
impl Displayable for GenericFormattedValue {
type DisplayImpl = GenericFormattedValue;
fn display(self) -> Self {
self
}
}
impl GenericFormattedValue { impl GenericFormattedValue {
pub fn new(format: Format, value: i64) -> Self { pub fn new(format: Format, value: i64) -> Self {
skip_assert_initialized!(); skip_assert_initialized!();
match format { match format {
Format::Undefined => Self::Undefined(Undefined(value)), Format::Undefined => Self::Undefined(Undefined(value)),
Format::Default => Self::Default(unsafe { FromGlib::from_glib(value as u64) }), Format::Default => Self::Default(unsafe { FromGlib::from_glib(value) }),
Format::Bytes => Self::Bytes(unsafe { FromGlib::from_glib(value as u64) }), Format::Bytes => Self::Bytes(unsafe { FromGlib::from_glib(value) }),
Format::Time => Self::Time(unsafe { FromGlib::from_glib(value as u64) }), Format::Time => Self::Time(unsafe { FromGlib::from_glib(value) }),
Format::Buffers => Self::Buffers(unsafe { FromGlib::from_glib(value as u64) }), Format::Buffers => Self::Buffers(unsafe { FromGlib::from_glib(value) }),
Format::Percent => { Format::Percent => Self::Percent(unsafe { FromGlib::from_glib(value) }),
Self::Percent(unsafe { FormattedValueFullRange::from_raw(format, value) }) Format::__Unknown(_) => Self::Other(format, unsafe { FromGlib::from_glib(value) }),
}
Format::__Unknown(_) => Self::Other(format, value),
} }
} }
@ -78,7 +115,7 @@ impl GenericFormattedValue {
Self::Time(v) => v.into_raw_value(), Self::Time(v) => v.into_raw_value(),
Self::Buffers(v) => v.into_raw_value(), Self::Buffers(v) => v.into_raw_value(),
Self::Percent(v) => v.into_raw_value(), Self::Percent(v) => v.into_raw_value(),
Self::Other(_, v) => v, Self::Other(_, v) => v.into_glib() as i64,
} }
} }
} }
@ -106,7 +143,7 @@ impl FormattedValue for GenericFormattedValue {
Self::Time(v) => v.is_some(), Self::Time(v) => v.is_some(),
Self::Buffers(v) => v.is_some(), Self::Buffers(v) => v.is_some(),
Self::Percent(v) => v.is_some(), Self::Percent(v) => v.is_some(),
Self::Other(..) => true, Self::Other(_, v) => v.is_some(),
} }
} }
@ -122,6 +159,7 @@ impl FormattedValueFullRange for GenericFormattedValue {
} }
impl FormattedValueIntrinsic for GenericFormattedValue {} impl FormattedValueIntrinsic for GenericFormattedValue {}
impl SignedIntrinsic for GenericFormattedValue {}
impl FormattedValueNoneBuilder for GenericFormattedValue { impl FormattedValueNoneBuilder for GenericFormattedValue {
#[track_caller] #[track_caller]
@ -142,7 +180,7 @@ impl FormattedValueNoneBuilder for GenericFormattedValue {
Format::Time => Self::Time(None), Format::Time => Self::Time(None),
Format::Buffers => Self::Buffers(None), Format::Buffers => Self::Buffers(None),
Format::Percent => Self::Percent(None), Format::Percent => Self::Percent(None),
Format::__Unknown(_) => panic!("`None` can't be represented by `__Unknown`"), unknown => Self::Other(unknown, Other::NONE),
} }
} }
} }
@ -151,27 +189,21 @@ impl UnsignedIntoSigned for GenericFormattedValue {
type Signed = Signed<GenericFormattedValue>; type Signed = Signed<GenericFormattedValue>;
#[track_caller] #[track_caller]
fn into_positive(self) -> Signed<GenericFormattedValue> { fn into_positive(self) -> Self::Signed {
match self { match self {
GenericFormattedValue::Undefined(_) => { GenericFormattedValue::Undefined(_) => {
unimplemented!("`GenericFormattedValue::Undefined` is already signed") unimplemented!("`GenericFormattedValue::Undefined` is already signed")
} }
GenericFormattedValue::Other(..) => {
unimplemented!("`GenericFormattedValue::Other` is already signed")
}
unsigned_inner => Signed::Positive(unsigned_inner), unsigned_inner => Signed::Positive(unsigned_inner),
} }
} }
#[track_caller] #[track_caller]
fn into_negative(self) -> Signed<GenericFormattedValue> { fn into_negative(self) -> Self::Signed {
match self { match self {
GenericFormattedValue::Undefined(_) => { GenericFormattedValue::Undefined(_) => {
unimplemented!("`GenericFormattedValue::Undefined` is already signed") unimplemented!("`GenericFormattedValue::Undefined` is already signed")
} }
GenericFormattedValue::Other(..) => {
unimplemented!("`GenericFormattedValue::Other` is already signed")
}
unsigned_inner => Signed::Negative(unsigned_inner), unsigned_inner => Signed::Negative(unsigned_inner),
} }
} }
@ -200,3 +232,56 @@ impl CompatibleFormattedValue<GenericFormattedValue> for GenericFormattedValue {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[allow(clippy::eq_op, clippy::op_ref)]
fn other() {
// Check a few ops on `Other`, better converage for
// the macro ops impl ensured as part of the `clock_time` module.
use opt_ops::prelude::*;
let other_none: Option<Other> = Other::try_from(u64::MAX).ok();
assert!(other_none.is_none());
let other_10 = Other::try_from(10).unwrap();
let other_20 = Other::try_from(20).unwrap();
let other_30 = Other::try_from(30).unwrap();
assert_eq!(other_10 + other_20, other_30);
assert_eq!(other_30 - other_20, other_10);
assert!(other_10 < Other::MAX);
assert_eq!(Some(other_10).opt_add(other_20), Some(other_30));
}
#[test]
#[allow(clippy::eq_op, clippy::op_ref)]
fn generic_other() {
let gen_other_42: GenericFormattedValue =
GenericFormattedValue::new(Format::__Unknown(128), 42);
assert_eq!(
gen_other_42,
GenericFormattedValue::Other(Format::__Unknown(128), Some(Other(42)))
);
assert_eq!(gen_other_42.format(), Format::__Unknown(128));
assert_eq!(gen_other_42.value(), 42);
assert!(gen_other_42.is_some());
let other_none: Option<Other> = Other::NONE;
assert!(other_none.is_none());
let gen_other_none: GenericFormattedValue =
GenericFormattedValue::none_for_format(Format::__Unknown(128));
assert!(gen_other_none.is_none());
assert_eq!(
gen_other_none,
GenericFormattedValue::Other(Format::__Unknown(128), None)
);
}
}

View file

@ -183,6 +183,8 @@ macro_rules! impl_non_trait_op_inner_type(
macro_rules! impl_unsigned_int_into_signed( macro_rules! impl_unsigned_int_into_signed(
($typ:ty) => { ($typ:ty) => {
impl crate::format::SignedIntrinsic for $typ {}
impl crate::UnsignedIntoSigned for $typ { impl crate::UnsignedIntoSigned for $typ {
type Signed = crate::Signed<$typ>; type Signed = crate::Signed<$typ>;
@ -239,6 +241,20 @@ macro_rules! impl_common_ops_for_newtype_uint(
} }
} }
impl std::ops::Deref for $typ {
type Target = $inner;
fn deref(&self) -> &$inner {
&self.0
}
}
impl AsRef<$inner> for $typ {
fn as_ref(&self) -> &$inner {
&self.0
}
}
impl_trait_op_same!($typ, Add, add, AddAssign, add_assign); impl_trait_op_same!($typ, Add, add, AddAssign, add_assign);
impl_trait_op_same!($typ, Sub, sub, SubAssign, sub_assign); impl_trait_op_same!($typ, Sub, sub, SubAssign, sub_assign);
impl std::ops::Div for $typ { impl std::ops::Div for $typ {
@ -1467,7 +1483,7 @@ macro_rules! impl_format_value_traits(
impl TryFrom<$inner> for $typ { impl TryFrom<$inner> for $typ {
type Error = GlibNoneError; type Error = GlibNoneError;
fn try_from(v: $inner) -> Result<$typ, GlibNoneError> { fn try_from(v: $inner) -> Result<Self, GlibNoneError> {
skip_assert_initialized!(); skip_assert_initialized!();
unsafe { Self::try_from_glib(v as i64) } unsafe { Self::try_from_glib(v as i64) }
} }
@ -1481,32 +1497,6 @@ macro_rules! impl_format_value_traits(
<$typ as TryFromGlib<u64>>::try_from_glib(val as u64) <$typ as TryFromGlib<u64>>::try_from_glib(val as u64)
} }
} }
impl std::ops::Deref for $typ {
type Target = $inner;
fn deref(&self) -> &$inner {
&self.0
}
}
impl std::ops::DerefMut for $typ {
fn deref_mut(&mut self) -> &mut $inner {
&mut self.0
}
}
impl AsRef<$inner> for $typ {
fn as_ref(&self) -> &$inner {
&self.0
}
}
impl AsMut<$inner> for $typ {
fn as_mut(&mut self) -> &mut $inner {
&mut self.0
}
}
}; };
); );
@ -1545,16 +1535,12 @@ macro_rules! option_glib_newtype_from_to {
// `$displayable_option_name` if `concat_idents!` was stable. // `$displayable_option_name` if `concat_idents!` was stable.
// See: https://doc.rust-lang.org/std/macro.concat_idents.html // See: https://doc.rust-lang.org/std/macro.concat_idents.html
macro_rules! glib_newtype_display { macro_rules! glib_newtype_display {
($typ:ty, $displayable_name:ident, $unit:expr) => { ($typ:ty, $displayable_name:ident) => {
pub struct $displayable_name($typ); pub struct $displayable_name($typ);
impl std::fmt::Display for $typ { impl std::fmt::Display for $typ {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use std::fmt::Write; std::fmt::Display::fmt(&self.0, f)
std::fmt::Display::fmt(&self.0, f)?;
f.write_char(' ')?;
f.write_str($unit)
} }
} }
@ -1566,8 +1552,50 @@ macro_rules! glib_newtype_display {
} }
}; };
($typ:ty, $displayable_name:ident, $displayable_option_name:ident, $unit:expr) => { ($typ:ty, $displayable_name:ident, Format::$format:ident$(,)?) => {
glib_newtype_display!($typ, $displayable_name, $unit); pub struct $displayable_name($typ);
impl std::fmt::Display for $typ {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)?;
std::fmt::Write::write_char(f, ' ')?;
std::fmt::Display::fmt(&Format::$format, f)
}
}
impl crate::utils::Displayable for $typ {
type DisplayImpl = $typ;
fn display(self) -> $typ {
self
}
}
};
($typ:ty, $displayable_name:ident, $displayable_option_name:ident) => {
glib_newtype_display!($typ, $displayable_name);
pub struct $displayable_option_name(Option<$typ>);
impl std::fmt::Display for $displayable_option_name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if let Some(val) = self.0.as_ref() {
std::fmt::Display::fmt(val, f)
} else {
f.write_str("undef.")
}
}
}
impl crate::utils::Displayable for Option<$typ> {
type DisplayImpl = $displayable_option_name;
fn display(self) -> Self::DisplayImpl {
$displayable_option_name(self)
}
}
};
($typ:ty, $displayable_name:ident, $displayable_option_name:ident, Format::$format:ident$(,)?) => {
glib_newtype_display!($typ, $displayable_name, Format::$format);
pub struct $displayable_option_name(Option<$typ>); pub struct $displayable_option_name(Option<$typ>);
@ -1577,7 +1605,7 @@ macro_rules! glib_newtype_display {
std::fmt::Display::fmt(val, f) std::fmt::Display::fmt(val, f)
} else { } else {
f.write_str("undef. ")?; f.write_str("undef. ")?;
f.write_str($unit) std::fmt::Display::fmt(&Format::$format, f)
} }
} }
} }

View file

@ -522,6 +522,21 @@ pub trait FormattedValueNoneBuilder: FormattedValueFullRange {
} }
} }
use std::fmt;
impl fmt::Display for Format {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Undefined => f.write_str("undefined"),
Self::Default => f.write_str("default"),
Self::Bytes => f.write_str("bytes"),
Self::Time => f.write_str("time"),
Self::Buffers => f.write_str("buffers"),
Self::Percent => f.write_str("%"),
Self::__Unknown(format) => write!(f, "(format: {})", format),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -715,6 +730,7 @@ mod tests {
assert_eq!(signed.positive(), Some(ct_1)); assert_eq!(signed.positive(), Some(ct_1));
assert!(!signed.is_negative()); assert!(!signed.is_negative());
assert!(signed.negative().is_none()); assert!(signed.negative().is_none());
assert_eq!(signed.signum(), 1);
let signed = ct_1.into_negative(); let signed = ct_1.into_negative();
assert_eq!(signed, Signed::Negative(ct_1)); assert_eq!(signed, Signed::Negative(ct_1));
@ -722,6 +738,7 @@ mod tests {
assert_eq!(signed.negative(), Some(ct_1)); assert_eq!(signed.negative(), Some(ct_1));
assert!(!signed.is_positive()); assert!(!signed.is_positive());
assert!(signed.positive().is_none()); assert!(signed.positive().is_none());
assert_eq!(signed.signum(), -1);
let def = Default(1); let def = Default(1);
@ -731,6 +748,7 @@ mod tests {
assert_eq!(signed.positive(), Some(def)); assert_eq!(signed.positive(), Some(def));
assert!(!signed.is_negative()); assert!(!signed.is_negative());
assert!(signed.negative().is_none()); assert!(signed.negative().is_none());
assert_eq!(signed.signum(), 1);
let signed = def.into_negative(); let signed = def.into_negative();
assert_eq!(signed, Signed::Negative(def)); assert_eq!(signed, Signed::Negative(def));
@ -738,6 +756,17 @@ mod tests {
assert_eq!(signed.negative(), Some(def)); assert_eq!(signed.negative(), Some(def));
assert!(!signed.is_positive()); assert!(!signed.is_positive());
assert!(signed.positive().is_none()); assert!(signed.positive().is_none());
assert_eq!(signed.signum(), -1);
let ct_zero = ClockTime::ZERO;
let p_ct_zero = ct_zero.into_positive();
assert!(p_ct_zero.is_positive());
assert!(!p_ct_zero.is_negative());
assert_eq!(p_ct_zero.signum(), 0);
let n_ct_zero = ct_zero.into_negative();
assert!(n_ct_zero.is_negative());
assert!(!n_ct_zero.is_positive());
assert_eq!(n_ct_zero.signum(), 0);
} }
#[test] #[test]
@ -811,6 +840,20 @@ mod tests {
&format!("{}", GenericFormattedValue::Percent(None)), &format!("{}", GenericFormattedValue::Percent(None)),
"undef. %" "undef. %"
); );
let other: Other = 42.try_into().unwrap();
assert_eq!(&format!("{other}"), "42");
let g_other = GenericFormattedValue::new(Format::__Unknown(128), 42);
assert_eq!(&format!("{g_other}"), "42 (format: 128)");
assert_eq!(&format!("{}", g_other.display()), "42 (format: 128)");
let g_other_none = GenericFormattedValue::Other(Format::__Unknown(128), None);
assert_eq!(&format!("{g_other_none}"), "undef. (format: 128)");
assert_eq!(
&format!("{}", g_other_none.display()),
"undef. (format: 128)"
);
} }
#[test] #[test]
@ -842,5 +885,21 @@ mod tests {
let none_s_bytes = Option::<Signed<Bytes>>::None; let none_s_bytes = Option::<Signed<Bytes>>::None;
assert_eq!(&format!("{}", none_s_bytes.display()), "undef. bytes"); assert_eq!(&format!("{}", none_s_bytes.display()), "undef. bytes");
let ct_1 = 45_834_908_569_837 * ClockTime::NSECOND;
assert_eq!(&format!("{ct_1}"), "12:43:54.908569837");
assert_eq!(&format!("{}", ct_1.display()), "12:43:54.908569837");
let g_ct_1 = GenericFormattedValue::Time(Some(ct_1));
assert_eq!(&format!("{g_ct_1}"), "12:43:54.908569837");
assert_eq!(&format!("{}", g_ct_1.display()), "12:43:54.908569837");
let p_g_ct1 = g_ct_1.into_positive();
assert_eq!(&format!("{p_g_ct1}"), "+12:43:54.908569837");
assert_eq!(&format!("{}", p_g_ct1.display()), "+12:43:54.908569837");
let n_g_ct1 = g_ct_1.into_negative();
assert_eq!(&format!("{n_g_ct1}"), "-12:43:54.908569837");
assert_eq!(&format!("{}", n_g_ct1.display()), "-12:43:54.908569837");
} }
} }

View file

@ -2,7 +2,7 @@
use std::fmt; use std::fmt;
use super::{Format, FormattedValueIntrinsic, FormattedValueNoneBuilder}; use super::{Format, FormattedValueNoneBuilder};
use crate::utils::Displayable; use crate::utils::Displayable;
// rustdoc-stripper-ignore-next // rustdoc-stripper-ignore-next
@ -12,7 +12,8 @@ use crate::utils::Displayable;
/// which is originaly unsigned. In C APIs, this is represented /// which is originaly unsigned. In C APIs, this is represented
/// by a tuple with a signed integer positive or negative and /// by a tuple with a signed integer positive or negative and
/// the absolute value. /// the absolute value.
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Signed<T> { pub enum Signed<T> {
Negative(T), Negative(T),
Positive(T), Positive(T),
@ -87,20 +88,6 @@ impl<T> Signed<T> {
} }
} }
// 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 // rustdoc-stripper-ignore-next
/// Returns the absolute value of `self`. /// Returns the absolute value of `self`.
pub fn abs(self) -> T { pub fn abs(self) -> T {
@ -121,9 +108,11 @@ impl<T> std::ops::Neg for Signed<T> {
} }
} }
pub trait SignedIntrinsic {}
impl<T> fmt::Display for Signed<T> impl<T> fmt::Display for Signed<T>
where where
T: fmt::Display + FormattedValueIntrinsic, T: fmt::Display + SignedIntrinsic,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::fmt::Write; use std::fmt::Write;
@ -140,7 +129,7 @@ where
impl<T> Displayable for Signed<T> impl<T> Displayable for Signed<T>
where where
T: fmt::Display + FormattedValueIntrinsic, T: fmt::Display + SignedIntrinsic,
{ {
type DisplayImpl = Signed<T>; type DisplayImpl = Signed<T>;
@ -169,7 +158,7 @@ pub struct DisplayableOptionSigned<T>(Option<Signed<T>>);
impl<T> fmt::Display for DisplayableOptionSigned<T> impl<T> fmt::Display for DisplayableOptionSigned<T>
where where
T: fmt::Display + FormattedValueIntrinsic, T: fmt::Display + SignedIntrinsic,
Option<T>: Displayable, Option<T>: Displayable,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -182,7 +171,7 @@ where
impl<T> Displayable for Option<Signed<T>> impl<T> Displayable for Option<Signed<T>>
where where
T: fmt::Display + FormattedValueIntrinsic, T: fmt::Display + SignedIntrinsic,
Option<T>: Displayable, Option<T>: Displayable,
{ {
type DisplayImpl = DisplayableOptionSigned<T>; type DisplayImpl = DisplayableOptionSigned<T>;
@ -194,7 +183,7 @@ where
impl<T> Displayable for Signed<Option<T>> impl<T> Displayable for Signed<Option<T>>
where where
T: fmt::Display + FormattedValueIntrinsic, T: fmt::Display + SignedIntrinsic,
Option<T>: Displayable, Option<T>: Displayable,
{ {
type DisplayImpl = DisplayableOptionSigned<T>; type DisplayImpl = DisplayableOptionSigned<T>;

View file

@ -36,7 +36,7 @@ glib_newtype_display!(
Buffers, Buffers,
DisplayableBuffers, DisplayableBuffers,
DisplayableOptionBuffers, DisplayableOptionBuffers,
"buffers" Format::Buffers,
); );
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
@ -49,7 +49,12 @@ impl_common_ops_for_newtype_uint!(Bytes, u64);
impl_signed_div_mul!(Bytes, u64); impl_signed_div_mul!(Bytes, u64);
impl_format_value_traits!(Bytes, Bytes, Bytes, u64); impl_format_value_traits!(Bytes, Bytes, Bytes, u64);
option_glib_newtype_from_to!(Bytes, u64::MAX); option_glib_newtype_from_to!(Bytes, u64::MAX);
glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes"); glib_newtype_display!(
Bytes,
DisplayableBytes,
DisplayableOptionBytes,
Format::Bytes,
);
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
pub struct Default(pub u64); pub struct Default(pub u64);
@ -65,7 +70,7 @@ glib_newtype_display!(
Default, Default,
DisplayableDefault, DisplayableDefault,
DisplayableOptionDefault, DisplayableOptionDefault,
"(Default)" Format::Default,
); );
pub type Time = super::ClockTime; pub type Time = super::ClockTime;
@ -81,7 +86,12 @@ impl Percent {
impl_common_ops_for_newtype_uint!(Percent, u32); impl_common_ops_for_newtype_uint!(Percent, u32);
impl_signed_div_mul!(Percent, u32); impl_signed_div_mul!(Percent, u32);
glib_newtype_display!(Percent, DisplayablePercent, DisplayableOptionPercent, "%"); glib_newtype_display!(
Percent,
DisplayablePercent,
DisplayableOptionPercent,
Format::Percent,
);
impl FormattedValue for Option<Percent> { impl FormattedValue for Option<Percent> {
type FullRange = Option<Percent>; type FullRange = Option<Percent>;
@ -202,32 +212,6 @@ impl FormattedValueNoneBuilder for Option<Percent> {
} }
} }
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)] #[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
#[error("value out of range")] #[error("value out of range")]
pub struct TryPercentFromFloatError(()); pub struct TryPercentFromFloatError(());

View file

@ -108,4 +108,4 @@ impl From<Undefined> for Signed<u64> {
} }
} }
glib_newtype_display!(Undefined, DisplayableUndefined, "(Undefined)"); glib_newtype_display!(Undefined, DisplayableUndefined, Format::Undefined);