From 90ff18e2b338dffb1731a116b321f74127d486ba Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Mon, 10 Feb 2020 13:13:41 +0100 Subject: [PATCH] implement Float and UFloat --- src/tags/shared/start.rs | 102 ++++++------ src/types/decimal_floating_point.rs | 137 ---------------- src/types/float.rs | 173 ++++++++++++++++++++ src/types/mod.rs | 10 +- src/types/signed_decimal_floating_point.rs | 94 ----------- src/types/ufloat.rs | 182 +++++++++++++++++++++ src/utils.rs | 21 --- 7 files changed, 409 insertions(+), 310 deletions(-) delete mode 100644 src/types/decimal_floating_point.rs create mode 100644 src/types/float.rs delete mode 100644 src/types/signed_decimal_floating_point.rs create mode 100644 src/types/ufloat.rs diff --git a/src/tags/shared/start.rs b/src/tags/shared/start.rs index 994b4ed..1b2afb2 100644 --- a/src/tags/shared/start.rs +++ b/src/tags/shared/start.rs @@ -1,18 +1,35 @@ use std::fmt; use std::str::FromStr; +use shorthand::ShortHand; + use crate::attribute::AttributePairs; -use crate::types::{ProtocolVersion, SignedDecimalFloatingPoint}; +use crate::types::{Float, ProtocolVersion}; use crate::utils::{parse_yes_or_no, tag}; use crate::{Error, RequiredVersion}; /// # [4.3.5.2. EXT-X-START] /// /// [4.3.5.2. EXT-X-START]: https://tools.ietf.org/html/rfc8216#section-4.3.5.2 -#[derive(PartialOrd, Debug, Clone, Copy, PartialEq)] +#[derive(ShortHand, PartialOrd, Debug, Clone, Copy, PartialEq)] +#[shorthand(enable(must_use))] pub struct ExtXStart { - time_offset: SignedDecimalFloatingPoint, - precise: bool, + #[shorthand(enable(skip))] + time_offset: Float, + /// Returns whether clients should not render media stream whose + /// presentation times are prior to the specified time offset. + /// + /// # Example + /// + /// ``` + /// # use hls_m3u8::tags::ExtXStart; + /// let mut start = ExtXStart::new(20.123456); + /// # assert_eq!(start.is_precise(), false); + /// start.set_is_precise(true); + /// + /// assert_eq!(start.is_precise(), true); + /// ``` + is_precise: bool, } impl ExtXStart { @@ -20,9 +37,9 @@ impl ExtXStart { /// Makes a new [`ExtXStart`] tag. /// - /// # Panic + /// # Panics /// - /// Panics if the time_offset value is infinite. + /// Panics if the `time_offset` is infinite or [`NaN`]. /// /// # Example /// @@ -30,30 +47,34 @@ impl ExtXStart { /// # use hls_m3u8::tags::ExtXStart; /// let start = ExtXStart::new(20.123456); /// ``` - pub fn new(time_offset: f64) -> Self { + /// + /// [`NaN`]: core::f64::NAN + pub fn new(time_offset: f32) -> Self { Self { - time_offset: SignedDecimalFloatingPoint::new(time_offset), - precise: false, + time_offset: Float::new(time_offset), + is_precise: false, } } /// Makes a new [`ExtXStart`] tag with the given `precise` flag. /// - /// # Panic + /// # Panics /// - /// Panics if the time_offset value is infinite. + /// Panics if the `time_offset` is infinite or [`NaN`]. /// /// # Example /// /// ``` /// # use hls_m3u8::tags::ExtXStart; /// let start = ExtXStart::with_precise(20.123456, true); - /// assert_eq!(start.precise(), true); + /// assert_eq!(start.is_precise(), true); /// ``` - pub fn with_precise(time_offset: f64, precise: bool) -> Self { + /// + /// [`NaN`]: core::f64::NAN + pub fn with_precise(time_offset: f32, is_precise: bool) -> Self { Self { - time_offset: SignedDecimalFloatingPoint::new(time_offset), - precise, + time_offset: Float::new(time_offset), + is_precise, } } @@ -64,9 +85,10 @@ impl ExtXStart { /// ``` /// # use hls_m3u8::tags::ExtXStart; /// let start = ExtXStart::new(20.123456); + /// /// assert_eq!(start.time_offset(), 20.123456); /// ``` - pub const fn time_offset(&self) -> f64 { self.time_offset.as_f64() } + pub const fn time_offset(self) -> f32 { self.time_offset.as_f32() } /// Sets the time offset of the media segments in the playlist. /// @@ -81,38 +103,8 @@ impl ExtXStart { /// /// assert_eq!(start.time_offset(), 1.0); /// ``` - pub fn set_time_offset(&mut self, value: f64) -> &mut Self { - self.time_offset = SignedDecimalFloatingPoint::new(value); - self - } - - /// Returns whether clients should not render media stream whose - /// presentation times are prior to the specified time offset. - /// - /// # Example - /// - /// ``` - /// # use hls_m3u8::tags::ExtXStart; - /// let start = ExtXStart::with_precise(20.123456, true); - /// assert_eq!(start.precise(), true); - /// ``` - pub const fn precise(&self) -> bool { self.precise } - - /// Sets the `precise` flag. - /// - /// # Example - /// - /// ``` - /// # use hls_m3u8::tags::ExtXStart; - /// let mut start = ExtXStart::new(20.123456); - /// # assert_eq!(start.precise(), false); - /// - /// start.set_precise(true); - /// - /// assert_eq!(start.precise(), true); - /// ``` - pub fn set_precise(&mut self, value: bool) -> &mut Self { - self.precise = value; + pub fn set_time_offset(&mut self, value: f32) -> &mut Self { + self.time_offset = Float::new(value); self } } @@ -126,9 +118,11 @@ impl fmt::Display for ExtXStart { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", Self::PREFIX)?; write!(f, "TIME-OFFSET={}", self.time_offset)?; - if self.precise { + + if self.is_precise { write!(f, ",PRECISE=YES")?; } + Ok(()) } } @@ -140,12 +134,12 @@ impl FromStr for ExtXStart { let input = tag(input, Self::PREFIX)?; let mut time_offset = None; - let mut precise = false; + let mut is_precise = false; for (key, value) in AttributePairs::new(input) { match key { - "TIME-OFFSET" => time_offset = Some((value.parse())?), - "PRECISE" => precise = (parse_yes_or_no(value))?, + "TIME-OFFSET" => time_offset = Some(value.parse()?), + "PRECISE" => is_precise = parse_yes_or_no(value)?, _ => { // [6.3.1. General Client Responsibilities] // > ignore any attribute/value pair with an unrecognized @@ -154,11 +148,11 @@ impl FromStr for ExtXStart { } } - let time_offset = time_offset.ok_or_else(|| Error::missing_value("EXT-X-TIME-OFFSET"))?; + let time_offset = time_offset.ok_or_else(|| Error::missing_value("TIME-OFFSET"))?; Ok(Self { time_offset, - precise, + is_precise, }) } } diff --git a/src/types/decimal_floating_point.rs b/src/types/decimal_floating_point.rs deleted file mode 100644 index 454fb66..0000000 --- a/src/types/decimal_floating_point.rs +++ /dev/null @@ -1,137 +0,0 @@ -use core::str::FromStr; - -use derive_more::{Deref, Display}; - -use crate::Error; - -/// Non-negative decimal floating-point number. -/// -/// See: [4.2. Attribute Lists] -/// -/// [4.2. Attribute Lists]: -/// https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-05#section-4.2 -#[derive(Deref, Default, Debug, Clone, Copy, PartialEq, PartialOrd, Display)] -pub(crate) struct DecimalFloatingPoint(f64); - -impl DecimalFloatingPoint { - /// Makes a new [`DecimalFloatingPoint`] instance. - /// - /// # Errors - /// - /// The given value must have a positive sign and be finite, - /// otherwise this function will return an error that has the kind - /// `ErrorKind::InvalidInput`. - pub fn new(value: f64) -> crate::Result { - if value.is_sign_negative() || value.is_infinite() || value.is_nan() { - return Err(Error::invalid_input()); - } - Ok(Self(value)) - } - - pub(crate) const fn from_f64_unchecked(value: f64) -> Self { Self(value) } - - /// Converts [`DecimalFloatingPoint`] to [`f64`]. - pub const fn as_f64(self) -> f64 { self.0 } -} - -// this trait is implemented manually, so it doesn't construct a -// [`DecimalFloatingPoint`], with a negative value. -impl FromStr for DecimalFloatingPoint { - type Err = Error; - - fn from_str(input: &str) -> Result { - Self::new(input.parse().map_err(Error::parse_float)?) - } -} - -#[doc(hidden)] -impl From for DecimalFloatingPoint { - fn from(value: f64) -> Self { - let mut result = value; - - // guard against the unlikely case of an infinite value... - if result.is_infinite() || result.is_nan() { - result = 0.0; - } - - Self(result.abs()) - } -} - -#[doc(hidden)] -impl From for DecimalFloatingPoint { - fn from(value: f32) -> Self { f64::from(value).into() } -} - -#[cfg(test)] -mod tests { - use super::*; - use pretty_assertions::assert_eq; - - macro_rules! test_from { - ( $($input:expr),* ) => { - use ::core::convert::From; - - #[test] - fn test_from() { - $( - assert_eq!( - DecimalFloatingPoint::from($input), - DecimalFloatingPoint::new(1.0).unwrap(), - ); - )* - } - } - } - - test_from![1_u8, 1_u16, 1_u32, 1.0_f32, -1.0_f32, 1.0_f64, -1.0_f64]; - - #[test] - pub fn test_display() { - let decimal_floating_point = DecimalFloatingPoint::new(22.0).unwrap(); - assert_eq!(decimal_floating_point.to_string(), "22".to_string()); - - let decimal_floating_point = DecimalFloatingPoint::new(4.1).unwrap(); - assert_eq!(decimal_floating_point.to_string(), "4.1".to_string()); - } - - #[test] - pub fn test_parser() { - assert_eq!( - DecimalFloatingPoint::new(22.0).unwrap(), - "22".parse::().unwrap() - ); - - assert_eq!( - DecimalFloatingPoint::new(4.1).unwrap(), - "4.1".parse::().unwrap() - ); - - assert!("1#".parse::().is_err()); - assert!("-1.0".parse::().is_err()); - } - - #[test] - fn test_new() { - assert!(DecimalFloatingPoint::new(::std::f64::INFINITY).is_err()); - assert!(DecimalFloatingPoint::new(-1.0).is_err()); - } - - #[test] - fn test_as_f64() { - assert_eq!(DecimalFloatingPoint::new(1.0).unwrap().as_f64(), 1.0); - } - - #[test] - fn test_from_inf() { - assert_eq!( - DecimalFloatingPoint::from(::std::f64::INFINITY), - DecimalFloatingPoint::new(0.0).unwrap() - ); - } - - #[test] - fn test_deref() { - assert_eq!(DecimalFloatingPoint::from(0.1).floor(), 0.0); - } -} diff --git a/src/types/float.rs b/src/types/float.rs new file mode 100644 index 0000000..48d1e26 --- /dev/null +++ b/src/types/float.rs @@ -0,0 +1,173 @@ +use core::convert::TryFrom; +use core::str::FromStr; + +use derive_more::{Deref, Display}; + +use crate::Error; + +/// This is a wrapper type around an [`f32`] that can not be constructed +/// with [`NaN`], [`INFINITY`] or [`NEG_INFINITY`]. +/// +/// [`NaN`]: core::f32::NAN +/// [`INFINITY`]: core::f32::INFINITY +/// [`NEG_INFINITY`]: core::f32::NEG_INFINITY +#[derive(Deref, Default, Debug, Copy, Clone, PartialEq, PartialOrd, Display)] +pub struct Float(f32); + +impl Float { + /// Makes a new [`Float`] from an [`f32`]. + /// + /// # Panics + /// + /// If the given float is infinite or [`NaN`]. + /// + /// # Examples + /// + /// ``` + /// use hls_m3u8::types::Float; + /// + /// let float = Float::new(1.0); + /// ``` + /// + /// This would panic: + /// + /// ```should_panic + /// use core::f32::NAN; + /// use hls_m3u8::types::Float; + /// + /// let float = Float::new(NAN); + /// ``` + /// + /// [`NaN`]: core::f32::NAN + pub fn new(float: f32) -> Self { + if float.is_infinite() { + panic!("float must be finite: `{}`", float); + } + + if float.is_nan() { + panic!("float must not be `NaN`"); + } + + Self(float) + } + + /// Returns the underlying [`f32`]. + pub const fn as_f32(self) -> f32 { self.0 } +} + +impl FromStr for Float { + type Err = Error; + + fn from_str(input: &str) -> Result { + let float = f32::from_str(input).map_err(Error::parse_float)?; + Self::try_from(float) + } +} + +impl TryFrom for Float { + type Error = Error; + + fn try_from(float: f32) -> Result { + if float.is_infinite() { + return Err(Error::custom(format!("float must be finite: `{}`", float))); + } + + if float.is_nan() { + return Err(Error::custom("float must not be `NaN`")); + } + + Ok(Self(float)) + } +} + +macro_rules! implement_from { + ( $( $type:tt ),+ ) => { + $( + impl ::core::convert::From<$type> for Float { + fn from(value: $type) -> Self { + Self(value as f32) + } + } + )+ + } +} + +implement_from!(i16, u16, i8, u8); + +// convenience implementation to compare f32 with a Float. +impl PartialEq for Float { + fn eq(&self, other: &f32) -> bool { &self.0 == other } +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn test_display() { + assert_eq!(Float::new(22.0).to_string(), "22".to_string()); + assert_eq!( + Float::new(3.14159265359).to_string(), + "3.1415927".to_string() + ); + assert_eq!( + Float::new(-3.14159265359).to_string(), + "-3.1415927".to_string() + ); + } + + #[test] + fn test_parser() { + assert_eq!(Float::new(22.0), Float::from_str("22").unwrap()); + assert_eq!(Float::new(-22.0), Float::from_str("-22").unwrap()); + assert_eq!( + Float::new(3.14159265359), + Float::from_str("3.14159265359").unwrap() + ); + assert!(Float::from_str("1#").is_err()); + assert!(Float::from_str("NaN").is_err()); + assert!(Float::from_str("inf").is_err()); + assert!(Float::from_str("-inf").is_err()); + } + + #[test] + #[should_panic = "float must be finite: `inf`"] + fn test_new_infinite() { Float::new(::core::f32::INFINITY); } + + #[test] + #[should_panic = "float must be finite: `-inf`"] + fn test_new_neg_infinite() { Float::new(::core::f32::NEG_INFINITY); } + + #[test] + #[should_panic = "float must not be `NaN`"] + fn test_new_nan() { Float::new(::core::f32::NAN); } + + #[test] + fn test_partial_eq() { + assert_eq!(Float::new(1.1), 1.1); + } + + #[test] + fn test_as_f32() { + assert_eq!(Float::new(1.1).as_f32(), 1.1_f32); + } + + #[test] + fn test_from() { + assert_eq!(Float::from(-1_i8), Float::new(-1.0)); + assert_eq!(Float::from(1_u8), Float::new(1.0)); + assert_eq!(Float::from(-1_i16), Float::new(-1.0)); + assert_eq!(Float::from(1_u16), Float::new(1.0)); + } + + #[test] + fn test_try_from() { + assert_eq!(Float::try_from(1.1_f32).unwrap(), Float::new(1.1)); + assert_eq!(Float::try_from(-1.1_f32).unwrap(), Float::new(-1.1)); + + assert!(Float::try_from(::core::f32::INFINITY).is_err()); + assert!(Float::try_from(::core::f32::NAN).is_err()); + assert!(Float::try_from(::core::f32::NEG_INFINITY).is_err()); + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index 5bcb7e9..e0af60d 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -2,7 +2,6 @@ mod byte_range; mod channels; mod closed_captions; -mod decimal_floating_point; mod decryption_key; mod encryption_method; mod hdcp_level; @@ -12,14 +11,15 @@ mod key_format_versions; mod media_type; mod protocol_version; mod resolution; -mod signed_decimal_floating_point; mod stream_inf; mod value; +mod float; +mod ufloat; + pub use byte_range::*; pub use channels::*; pub use closed_captions::*; -pub(crate) use decimal_floating_point::*; pub use decryption_key::*; pub use encryption_method::*; pub use hdcp_level::*; @@ -29,6 +29,8 @@ pub use key_format_versions::*; pub use media_type::*; pub use protocol_version::*; pub use resolution::*; -pub(crate) use signed_decimal_floating_point::*; pub use stream_inf::*; pub use value::*; + +pub use float::Float; +pub use ufloat::UFloat; diff --git a/src/types/signed_decimal_floating_point.rs b/src/types/signed_decimal_floating_point.rs deleted file mode 100644 index 62aa32a..0000000 --- a/src/types/signed_decimal_floating_point.rs +++ /dev/null @@ -1,94 +0,0 @@ -use derive_more::Deref; -use derive_more::{Display, FromStr}; - -/// Signed decimal floating-point number. -/// -/// See: [4.2. Attribute Lists] -/// -/// [4.2. Attribute Lists]: https://tools.ietf.org/html/rfc8216#section-4.2 -#[derive(Deref, Default, Debug, Clone, Copy, PartialEq, PartialOrd, Display, FromStr)] -pub(crate) struct SignedDecimalFloatingPoint(f64); - -impl SignedDecimalFloatingPoint { - /// Makes a new [`SignedDecimalFloatingPoint`] instance. - /// - /// # Panics - /// - /// The given value must be finite, otherwise this function will panic! - pub fn new(value: f64) -> Self { - if value.is_infinite() || value.is_nan() { - panic!("Floating point value must be finite and not NaN!"); - } - Self(value) - } - - pub(crate) const fn from_f64_unchecked(value: f64) -> Self { Self(value) } - - /// Converts [`DecimalFloatingPoint`] to [`f64`]. - pub const fn as_f64(self) -> f64 { self.0 } -} - -#[cfg(test)] -mod tests { - use super::*; - use pretty_assertions::assert_eq; - - macro_rules! test_from { - ( $( $input:expr => $output:expr ),* ) => { - use ::core::convert::From; - - #[test] - fn test_from() { - $( - assert_eq!( - $input, - $output, - ); - )* - } - } - } - - test_from![ - SignedDecimalFloatingPoint::from(1_u8) => SignedDecimalFloatingPoint::new(1.0), - SignedDecimalFloatingPoint::from(1_i8) => SignedDecimalFloatingPoint::new(1.0), - SignedDecimalFloatingPoint::from(1_u16) => SignedDecimalFloatingPoint::new(1.0), - SignedDecimalFloatingPoint::from(1_i16) => SignedDecimalFloatingPoint::new(1.0), - SignedDecimalFloatingPoint::from(1_u32) => SignedDecimalFloatingPoint::new(1.0), - SignedDecimalFloatingPoint::from(1_i32) => SignedDecimalFloatingPoint::new(1.0), - SignedDecimalFloatingPoint::from(1.0_f32) => SignedDecimalFloatingPoint::new(1.0), - SignedDecimalFloatingPoint::from(1.0_f64) => SignedDecimalFloatingPoint::new(1.0) - ]; - - #[test] - fn test_display() { - assert_eq!( - SignedDecimalFloatingPoint::new(1.0).to_string(), - 1.0_f64.to_string() - ); - } - - #[test] - #[should_panic] - fn test_new_panic() { SignedDecimalFloatingPoint::new(::std::f64::INFINITY); } - - #[test] - fn test_parser() { - assert_eq!( - SignedDecimalFloatingPoint::new(1.0), - "1.0".parse::().unwrap() - ); - - assert!("garbage".parse::().is_err()); - } - - #[test] - fn test_as_f64() { - assert_eq!(SignedDecimalFloatingPoint::new(1.0).as_f64(), 1.0); - } - - #[test] - fn test_deref() { - assert_eq!(SignedDecimalFloatingPoint::from(0.1).floor(), 0.0); - } -} diff --git a/src/types/ufloat.rs b/src/types/ufloat.rs new file mode 100644 index 0000000..ad4d180 --- /dev/null +++ b/src/types/ufloat.rs @@ -0,0 +1,182 @@ +use core::convert::TryFrom; +use core::str::FromStr; + +use derive_more::{Deref, Display}; + +use crate::Error; + +/// This is a wrapper type around an [`f32`] that can not be constructed +/// with a negative float (ex. `-1.1`), [`NaN`], [`INFINITY`] or +/// [`NEG_INFINITY`]. +/// +/// [`NaN`]: core::f32::NaN +/// [`INFINITY`]: core::f32::INFINITY +/// [`NEG_INFINITY`]: core::f32::NEG_INFINITY +#[derive(Deref, Default, Debug, Copy, Clone, PartialEq, PartialOrd, Display)] +pub struct UFloat(f32); + +impl UFloat { + /// Makes a new [`UFloat`] from an [`f32`]. + /// + /// # Panics + /// + /// If the given float is negative, infinite or [`NaN`]. + /// + /// # Examples + /// + /// ``` + /// use hls_m3u8::types::UFloat; + /// + /// let float = UFloat::new(1.0); + /// ``` + /// + /// This would panic: + /// + /// ```should_panic + /// use hls_m3u8::types::UFloat; + /// + /// let float = UFloat::new(-1.0); + /// ``` + /// + /// [`NaN`]: core::f32::NAN + pub fn new(float: f32) -> Self { + if float.is_infinite() { + panic!("float must be finite: `{}`", float); + } + + if float.is_nan() { + panic!("float must not be `NaN`"); + } + + if float.is_sign_negative() { + panic!("float must be positive: `{}`", float); + } + + Self(float) + } + + /// Returns the underlying [`f32`]. + pub const fn as_f32(self) -> f32 { self.0 } +} + +impl FromStr for UFloat { + type Err = Error; + + fn from_str(input: &str) -> Result { + let float = f32::from_str(input).map_err(Error::parse_float)?; + Self::try_from(float) + } +} + +impl TryFrom for UFloat { + type Error = Error; + + fn try_from(float: f32) -> Result { + if float.is_infinite() { + return Err(Error::custom(format!("float must be finite: `{}`", float))); + } + + if float.is_nan() { + return Err(Error::custom("float must not be `NaN`")); + } + + if float.is_sign_negative() { + return Err(Error::custom(format!( + "float must be positive: `{}`", + float + ))); + } + + Ok(Self(float)) + } +} + +macro_rules! implement_from { + ( $( $type:tt ),+ ) => { + $( + impl ::core::convert::From<$type> for UFloat { + fn from(value: $type) -> Self { + Self(value as f32) + } + } + )+ + } +} + +implement_from!(u16, u8); + +// convenience implementation to compare f32 with a Float. +impl PartialEq for UFloat { + fn eq(&self, other: &f32) -> bool { &self.0 == other } +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn test_display() { + assert_eq!(UFloat::new(22.0).to_string(), "22".to_string()); + assert_eq!( + UFloat::new(3.14159265359).to_string(), + "3.1415927".to_string() + ); + } + + #[test] + fn test_parser() { + assert_eq!(UFloat::new(22.0), UFloat::from_str("22").unwrap()); + assert_eq!( + UFloat::new(3.14159265359), + UFloat::from_str("3.14159265359").unwrap() + ); + assert!(UFloat::from_str("1#").is_err()); + assert!(UFloat::from_str("-1.0").is_err()); + assert!(UFloat::from_str("NaN").is_err()); + assert!(UFloat::from_str("inf").is_err()); + assert!(UFloat::from_str("-inf").is_err()); + } + + #[test] + #[should_panic = "float must be positive: `-1.1`"] + fn test_new_negative() { UFloat::new(-1.1); } + + #[test] + #[should_panic = "float must be finite: `inf`"] + fn test_new_infinite() { UFloat::new(::core::f32::INFINITY); } + + #[test] + #[should_panic = "float must be finite: `-inf`"] + fn test_new_neg_infinite() { UFloat::new(::core::f32::NEG_INFINITY); } + + #[test] + #[should_panic = "float must not be `NaN`"] + fn test_new_nan() { UFloat::new(::core::f32::NAN); } + + #[test] + fn test_partial_eq() { + assert_eq!(UFloat::new(1.1), 1.1); + } + + #[test] + fn test_as_f32() { + assert_eq!(UFloat::new(1.1).as_f32(), 1.1_f32); + } + + #[test] + fn test_from() { + assert_eq!(UFloat::from(1_u8), UFloat::new(1.0)); + assert_eq!(UFloat::from(1_u16), UFloat::new(1.0)); + } + + #[test] + fn test_try_from() { + assert_eq!(UFloat::try_from(1.1_f32).unwrap(), UFloat::new(1.1)); + + assert!(UFloat::try_from(-1.1_f32).is_err()); + assert!(UFloat::try_from(::core::f32::INFINITY).is_err()); + assert!(UFloat::try_from(::core::f32::NAN).is_err()); + assert!(UFloat::try_from(::core::f32::NEG_INFINITY).is_err()); + } +} diff --git a/src/utils.rs b/src/utils.rs index 5f11764..989d029 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -11,27 +11,6 @@ macro_rules! required_version { } } -macro_rules! impl_from { - ( $($( $type:tt ),* => $target:path ),* ) => { - use ::core::convert::From; - - $( // repeat $target - $( // repeat $type - impl From<$type> for $target { - fn from(value: $type) -> Self { - Self::from_f64_unchecked(value.into()) - } - } - )* - )* - }; -} - -impl_from![ - u8, u16, u32 => crate::types::DecimalFloatingPoint, - u8, i8, u16, i16, u32, i32, f32, f64 => crate::types::SignedDecimalFloatingPoint -]; - pub(crate) fn parse_iv_from_str(input: &str) -> crate::Result<[u8; 16]> { if !(input.starts_with("0x") || input.starts_with("0X")) { return Err(Error::invalid_input());