add LosslessTry{From,Into} and immplement them for Fixed <-> Fixed
This commit is contained in:
parent
f23ddc6616
commit
bc5e01120f
12
README.md
12
README.md
|
@ -59,6 +59,10 @@ The conversions supported cover the following cases.
|
|||
numeric primitives are provided using the [`LossyFrom`] and
|
||||
[`LossyInto`] traits. The source can have more fractional bits
|
||||
than the destination.
|
||||
* Checked lossless conversions between fixed-point numbers and
|
||||
numeric primitives are provided using the [`LosslessTryFrom`] and
|
||||
[`LosslessTryInto`] traits. The source cannot have more fractional
|
||||
bits than the destination.
|
||||
* Checked conversions between fixed-point numbers and numeric
|
||||
primitives are provided using the [`FromFixed`] and [`ToFixed`]
|
||||
traits, or using the [`from_num`] and [`to_num`] methods and
|
||||
|
@ -77,14 +81,18 @@ The conversions supported cover the following cases.
|
|||
### Version 1.0.0 news (unreleased)
|
||||
|
||||
* The crate now requires rustc version 1.43.0 or later.
|
||||
* All deprecated items were removed.
|
||||
* The [`LosslessTryFrom`][ltf-1-0] and [`LosslessTryInto`][lti-1-0]
|
||||
traits were added.
|
||||
* The [`PHI`][phi-1-0] and [`FRAC_1_PHI`][f1phi-1-0] constants were
|
||||
added to the [`consts`][cons-1-0] module and as
|
||||
[associated constants][f-phi-1-0] for fixed-point types.
|
||||
* All deprecated items were removed.
|
||||
|
||||
[cons-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/consts/index.html
|
||||
[f-phi-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#associatedconstant.PHI
|
||||
[f1phi-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/consts/constant.FRAC_1_PHI.html
|
||||
[ltf-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.LosslessTryFrom.html
|
||||
[lti-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.LosslessTryInto.html
|
||||
[phi-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/consts/constant.PHI.html
|
||||
|
||||
### Version 0.5.6 news (2020-05-01)
|
||||
|
@ -254,6 +262,8 @@ additional terms or conditions.
|
|||
[`I4F12`]: https://docs.rs/fixed/0.5.6/fixed/types/type.I4F12.html
|
||||
[`I4F4`]: https://docs.rs/fixed/0.5.6/fixed/types/type.I4F4.html
|
||||
[`Into`]: https://doc.rust-lang.org/nightly/core/convert/trait.Into.html
|
||||
[`LosslessTryFrom`]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.LosslessTryFrom.html
|
||||
[`LosslessTryInto`]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.LosslessTryInto.html
|
||||
[`LossyFrom`]: https://docs.rs/fixed/0.5.6/fixed/traits/trait.LossyFrom.html
|
||||
[`LossyInto`]: https://docs.rs/fixed/0.5.6/fixed/traits/trait.LossyInto.html
|
||||
[`LowerHex`]: https://doc.rust-lang.org/nightly/core/fmt/trait.LowerHex.html
|
||||
|
|
|
@ -9,14 +9,18 @@ Version 1.0.0 (unreleased)
|
|||
==========================
|
||||
|
||||
* The crate now requires rustc version 1.43.0 or later.
|
||||
* All deprecated items were removed.
|
||||
* The [`LosslessTryFrom`][ltf-1-0] and [`LosslessTryInto`][lti-1-0]
|
||||
traits were added.
|
||||
* The [`PHI`][phi-1-0] and [`FRAC_1_PHI`][f1phi-1-0] constants were
|
||||
added to the [`consts`][cons-1-0] module and as
|
||||
[associated constants][f-phi-1-0] for fixed-point types.
|
||||
* All deprecated items were removed.
|
||||
|
||||
[cons-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/consts/index.html
|
||||
[f-phi-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#associatedconstant.PHI
|
||||
[f1phi-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/consts/constant.FRAC_1_PHI.html
|
||||
[ltf-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.LosslessTryFrom.html
|
||||
[lti-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/traits/trait.LosslessTryInto.html
|
||||
[phi-1-0]: https://tspiteri.gitlab.io/fixed/dev/fixed/consts/constant.PHI.html
|
||||
|
||||
Version 0.5.6 (2020-05-01)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
use crate::{
|
||||
helpers::IntHelper,
|
||||
traits::LossyFrom,
|
||||
traits::{LosslessTryFrom, LossyFrom},
|
||||
types::extra::{
|
||||
Diff, IsLessOrEqual, LeEqU128, LeEqU16, LeEqU32, LeEqU64, LeEqU8, True, U0, U1, U127, U128,
|
||||
U15, U16, U31, U32, U63, U64, U7, U8,
|
||||
|
@ -91,10 +91,47 @@ macro_rules! convert {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! convert_lossless {
|
||||
(
|
||||
($Src:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
|
||||
($Dst:ident, $DstBits:ident, $DstLeEqU:ident)
|
||||
) => {
|
||||
// lossless because Src::FRAC_NBITS <= Dst::FRAC_NBITS
|
||||
impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LosslessTryFrom<$Src<FracSrc>>
|
||||
for $Dst<FracDst>
|
||||
where
|
||||
FracSrc: IsLessOrEqual<FracDst, Output = True>,
|
||||
{
|
||||
/// Converts a fixed-pint number.
|
||||
///
|
||||
/// This conversion may fail (fallible) but does not lose
|
||||
/// precision (lossless).
|
||||
#[inline]
|
||||
fn lossless_try_from(src: $Src<FracSrc>) -> Option<Self> {
|
||||
src.checked_to_num()
|
||||
}
|
||||
}
|
||||
};
|
||||
($Src:ident, $SrcBits:ident, $SrcLeEqU:ident) => {
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI8, U8, LeEqU8) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI16, U16, LeEqU16) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI32, U32, LeEqU32) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI64, U64, LeEqU64) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI128, U128, LeEqU128) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU8, U8, LeEqU8) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU16, U16, LeEqU16) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU32, U32, LeEqU32) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU64, U64, LeEqU64) }
|
||||
convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU128, U128, LeEqU128) }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! convert_lossy {
|
||||
(
|
||||
($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
|
||||
($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)) => {
|
||||
($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
|
||||
) => {
|
||||
// unsigned -> unsigned, infallible because Src::INT_NBITS <= Dst::INT_NBITS
|
||||
impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstU<FracDst>
|
||||
where
|
||||
$SrcBits: Sub<FracSrc>,
|
||||
|
@ -113,6 +150,7 @@ macro_rules! convert_lossy {
|
|||
}
|
||||
}
|
||||
|
||||
// signed -> signed, infallible because Src::INT_NBITS <= Dst::INT_NBITS
|
||||
impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcI<FracSrc>> for $DstI<FracDst>
|
||||
where
|
||||
$SrcBits: Sub<FracSrc>,
|
||||
|
@ -131,6 +169,7 @@ macro_rules! convert_lossy {
|
|||
}
|
||||
}
|
||||
|
||||
// signed -> signed, infallible because Src::INT_NBITS <= Dst::INT_NBITS - 1
|
||||
impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstI<FracDst>
|
||||
where
|
||||
$SrcBits: Sub<FracSrc>,
|
||||
|
@ -182,6 +221,17 @@ convert! { (FixedU32, FixedI32, U32, LeEqU32) -> (FixedU128, FixedI128, U128, U1
|
|||
|
||||
convert! { (FixedU64, FixedI64, U64, LeEqU64) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
|
||||
|
||||
convert_lossless! { FixedI8, U8, LeEqU8 }
|
||||
convert_lossless! { FixedI16, U16, LeEqU16 }
|
||||
convert_lossless! { FixedI32, U32, LeEqU32 }
|
||||
convert_lossless! { FixedI64, U64, LeEqU64 }
|
||||
convert_lossless! { FixedI128, U128, LeEqU128 }
|
||||
convert_lossless! { FixedU8, U8, LeEqU8 }
|
||||
convert_lossless! { FixedU16, U16, LeEqU16 }
|
||||
convert_lossless! { FixedU32, U32, LeEqU32 }
|
||||
convert_lossless! { FixedU64, U64, LeEqU64 }
|
||||
convert_lossless! { FixedU128, U128, LeEqU128 }
|
||||
|
||||
convert_lossy! { FixedU8, FixedI8, U8, LeEqU8 }
|
||||
convert_lossy! { FixedU16, FixedI16, U16, LeEqU16 }
|
||||
convert_lossy! { FixedU32, FixedI32, U32, LeEqU32 }
|
||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -68,6 +68,10 @@ The conversions supported cover the following cases.
|
|||
numeric primitives are provided using the [`LossyFrom`] and
|
||||
[`LossyInto`] traits. The source can have more fractional bits
|
||||
than the destination.
|
||||
* Checked lossless conversions between fixed-point numbers and
|
||||
numeric primitives are provided using the [`LosslessTryFrom`] and
|
||||
[`LosslessTryInto`] traits. The source cannot have more fractional
|
||||
bits than the destination.
|
||||
* Checked conversions between fixed-point numbers and numeric
|
||||
primitives are provided using the [`FromFixed`] and [`ToFixed`]
|
||||
traits, or using the [`from_num`] and [`to_num`] methods and
|
||||
|
@ -218,6 +222,8 @@ additional terms or conditions.
|
|||
[`I4F12`]: types/type.I4F12.html
|
||||
[`I4F4`]: types/type.I4F4.html
|
||||
[`Into`]: https://doc.rust-lang.org/nightly/core/convert/trait.Into.html
|
||||
[`LosslessTryFrom`]: traits/trait.LosslessTryFrom.html
|
||||
[`LosslessTryInto`]: traits/trait.LosslessTryInto.html
|
||||
[`LossyFrom`]: traits/trait.LossyFrom.html
|
||||
[`LossyInto`]: traits/trait.LossyInto.html
|
||||
[`LowerHex`]: https://doc.rust-lang.org/nightly/core/fmt/trait.LowerHex.html
|
||||
|
@ -303,7 +309,9 @@ use core::{
|
|||
///
|
||||
/// [prelude]: https://doc.rust-lang.org/nightly/std/prelude/index.html
|
||||
pub mod prelude {
|
||||
pub use crate::traits::{FromFixed, LossyFrom, LossyInto, ToFixed};
|
||||
pub use crate::traits::{
|
||||
FromFixed, LosslessTryFrom, LosslessTryInto, LossyFrom, LossyInto, ToFixed,
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -1153,6 +1153,70 @@ pub trait FixedUnsigned: Fixed {
|
|||
fn checked_next_power_of_two(self) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// This trait provides lossless conversions that might be fallible.
|
||||
///
|
||||
/// This trait is implemented for conversions between integer
|
||||
/// primitives, floating-point primitives and fixed-point numbers.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use fixed::traits::LosslessTryFrom;
|
||||
/// use fixed::types::{I4F12, I24F8};
|
||||
/// // original is 0x000001.23, lossless is 0x1.230
|
||||
/// let original = I24F8::from_bits(0x0000_0123);
|
||||
/// let lossless = I4F12::lossless_try_from(original);
|
||||
/// assert_eq!(lossless, Some(I4F12::from_bits(0x1230)));
|
||||
/// // too_large is 0x000012.34, 0x12.340 does not fit in I4F12
|
||||
/// let too_large = I24F8::from_bits(0x0000_1234);
|
||||
/// let overflow = I4F12::lossless_try_from(too_large);
|
||||
/// assert_eq!(overflow, None);
|
||||
/// ```
|
||||
pub trait LosslessTryFrom<Src>: Sized {
|
||||
/// Performs the conversion.
|
||||
fn lossless_try_from(src: Src) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// This trait provides lossless conversions that might be fallible.
|
||||
/// This is the reciprocal of [`LosslessTryFrom`].
|
||||
///
|
||||
/// Usually [`LosslessTryFrom`] should be implemented instead of this
|
||||
/// trait; there is a blanket implementation which provides this trait
|
||||
/// when [`LosslessTryFrom`] is implemented (similar to [`Into`] and
|
||||
/// [`From`]).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use fixed::traits::LosslessTryInto;
|
||||
/// use fixed::types::{I4F12, I24F8};
|
||||
/// // original is 0x000001.23, lossless is 0x1.230
|
||||
/// let original = I24F8::from_bits(0x0000_0123);
|
||||
/// let lossless: Option<I4F12> = original.lossless_try_into();
|
||||
/// assert_eq!(lossless, Some(I4F12::from_bits(0x1230)));
|
||||
/// // too_large is 0x000012.34, 0x12.340 does not fit in I4F12
|
||||
/// let too_large = I24F8::from_bits(0x0000_1234);
|
||||
/// let overflow: Option<I4F12> = too_large.lossless_try_into();
|
||||
/// assert_eq!(overflow, None);
|
||||
/// ```
|
||||
///
|
||||
/// [`From`]: https://doc.rust-lang.org/nightly/core/convert/trait.From.html
|
||||
/// [`Into`]: https://doc.rust-lang.org/nightly/core/convert/trait.Into.html
|
||||
/// [`LosslessTryFrom`]: trait.LosslessTryFrom.html
|
||||
pub trait LosslessTryInto<Dst> {
|
||||
/// Performs the conversion.
|
||||
fn lossless_try_into(self) -> Option<Dst>;
|
||||
}
|
||||
|
||||
impl<Src, Dst> LosslessTryInto<Dst> for Src
|
||||
where
|
||||
Dst: LosslessTryFrom<Src>,
|
||||
{
|
||||
fn lossless_try_into(self) -> Option<Dst> {
|
||||
Dst::lossless_try_from(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait provides infallible conversions that might be lossy.
|
||||
///
|
||||
/// This trait is implemented for conversions between integer
|
||||
|
@ -1162,11 +1226,11 @@ pub trait FixedUnsigned: Fixed {
|
|||
///
|
||||
/// ```rust
|
||||
/// use fixed::traits::LossyFrom;
|
||||
/// use fixed::types::{I12F4, I4F60};
|
||||
/// // original is 0x1.234
|
||||
/// let original = I4F60::from_bits(0x1234i64 << (60 - 12));
|
||||
/// use fixed::types::{I12F4, I8F24};
|
||||
/// // original is 0x12.345678, lossy is 0x012.3
|
||||
/// let original = I8F24::from_bits(0x1234_5678);
|
||||
/// let lossy = I12F4::lossy_from(original);
|
||||
/// assert_eq!(lossy, I12F4::from_bits(0x0012));
|
||||
/// assert_eq!(lossy, I12F4::from_bits(0x0123));
|
||||
/// ```
|
||||
pub trait LossyFrom<Src> {
|
||||
/// Performs the conversion.
|
||||
|
@ -1184,11 +1248,11 @@ pub trait LossyFrom<Src> {
|
|||
///
|
||||
/// ```rust
|
||||
/// use fixed::traits::LossyInto;
|
||||
/// use fixed::types::{I12F4, I4F12};
|
||||
/// // original is 0x1.234
|
||||
/// let original = I4F12::from_bits(0x1234);
|
||||
/// use fixed::types::{I12F4, I8F24};
|
||||
/// // original is 0x12.345678, lossy is 0x012.3
|
||||
/// let original = I8F24::from_bits(0x1234_5678);
|
||||
/// let lossy: I12F4 = original.lossy_into();
|
||||
/// assert_eq!(lossy, I12F4::from_bits(0x0012));
|
||||
/// assert_eq!(lossy, I12F4::from_bits(0x0123));
|
||||
/// ```
|
||||
///
|
||||
/// [`From`]: https://doc.rust-lang.org/nightly/core/convert/trait.From.html
|
||||
|
|
Loading…
Reference in New Issue