implement infallible fixed to primitive conversions

This commit is contained in:
Trevor Spiteri 2019-01-26 21:16:20 +01:00
parent 266f2910ce
commit b71b41cd70
4 changed files with 103 additions and 16 deletions

View File

@ -33,8 +33,17 @@ fixed-point number lies in the range 0.5 ≤ *x* < 0.5 for signed
fixed-point numbers, and in the range 0 ≤ *x* < 1 for unsigned fixed-point numbers, and in the range 0 ≤ *x* < 1 for unsigned
fixed-point numbers. fixed-point numbers.
All lossless infallible conversions between fixed-point numbers and
integer primitives are implemented. That is, you can use [`From`] or
[`Into`] for the conversions that always work without losing any bits.
## Whats new ## Whats new
### Version 0.1.5 (unreleased)
* Lossless infallible conversions between fixed-point numbers and
integer primitives are now supported using [`From`] and [`Into`].
### Version 0.1.4 news (2018-11-29) ### Version 0.1.4 news (2018-11-29)
* Division is now implemented for [`FixedI128`] and [`FixedU128`]. * Division is now implemented for [`FixedI128`] and [`FixedU128`].
@ -129,5 +138,7 @@ additional terms or conditions.
[`FixedU32`]: https://docs.rs/fixed/0.1.4/fixed/struct.FixedU32.html [`FixedU32`]: https://docs.rs/fixed/0.1.4/fixed/struct.FixedU32.html
[`FixedU64`]: https://docs.rs/fixed/0.1.4/fixed/struct.FixedU64.html [`FixedU64`]: https://docs.rs/fixed/0.1.4/fixed/struct.FixedU64.html
[`FixedU8`]: https://docs.rs/fixed/0.1.4/fixed/struct.FixedU8.html [`FixedU8`]: https://docs.rs/fixed/0.1.4/fixed/struct.FixedU8.html
[`From`]: https://doc.rust-lang.org/nightly/std/convert/trait.From.html
[`Into`]: https://doc.rust-lang.org/nightly/std/convert/trait.Into.html
[`f16`]: https://docs.rs/half/^1/half/struct.f16.html [`f16`]: https://docs.rs/half/^1/half/struct.f16.html
[const generics]: https://github.com/rust-lang/rust/issues/44580 [const generics]: https://github.com/rust-lang/rust/issues/44580

View File

@ -5,6 +5,12 @@ modification, are permitted in any medium without royalty provided the
copyright notice and this notice are preserved. This file is offered copyright notice and this notice are preserved. This file is offered
as-is, without any warranty. --> as-is, without any warranty. -->
Version 0.1.5 (unreleased)
==========================
* Lossless infallible conversions between fixed-point numbers and
integer primitives are now supported using `From` and `Into`.
Version 0.1.4 (2018-11-29) Version 0.1.4 (2018-11-29)
========================== ==========================

View File

@ -101,7 +101,7 @@ convert! { (FixedU32, FixedI32, U32) -> (FixedU128, FixedI128, U128) }
convert! { (FixedU64, FixedI64, U64) -> (FixedU128, FixedI128, U128) } convert! { (FixedU64, FixedI64, U64) -> (FixedU128, FixedI128, U128) }
macro_rules! prim_convert { macro_rules! prim_to_fixed {
(($SrcU:ident, $SrcI:ident, $SrcBits:ident) -> ($DstU:ident, $DstI:ident, $DstBits:ident)) => { (($SrcU:ident, $SrcI:ident, $SrcBits:ident) -> ($DstU:ident, $DstI:ident, $DstBits:ident)) => {
// Condition: FracDst <= $DstBits - $SrcBits // Condition: FracDst <= $DstBits - $SrcBits
impl<FracDst> From<$SrcU> for $DstU<FracDst> impl<FracDst> From<$SrcU> for $DstU<FracDst>
@ -169,25 +169,85 @@ macro_rules! prim_convert {
}; };
} }
prim_convert! { (u8, i8) -> (FixedU8, FixedI8) } prim_to_fixed! { (u8, i8) -> (FixedU8, FixedI8) }
prim_convert! { (u8, i8, U8) -> (FixedU16, FixedI16, U16) } prim_to_fixed! { (u8, i8, U8) -> (FixedU16, FixedI16, U16) }
prim_convert! { (u8, i8, U8) -> (FixedU32, FixedI32, U32) } prim_to_fixed! { (u8, i8, U8) -> (FixedU32, FixedI32, U32) }
prim_convert! { (u8, i8, U8) -> (FixedU64, FixedI64, U64) } prim_to_fixed! { (u8, i8, U8) -> (FixedU64, FixedI64, U64) }
prim_convert! { (u8, i8, U8) -> (FixedU128, FixedI128, U128) } prim_to_fixed! { (u8, i8, U8) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u16, i16) -> (FixedU16, FixedI16) } prim_to_fixed! { (u16, i16) -> (FixedU16, FixedI16) }
prim_convert! { (u16, i16, U16) -> (FixedU32, FixedI32, U32) } prim_to_fixed! { (u16, i16, U16) -> (FixedU32, FixedI32, U32) }
prim_convert! { (u16, i16, U16) -> (FixedU64, FixedI64, U64) } prim_to_fixed! { (u16, i16, U16) -> (FixedU64, FixedI64, U64) }
prim_convert! { (u16, i16, U16) -> (FixedU128, FixedI128, U128) } prim_to_fixed! { (u16, i16, U16) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u32, i32) -> (FixedU32, FixedI32) } prim_to_fixed! { (u32, i32) -> (FixedU32, FixedI32) }
prim_convert! { (u32, i32, U32) -> (FixedU64, FixedI64, U64) } prim_to_fixed! { (u32, i32, U32) -> (FixedU64, FixedI64, U64) }
prim_convert! { (u32, i32, U32) -> (FixedU128, FixedI128, U128) } prim_to_fixed! { (u32, i32, U32) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u64, i64) -> (FixedU64, FixedI64) } prim_to_fixed! { (u64, i64) -> (FixedU64, FixedI64) }
prim_convert! { (u64, i64, U64) -> (FixedU128, FixedI128, U128) } prim_to_fixed! { (u64, i64, U64) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u128, i128) -> (FixedU128, FixedI128) } prim_to_fixed! { (u128, i128) -> (FixedU128, FixedI128) }
macro_rules! fixed_to_prim {
(($SrcU:ident, $SrcI:ident) -> ($DstU:ident, $DstI:ident)) => {
impl From<$SrcU<U0>> for $DstU {
#[inline]
fn from(src: $SrcU<U0>) -> $DstU {
src.to_bits()
}
}
impl From<$SrcI<U0>> for $DstI {
#[inline]
fn from(src: $SrcI<U0>) -> $DstI {
src.to_bits()
}
}
};
(($SrcU:ident, $SrcI:ident) -> wider ($DstU:ident, $DstI:ident)) => {
impl From<$SrcU<U0>> for $DstU {
#[inline]
fn from(src: $SrcU<U0>) -> $DstU {
src.to_bits().into()
}
}
impl From<$SrcI<U0>> for $DstI {
#[inline]
fn from(src: $SrcI<U0>) -> $DstI {
src.to_bits().into()
}
}
impl From<$SrcU<U0>> for $DstI {
#[inline]
fn from(src: $SrcU<U0>) -> $DstI {
src.to_bits().into()
}
}
};
}
fixed_to_prim! { (FixedU8, FixedI8) -> (u8, i8) }
fixed_to_prim! { (FixedU8, FixedI8) -> wider (u16, i16) }
fixed_to_prim! { (FixedU8, FixedI8) -> wider (u32, i32) }
fixed_to_prim! { (FixedU8, FixedI8) -> wider (u64, i64) }
fixed_to_prim! { (FixedU8, FixedI8) -> wider (u128, i128) }
fixed_to_prim! { (FixedU16, FixedI16) -> (u16, i16) }
fixed_to_prim! { (FixedU16, FixedI16) -> wider (u32, i32) }
fixed_to_prim! { (FixedU16, FixedI16) -> wider (u64, i64) }
fixed_to_prim! { (FixedU16, FixedI16) -> wider (u128, i128) }
fixed_to_prim! { (FixedU32, FixedI32) -> (u32, i32) }
fixed_to_prim! { (FixedU32, FixedI32) -> wider (u64, i64) }
fixed_to_prim! { (FixedU32, FixedI32) -> wider (u128, i128) }
fixed_to_prim! { (FixedU64, FixedI64) -> (u64, i64) }
fixed_to_prim! { (FixedU64, FixedI64) -> wider (u128, i128) }
fixed_to_prim! { (FixedU128, FixedI128) -> (u128, i128) }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -214,6 +274,7 @@ mod tests {
let l = L8::from_bits(val); let l = L8::from_bits(val);
assert_eq!(l, L8::from(val)); assert_eq!(l, L8::from(val));
assert_eq!(val, u8::from(l));
assert_eq!(LL16::from(l), LL16::from_bits(val16)); assert_eq!(LL16::from(l), LL16::from_bits(val16));
assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8)); assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8));
assert_eq!(LL128::from(l), LL128::from_bits(val128)); assert_eq!(LL128::from(l), LL128::from_bits(val128));
@ -248,6 +309,7 @@ mod tests {
let l = L8::from_bits(val); let l = L8::from_bits(val);
assert_eq!(l, L8::from(val)); assert_eq!(l, L8::from(val));
assert_eq!(val, i8::from(l));
assert_eq!(LL16::from(l), LL16::from_bits(val16)); assert_eq!(LL16::from(l), LL16::from_bits(val16));
assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8)); assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8));
assert_eq!(LL128::from(l), LL128::from_bits(val128)); assert_eq!(LL128::from(l), LL128::from_bits(val128));
@ -282,6 +344,7 @@ mod tests {
let l = L8::from_bits(val); let l = L8::from_bits(val);
assert_eq!(l, L8::from(val)); assert_eq!(l, L8::from(val));
assert_eq!(val, u8::from(l));
assert_eq!(LL16::from(l), LL16::from_bits(val16)); assert_eq!(LL16::from(l), LL16::from_bits(val16));
assert_eq!(LH16::from(l), LH16::from_bits(val16 << 7)); assert_eq!(LH16::from(l), LH16::from_bits(val16 << 7));
assert_eq!(LL128::from(l), LL128::from_bits(val128)); assert_eq!(LL128::from(l), LL128::from_bits(val128));

View File

@ -42,6 +42,10 @@ fixed-point number lies in the range 0.5 ≤ *x* < 0.5 for signed
fixed-point numbers, and in the range 0 *x* < 1 for unsigned fixed-point numbers, and in the range 0 *x* < 1 for unsigned
fixed-point numbers. fixed-point numbers.
All lossless infallible conversions between fixed-point numbers and
integer primitives are implemented. That is, you can use [`From`] or
[`Into`] for the conversions that always work without losing any bits.
## Quick example ## Quick example
```rust ```rust
@ -117,6 +121,7 @@ additional terms or conditions.
[LICENSE-APACHE]: https://www.apache.org/licenses/LICENSE-2.0 [LICENSE-APACHE]: https://www.apache.org/licenses/LICENSE-2.0
[LICENSE-MIT]: https://opensource.org/licenses/MIT [LICENSE-MIT]: https://opensource.org/licenses/MIT
[`FixedI128`]: struct.FixedI128.html [`FixedI128`]: struct.FixedI128.html
[`FixedI128`]: struct.FixedI128.html
[`FixedI16`]: struct.FixedI16.html [`FixedI16`]: struct.FixedI16.html
[`FixedI32`]: struct.FixedI32.html [`FixedI32`]: struct.FixedI32.html
[`FixedI64`]: struct.FixedI64.html [`FixedI64`]: struct.FixedI64.html
@ -126,6 +131,8 @@ additional terms or conditions.
[`FixedU32`]: struct.FixedU32.html [`FixedU32`]: struct.FixedU32.html
[`FixedU64`]: struct.FixedU64.html [`FixedU64`]: struct.FixedU64.html
[`FixedU8`]: struct.FixedU8.html [`FixedU8`]: struct.FixedU8.html
[`From`]: https://doc.rust-lang.org/nightly/std/convert/trait.From.html
[`Into`]: https://doc.rust-lang.org/nightly/std/convert/trait.Into.html
[`f16`]: https://docs.rs/half/^1/half/struct.f16.html [`f16`]: https://docs.rs/half/^1/half/struct.f16.html
[const generics]: https://github.com/rust-lang/rust/issues/44580 [const generics]: https://github.com/rust-lang/rust/issues/44580
*/ */