From d44c2937535d4a7107e7eac465a3321845b9b028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 3 Jun 2019 18:42:00 +0300 Subject: [PATCH] Use TryFrom/TryInto traits where it makes sense instead of our previous ad-hoc solutions --- examples/src/bin/queries.rs | 9 +- gstreamer-video/src/video_info.rs | 6 +- gstreamer-video/src/video_time_code.rs | 13 +- gstreamer/src/format.rs | 363 ++++++++++++++++--------- gstreamer/src/query.rs | 11 +- 5 files changed, 261 insertions(+), 141 deletions(-) diff --git a/examples/src/bin/queries.rs b/examples/src/bin/queries.rs index 0c66f9212..7348a89eb 100644 --- a/examples/src/bin/queries.rs +++ b/examples/src/bin/queries.rs @@ -17,6 +17,7 @@ use gst::prelude::*; extern crate glib; +use std::convert::TryInto; use std::env; #[path = "../examples-common.rs"] @@ -60,7 +61,7 @@ fn example_main() { //let pos = pipeline.query_position(gst::Format::Time).unwrap_or(-1); //let dur = pipeline.query_duration(gst::Format::Time).unwrap_or(-1); - let pos = { + let pos: gst::ClockTime = { // Create a new position query and send it to the pipeline. // This will traverse all elements in the pipeline, until one feels // capable of answering the query. @@ -71,10 +72,10 @@ fn example_main() { None } } - .and_then(|pos| pos.try_into_time().ok()) + .and_then(|pos| pos.try_into().ok()) .unwrap(); - let dur = { + let dur: gst::ClockTime = { // Create a new duration query and send it to the pipeline. // This will traverse all elements in the pipeline, until one feels // capable of answering the query. @@ -85,7 +86,7 @@ fn example_main() { None } } - .and_then(|dur| dur.try_into_time().ok()) + .and_then(|dur| dur.try_into().ok()) .unwrap(); println!("{} / {}", pos, dur); diff --git a/gstreamer-video/src/video_info.rs b/gstreamer-video/src/video_info.rs index a2a719620..d79f15c35 100644 --- a/gstreamer-video/src/video_info.rs +++ b/gstreamer-video/src/video_info.rs @@ -196,8 +196,10 @@ impl From<::VideoMultiviewFramePacking> for ::VideoMultiviewMode { } } -impl ::VideoMultiviewFramePacking { - pub fn try_from( +impl std::convert::TryFrom<::VideoMultiviewMode> for ::VideoMultiviewFramePacking { + type Error = ::VideoMultiviewMode; + + fn try_from( v: ::VideoMultiviewMode, ) -> Result<::VideoMultiviewFramePacking, ::VideoMultiviewMode> { let v2 = from_glib(v.to_glib()); diff --git a/gstreamer-video/src/video_time_code.rs b/gstreamer-video/src/video_time_code.rs index d2c0fbcf0..9f9b6fe89 100644 --- a/gstreamer-video/src/video_time_code.rs +++ b/gstreamer-video/src/video_time_code.rs @@ -16,6 +16,7 @@ use gst; use gst::prelude::*; use gst_video_sys; use std::cmp; +use std::convert::{TryFrom, TryInto}; use std::fmt; use std::mem; use std::ptr; @@ -147,12 +148,16 @@ impl VideoTimeCode { assert!(field_count <= 2); self.0.field_count = field_count } +} - pub fn try_into(self) -> Result { - if self.is_valid() { - Ok(ValidVideoTimeCode(self.0)) +impl TryFrom for ValidVideoTimeCode { + type Error = VideoTimeCode; + + fn try_from(v: VideoTimeCode) -> Result { + if v.is_valid() { + Ok(ValidVideoTimeCode(v.0)) } else { - Err(self) + Err(v) } } } diff --git a/gstreamer/src/format.rs b/gstreamer/src/format.rs index 8fe33cc95..451d15066 100644 --- a/gstreamer/src/format.rs +++ b/gstreamer/src/format.rs @@ -7,6 +7,7 @@ // except according to those terms. use muldiv::MulDiv; +use std::convert::TryFrom; use std::ops; use ClockTime; use Format; @@ -14,44 +15,57 @@ use Format; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] #[cfg_attr(feature = "ser_de", derive(Serialize, Deserialize))] pub enum GenericFormattedValue { - Undefined(i64), + Undefined(Undefined), Default(Default), Bytes(Bytes), Time(ClockTime), Buffers(Buffers), - Percent(Option), + Percent(Percent), Other(Format, i64), } +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] +pub struct Undefined(pub i64); #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Default(pub Option); #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Bytes(pub Option); +pub type Time = ClockTime; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Buffers(pub Option); -pub type Time = ClockTime; +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] +pub struct Percent(pub Option); -pub trait FormattedValue: Copy + Clone + Sized + 'static { +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TryFromGenericFormattedValueError(()); + +impl std::error::Error for TryFromGenericFormattedValueError { + fn description(&self) -> &str { + "invalid generic value format" + } +} + +impl std::fmt::Display for TryFromGenericFormattedValueError { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "invalid generic value format") + } +} + +pub trait FormattedValue: Copy + Clone + Sized + Into + 'static { fn get_default_format() -> Format; - fn try_from(v: GenericFormattedValue) -> Option; - fn get_format(&self) -> Format; unsafe fn from_raw(format: Format, value: i64) -> Self; unsafe fn to_raw_value(&self) -> i64; } -pub trait SpecificFormattedValue: FormattedValue {} +pub trait SpecificFormattedValue: FormattedValue + TryFrom {} impl FormattedValue for GenericFormattedValue { fn get_default_format() -> Format { Format::Undefined } - fn try_from(v: GenericFormattedValue) -> Option { - Some(v) - } - fn get_format(&self) -> Format { self.get_format() } @@ -68,7 +82,7 @@ impl FormattedValue for GenericFormattedValue { impl GenericFormattedValue { pub fn new(format: Format, value: i64) -> Self { match format { - Format::Undefined => GenericFormattedValue::Undefined(value), + Format::Undefined => GenericFormattedValue::Undefined(Undefined(value)), Format::Default => GenericFormattedValue::Default(if value == -1 { Default(None) } else { @@ -89,43 +103,13 @@ impl GenericFormattedValue { } else { Buffers(Some(value as u64)) }), - Format::Percent => GenericFormattedValue::Percent(if value == -1 { - None - } else { - Some(value as u32) - }), + Format::Percent => { + GenericFormattedValue::Percent(unsafe { Percent::from_raw(format, value) }) + } Format::__Unknown(_) => GenericFormattedValue::Other(format, value), } } - pub fn from_undefined(v: i64) -> Self { - GenericFormattedValue::Undefined(v) - } - - pub fn from_default>(v: V) -> Self { - GenericFormattedValue::Default(v.into()) - } - - pub fn from_bytes>(v: V) -> Self { - GenericFormattedValue::Bytes(v.into()) - } - - pub fn from_time>(v: V) -> Self { - GenericFormattedValue::Time(v.into()) - } - - pub fn from_buffers>(v: V) -> Self { - GenericFormattedValue::Buffers(v.into()) - } - - pub fn from_percent>>(v: V) -> Self { - GenericFormattedValue::Percent(v.into()) - } - - pub fn from_other(format: Format, v: i64) -> Self { - GenericFormattedValue::Other(format, v) - } - pub fn get_format(&self) -> Format { match *self { GenericFormattedValue::Undefined(_) => Format::Undefined, @@ -140,7 +124,7 @@ impl GenericFormattedValue { pub fn get_value(&self) -> i64 { match *self { - GenericFormattedValue::Undefined(v) => v, + GenericFormattedValue::Undefined(v) => v.0, GenericFormattedValue::Default(v) => v.map(|v| v as i64).unwrap_or(-1), GenericFormattedValue::Bytes(v) => v.map(|v| v as i64).unwrap_or(-1), GenericFormattedValue::Time(v) => v.map(|v| v as i64).unwrap_or(-1), @@ -149,72 +133,6 @@ impl GenericFormattedValue { GenericFormattedValue::Other(_, v) => v, } } - - pub fn try_into(self) -> Result { - if F::get_default_format() == self.get_format() - || F::get_default_format() == Format::Undefined - { - Ok(unsafe { F::from_raw(self.get_format(), self.to_raw_value()) }) - } else { - Err(self) - } - } - - pub fn try_into_undefined(self) -> Result { - if let GenericFormattedValue::Undefined(v) = self { - Ok(v) - } else { - Err(self) - } - } - - pub fn try_into_default(self) -> Result { - if let GenericFormattedValue::Default(v) = self { - Ok(v) - } else { - Err(self) - } - } - - pub fn try_into_bytes(self) -> Result { - if let GenericFormattedValue::Bytes(v) = self { - Ok(v) - } else { - Err(self) - } - } - - pub fn try_into_time(self) -> Result { - if let GenericFormattedValue::Time(v) = self { - Ok(v) - } else { - Err(self) - } - } - - pub fn try_into_buffers(self) -> Result { - if let GenericFormattedValue::Buffers(v) = self { - Ok(v) - } else { - Err(self) - } - } - - pub fn try_into_percent(self) -> Result, Self> { - if let GenericFormattedValue::Percent(v) = self { - Ok(v) - } else { - Err(self) - } - } - - pub fn try_into_other(self) -> Result<(Format, i64), Self> { - if let GenericFormattedValue::Other(f, v) = self { - Ok((f, v)) - } else { - Err(self) - } - } } macro_rules! impl_op_same( @@ -359,25 +277,11 @@ macro_rules! impl_op_u64( macro_rules! impl_format_value_traits( ($name:ident, $format:ident, $format_value:ident) => { - impl From<$name> for GenericFormattedValue { - fn from(v: $name) -> GenericFormattedValue { - GenericFormattedValue::$format_value(v) - } - } - impl FormattedValue for $name { fn get_default_format() -> Format { Format::$format } - fn try_from(v: GenericFormattedValue) -> Option { - if let GenericFormattedValue::$format_value(v) = v { - Some(v) - } else { - None - } - } - fn get_format(&self) -> Format { Format::$format } @@ -396,6 +300,24 @@ macro_rules! impl_format_value_traits( } } + impl From<$name> for GenericFormattedValue { + fn from(v: $name) -> GenericFormattedValue { + GenericFormattedValue::$format_value(v) + } + } + + impl TryFrom for $name { + type Error = TryFromGenericFormattedValueError; + + fn try_from(v: GenericFormattedValue) -> Result<$name, TryFromGenericFormattedValueError> { + if let GenericFormattedValue::$format_value(v) = v { + Ok(v) + } else { + Err(TryFromGenericFormattedValueError(())) + } + } + } + impl SpecificFormattedValue for $name { } impl From for $name { @@ -596,6 +518,195 @@ impl_format_value_traits!(Bytes, Bytes, Bytes); impl_format_value_traits!(ClockTime, Time, Time); impl_format_value_traits!(Buffers, Buffers, Buffers); +impl FormattedValue for Undefined { + fn get_default_format() -> Format { + Format::Undefined + } + + fn get_format(&self) -> Format { + Format::Undefined + } + + unsafe fn from_raw(format: Format, value: i64) -> Self { + debug_assert_eq!(format, Format::Undefined); + Undefined(value) + } + + unsafe fn to_raw_value(&self) -> i64 { + self.0 + } +} + +impl From for GenericFormattedValue { + fn from(v: Undefined) -> GenericFormattedValue { + GenericFormattedValue::Undefined(v) + } +} + +impl TryFrom for Undefined { + type Error = TryFromGenericFormattedValueError; + + fn try_from(v: GenericFormattedValue) -> Result { + if let GenericFormattedValue::Undefined(v) = v { + Ok(v) + } else { + Err(TryFromGenericFormattedValueError(())) + } + } +} + +impl SpecificFormattedValue for Undefined {} + +impl From for Undefined { + fn from(v: i64) -> Undefined { + Undefined(v) + } +} + +impl Into for Undefined { + fn into(self) -> i64 { + self.0 + } +} + +impl ops::Deref for Undefined { + type Target = i64; + + fn deref(&self) -> &i64 { + &self.0 + } +} + +impl ops::DerefMut for Undefined { + fn deref_mut(&mut self) -> &mut i64 { + &mut self.0 + } +} + +impl AsRef for Undefined { + fn as_ref(&self) -> &i64 { + &self.0 + } +} + +impl AsMut for Undefined { + fn as_mut(&mut self) -> &mut i64 { + &mut self.0 + } +} + +impl FormattedValue for Percent { + fn get_default_format() -> Format { + Format::Percent + } + + fn get_format(&self) -> Format { + Format::Percent + } + + unsafe fn from_raw(format: Format, value: i64) -> Self { + debug_assert_eq!(format, Format::Percent); + if value < 0 || value > gst_sys::GST_FORMAT_PERCENT_MAX { + Percent(None) + } else { + Percent(Some(value as u32)) + } + } + + unsafe fn to_raw_value(&self) -> i64 { + self.0.map(|v| v as i64).unwrap_or(-1) + } +} + +impl From for GenericFormattedValue { + fn from(v: Percent) -> GenericFormattedValue { + GenericFormattedValue::Percent(v) + } +} + +impl TryFrom for Percent { + type Error = TryFromGenericFormattedValueError; + + fn try_from(v: GenericFormattedValue) -> Result { + if let GenericFormattedValue::Percent(v) = v { + Ok(v) + } else { + Err(TryFromGenericFormattedValueError(())) + } + } +} + +impl SpecificFormattedValue for Percent {} + +impl ops::Deref for Percent { + type Target = Option; + + fn deref(&self) -> &Option { + &self.0 + } +} + +impl ops::DerefMut for Percent { + fn deref_mut(&mut self) -> &mut Option { + &mut self.0 + } +} + +impl AsRef> for Percent { + fn as_ref(&self) -> &Option { + &self.0 + } +} + +impl AsMut> for Percent { + fn as_mut(&mut self) -> &mut Option { + &mut self.0 + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TryPercentFromFloatError(()); + +impl std::error::Error for TryPercentFromFloatError { + fn description(&self) -> &str { + "value out of range" + } +} + +impl std::fmt::Display for TryPercentFromFloatError { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "value out of range") + } +} + +impl TryFrom for Percent { + type Error = TryPercentFromFloatError; + + fn try_from(v: f64) -> Result { + if v < 0.0 || v > 1.0 { + Err(TryPercentFromFloatError(())) + } else { + Ok(Percent(Some( + (v * gst_sys::GST_FORMAT_PERCENT_SCALE as f64).round() as u32, + ))) + } + } +} + +impl TryFrom for Percent { + type Error = TryPercentFromFloatError; + + fn try_from(v: f32) -> Result { + if v < 0.0 || v > 1.0 { + Err(TryPercentFromFloatError(())) + } else { + Ok(Percent(Some( + (v * gst_sys::GST_FORMAT_PERCENT_SCALE as f32).round() as u32, + ))) + } + } +} + #[cfg(test)] mod tests { #[test] diff --git a/gstreamer/src/query.rs b/gstreamer/src/query.rs index e6a852eec..1fb52f2b8 100644 --- a/gstreamer/src/query.rs +++ b/gstreamer/src/query.rs @@ -1277,6 +1277,7 @@ declare_concrete_query!(Other, T); #[cfg(test)] mod tests { use super::*; + use std::convert::TryInto; #[test] fn test_writability() { @@ -1286,10 +1287,10 @@ mod tests { match query.view_mut() { QueryView::Position(ref mut p) => { let pos = p.get_result(); - assert_eq!(pos.try_into_time(), Ok(::CLOCK_TIME_NONE)); + assert_eq!(pos.try_into(), Ok(::CLOCK_TIME_NONE)); p.set(3 * ::SECOND); let pos = p.get_result(); - assert_eq!(pos.try_into_time(), Ok(3 * ::SECOND)); + assert_eq!(pos.try_into(), Ok(3 * ::SECOND)); } _ => panic!("Wrong concrete Query in Query"), } @@ -1299,7 +1300,7 @@ mod tests { match query.view() { QueryView::Position(ref p) => { let pos = p.get_result(); - assert_eq!(pos.try_into_time(), Ok(3 * ::SECOND)); + assert_eq!(pos.try_into(), Ok(3 * ::SECOND)); unsafe { assert!(!p.as_mut_ptr().is_null()); } @@ -1310,7 +1311,7 @@ mod tests { let mut p = Query::new_position(::Format::Time); let pos = p.get_result(); - assert_eq!(pos.try_into_time(), Ok(::CLOCK_TIME_NONE)); + assert_eq!(pos.try_into(), Ok(::CLOCK_TIME_NONE)); p.get_mut_structure().set("check_mut", &true); @@ -1349,7 +1350,7 @@ mod tests { match query.view() { QueryView::Duration(ref d) => { let duration = d.get_result(); - assert_eq!(duration.try_into_time(), Ok(2 * ::SECOND)); + assert_eq!(duration.try_into(), Ok(2 * ::SECOND)); } _ => (), }