gst/format: use fmt::Display whenever possible

Previous implementation for the glib format new types built a
`String` for the displayable value. This commit uses `fmt`
mechanisms so as to limit useless allocations.
This commit is contained in:
François Laignel 2022-09-16 17:59:05 +02:00 committed by François Laignel
parent e0d9f886e3
commit a1dbc7a0ee
2 changed files with 74 additions and 32 deletions

View file

@ -1,5 +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 crate::utils::Displayable;
use crate::ClockTime; use crate::ClockTime;
use crate::Format; use crate::Format;
use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib}; use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib};
@ -449,8 +450,6 @@ impl Percent {
impl fmt::Display for GenericFormattedValue { impl fmt::Display for GenericFormattedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use crate::utils::Displayable;
match self { match self {
Self::Undefined(val) => val.fmt(f), Self::Undefined(val) => val.fmt(f),
Self::Default(val) => val.display().fmt(f), Self::Default(val) => val.display().fmt(f),
@ -835,19 +834,29 @@ impl FormattedValueIntrinsic for GenericFormattedValue {}
impl_common_ops_for_newtype_uint!(Default, u64); impl_common_ops_for_newtype_uint!(Default, u64);
impl_format_value_traits!(Default, Default, Default, u64); impl_format_value_traits!(Default, Default, Default, u64);
option_glib_newtype_from_to!(Default, u64::MAX); option_glib_newtype_from_to!(Default, u64::MAX);
option_glib_newtype_display!(Default, "(Default)"); glib_newtype_display!(
Default,
DisplayableDefault,
DisplayableOptionDefault,
"(Default)"
);
impl_common_ops_for_newtype_uint!(Bytes, u64); impl_common_ops_for_newtype_uint!(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);
option_glib_newtype_display!(Bytes, "bytes"); glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes");
impl_format_value_traits!(ClockTime, Time, Time, u64); impl_format_value_traits!(ClockTime, Time, Time, u64);
impl_common_ops_for_newtype_uint!(Buffers, u64); impl_common_ops_for_newtype_uint!(Buffers, u64);
impl_format_value_traits!(Buffers, Buffers, Buffers, u64); impl_format_value_traits!(Buffers, Buffers, Buffers, u64);
option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE); option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE);
option_glib_newtype_display!(Buffers, "buffers"); glib_newtype_display!(
Buffers,
DisplayableBuffers,
DisplayableOptionBuffers,
"buffers"
);
impl FormattedValue for Undefined { impl FormattedValue for Undefined {
type FullRange = Undefined; type FullRange = Undefined;
@ -945,22 +954,10 @@ impl AsMut<i64> for Undefined {
} }
} }
impl fmt::Display for Undefined { glib_newtype_display!(Undefined, DisplayableUndefined, "(Undefined)");
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} (Undefined)", self.0)
}
}
impl crate::utils::Displayable for Undefined {
type DisplayImpl = Undefined;
fn display(self) -> Undefined {
self
}
}
impl_common_ops_for_newtype_uint!(Percent, u32); impl_common_ops_for_newtype_uint!(Percent, u32);
option_glib_newtype_display!(Percent, "%"); glib_newtype_display!(Percent, DisplayablePercent, DisplayableOptionPercent, "%");
impl FormattedValue for Option<Percent> { impl FormattedValue for Option<Percent> {
type FullRange = Option<Percent>; type FullRange = Option<Percent>;
@ -1364,4 +1361,21 @@ mod tests {
unsafe { Option::<ClockTime>::from_raw(Format::Time, raw_ct_none) }.into_signed(-1); unsafe { Option::<ClockTime>::from_raw(Format::Time, raw_ct_none) }.into_signed(-1);
assert!(signed.is_none()); assert!(signed.is_none());
} }
#[test]
fn display_new_types() {
let bytes = Bytes(42);
assert_eq!(&format!("{bytes}"), "42 bytes");
assert_eq!(&format!("{}", bytes.display()), "42 bytes");
assert_eq!(&format!("{}", Some(bytes).display()), "42 bytes");
assert_eq!(&format!("{}", Bytes::NONE.display()), "undef. bytes");
let gv_1 = GenericFormattedValue::Percent(Some(Percent(42)));
assert_eq!(&format!("{gv_1}"), "42 %");
assert_eq!(
&format!("{}", GenericFormattedValue::Percent(None)),
"undef. %"
);
}
} }

View file

@ -541,25 +541,53 @@ macro_rules! option_glib_newtype_from_to {
}; };
} }
macro_rules! option_glib_newtype_display { // FIXME we could automatically build `$displayable_name` and
($name:ident, $unit:expr) => { // `$displayable_option_name` if `concat_idents!` was stable.
impl crate::utils::Displayable for Option<$name> { // See: https://doc.rust-lang.org/std/macro.concat_idents.html
type DisplayImpl = String; macro_rules! glib_newtype_display {
($name:ident, $displayable_name:ident, $unit:expr) => {
pub struct $displayable_name($name);
fn display(self) -> String { impl std::fmt::Display for $name {
if let Some(val) = self { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
val.display() use std::fmt::Write;
} else {
format!("undef. {}", $unit) std::fmt::Display::fmt(&self.0, f)?;
} f.write_char(' ')?;
f.write_str($unit)
} }
} }
impl crate::utils::Displayable for $name { impl crate::utils::Displayable for $name {
type DisplayImpl = String; type DisplayImpl = $name;
fn display(self) -> String { fn display(self) -> $name {
format!("{} {}", self.0, $unit) self
}
}
};
($name:ident, $displayable_name:ident, $displayable_option_name:ident, $unit:expr) => {
glib_newtype_display!($name, $displayable_name, $unit);
pub struct $displayable_option_name(Option<$name>);
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. ")?;
f.write_str($unit)
}
}
}
impl crate::utils::Displayable for Option<$name> {
type DisplayImpl = $displayable_option_name;
fn display(self) -> Self::DisplayImpl {
$displayable_option_name(self)
} }
} }
}; };