add infallible conversions from other Fixed and from primitives

This commit is contained in:
Trevor Spiteri 2019-01-26 20:38:25 +01:00
parent 4e98c8ddd4
commit 266f2910ce
3 changed files with 306 additions and 8 deletions

297
src/convert.rs Normal file
View File

@ -0,0 +1,297 @@
// Copyright © 2018 Trevor Spiteri
// This library is free software: you can redistribute it and/or
// modify it under the terms of either
//
// * the Apache License, Version 2.0 or
// * the MIT License
//
// at your option.
//
// You should have recieved copies of the Apache License and the MIT
// License along with the library. If not, see
// <https://www.apache.org/licenses/LICENSE-2.0> and
// <https://opensource.org/licenses/MIT>.
use core::ops::{Add, Sub};
use frac::{IsGreaterOrEqual, IsLessOrEqual, True, Unsigned, U0, U1, U128, U16, U32, U64, U8};
use {
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
FixedU8,
};
macro_rules! convert {
(($SrcU:ident, $SrcI:ident, $SrcBits:ident) -> ($DstU:ident, $DstI:ident, $DstBits:ident)) => {
// Conditions: FracSrc <= FracDst <= FracSrc + ($DstBits - $SrcBits)
impl<FracSrc, FracDst, FracMax> From<$SrcU<FracSrc>> for $DstU<FracDst>
where
FracSrc: Unsigned
+ IsLessOrEqual<$SrcBits, Output = True>
+ Add<<$DstBits as Sub<$SrcBits>>::Output, Output = FracMax>,
FracDst: Unsigned
+ IsLessOrEqual<$DstBits, Output = True>
+ IsGreaterOrEqual<FracSrc, Output = True>
+ IsLessOrEqual<FracMax, Output = True>,
FracMax: Unsigned,
{
#[inline]
fn from(src: $SrcU<FracSrc>) -> $DstU<FracDst> {
let unshifted = $DstU::<FracDst>::from_bits(src.to_bits().into()).to_bits();
let shift = FracDst::to_u32() - FracSrc::to_u32();
$DstU::<FracDst>::from_bits(unshifted << shift)
}
}
// Conditions: FracSrc <= FracDst <= FracSrc + ($DstBits - $SrcBits)
impl<FracSrc, FracDst, FracMax> From<$SrcI<FracSrc>> for $DstI<FracDst>
where
FracSrc: Unsigned
+ IsLessOrEqual<$SrcBits, Output = True>
+ Add<<$DstBits as Sub<$SrcBits>>::Output, Output = FracMax>,
FracDst: Unsigned
+ IsLessOrEqual<$DstBits, Output = True>
+ IsGreaterOrEqual<FracSrc, Output = True>
+ IsLessOrEqual<FracMax, Output = True>,
FracMax: Unsigned,
{
#[inline]
fn from(src: $SrcI<FracSrc>) -> $DstI<FracDst> {
let unshifted = $DstI::<FracDst>::from_bits(src.to_bits().into()).to_bits();
let shift = FracDst::to_u32() - FracSrc::to_u32();
$DstI::<FracDst>::from_bits(unshifted << shift)
}
}
// Conditions: FracSrc <= FracDst <= FracSrc + ($DstBits - $SrcBits - 1)
impl<FracSrc, FracDst, FracMax> From<$SrcU<FracSrc>> for $DstI<FracDst>
where
FracSrc: Unsigned
+ IsLessOrEqual<$SrcBits, Output = True>
+ Add<
<<$DstBits as Sub<$SrcBits>>::Output as Sub<U1>>::Output,
Output = FracMax,
>,
FracDst: Unsigned
+ IsLessOrEqual<$DstBits, Output = True>
+ IsGreaterOrEqual<FracSrc, Output = True>
+ IsLessOrEqual<FracMax, Output = True>,
FracMax: Unsigned,
{
#[inline]
fn from(src: $SrcU<FracSrc>) -> $DstI<FracDst> {
let unshifted = $DstI::<FracDst>::from_bits(src.to_bits().into()).to_bits();
let shift = FracDst::to_u32() - FracSrc::to_u32();
$DstI::<FracDst>::from_bits(unshifted << shift)
}
}
};
}
convert! { (FixedU8, FixedI8, U8) -> (FixedU16, FixedI16, U16) }
convert! { (FixedU8, FixedI8, U8) -> (FixedU32, FixedI32, U32) }
convert! { (FixedU8, FixedI8, U8) -> (FixedU64, FixedI64, U64) }
convert! { (FixedU8, FixedI8, U8) -> (FixedU128, FixedI128, U128) }
convert! { (FixedU16, FixedI16, U16) -> (FixedU32, FixedI32, U32) }
convert! { (FixedU16, FixedI16, U16) -> (FixedU64, FixedI64, U64) }
convert! { (FixedU16, FixedI16, U16) -> (FixedU128, FixedI128, U128) }
convert! { (FixedU32, FixedI32, U32) -> (FixedU64, FixedI64, U64) }
convert! { (FixedU32, FixedI32, U32) -> (FixedU128, FixedI128, U128) }
convert! { (FixedU64, FixedI64, U64) -> (FixedU128, FixedI128, U128) }
macro_rules! prim_convert {
(($SrcU:ident, $SrcI:ident, $SrcBits:ident) -> ($DstU:ident, $DstI:ident, $DstBits:ident)) => {
// Condition: FracDst <= $DstBits - $SrcBits
impl<FracDst> From<$SrcU> for $DstU<FracDst>
where
FracDst: Unsigned
+ IsLessOrEqual<$DstBits, Output = True>
+ IsLessOrEqual<<$DstBits as Sub<$SrcBits>>::Output, Output = True>,
{
#[inline]
fn from(src: $SrcU) -> $DstU<FracDst> {
let unshifted = $DstU::<FracDst>::from_bits(src.into()).to_bits();
let shift = FracDst::to_u32();
$DstU::<FracDst>::from_bits(unshifted << shift)
}
}
// Condition: FracDst <= $DstBits - $SrcBits
impl<FracDst> From<$SrcI> for $DstI<FracDst>
where
FracDst: Unsigned
+ IsLessOrEqual<$DstBits, Output = True>
+ IsLessOrEqual<<$DstBits as Sub<$SrcBits>>::Output, Output = True>,
{
#[inline]
fn from(src: $SrcI) -> $DstI<FracDst> {
let unshifted = $DstI::<FracDst>::from_bits(src.into()).to_bits();
let shift = FracDst::to_u32();
$DstI::<FracDst>::from_bits(unshifted << shift)
}
}
// Condition: FracDst <= $DstBits - $SrcBits - 1
impl<FracDst> From<$SrcU> for $DstI<FracDst>
where
FracDst: Unsigned
+ IsLessOrEqual<$DstBits, Output = True>
+ IsLessOrEqual<
<<$DstBits as Sub<$SrcBits>>::Output as Sub<U1>>::Output,
Output = True,
>,
{
#[inline]
fn from(src: $SrcU) -> $DstI<FracDst> {
let unshifted = $DstI::<FracDst>::from_bits(src.into()).to_bits();
let shift = FracDst::to_u32();
$DstI::<FracDst>::from_bits(unshifted << shift)
}
}
};
(($SrcU:ident, $SrcI:ident) -> ($DstU:ident, $DstI:ident)) => {
impl From<$SrcU> for $DstU<U0> {
#[inline]
fn from(src: $SrcU) -> $DstU<U0> {
$DstU::<U0>::from_bits(src)
}
}
impl From<$SrcI> for $DstI<U0> {
#[inline]
fn from(src: $SrcI) -> $DstI<U0> {
$DstI::<U0>::from_bits(src)
}
}
};
}
prim_convert! { (u8, i8) -> (FixedU8, FixedI8) }
prim_convert! { (u8, i8, U8) -> (FixedU16, FixedI16, U16) }
prim_convert! { (u8, i8, U8) -> (FixedU32, FixedI32, U32) }
prim_convert! { (u8, i8, U8) -> (FixedU64, FixedI64, U64) }
prim_convert! { (u8, i8, U8) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u16, i16) -> (FixedU16, FixedI16) }
prim_convert! { (u16, i16, U16) -> (FixedU32, FixedI32, U32) }
prim_convert! { (u16, i16, U16) -> (FixedU64, FixedI64, U64) }
prim_convert! { (u16, i16, U16) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u32, i32) -> (FixedU32, FixedI32) }
prim_convert! { (u32, i32, U32) -> (FixedU64, FixedI64, U64) }
prim_convert! { (u32, i32, U32) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u64, i64) -> (FixedU64, FixedI64) }
prim_convert! { (u64, i64, U64) -> (FixedU128, FixedI128, U128) }
prim_convert! { (u128, i128) -> (FixedU128, FixedI128) }
#[cfg(test)]
mod tests {
use *;
#[test]
fn expanding_from_unsigned() {
type L8 = FixedU8<frac::U0>;
type LL16 = FixedU16<frac::U0>;
type LH16 = FixedU16<frac::U8>;
type LL128 = FixedU128<frac::U0>;
type LH128 = FixedU128<frac::U120>;
type H8 = FixedU8<frac::U8>;
type HL16 = FixedU16<frac::U8>;
type HH16 = FixedU16<frac::U16>;
type HL128 = FixedU128<frac::U8>;
type HH128 = FixedU128<frac::U128>;
let vals: &[u8] = &[0x00, 0x7f, 0x80, 0xff];
for &val in vals {
let val16 = u16::from(val);
let val128 = u128::from(val);
let l = L8::from_bits(val);
assert_eq!(l, L8::from(val));
assert_eq!(LL16::from(l), LL16::from_bits(val16));
assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8));
assert_eq!(LL128::from(l), LL128::from_bits(val128));
assert_eq!(LH128::from(l), LH128::from_bits(val128 << 120));
let h = H8::from_bits(val);
assert_eq!(HL16::from(h), HL16::from_bits(val16));
assert_eq!(HH16::from(h), HH16::from_bits(val16 << 8));
assert_eq!(HL128::from(h), HL128::from_bits(val128));
assert_eq!(HH128::from(h), HH128::from_bits(val128 << 120));
}
}
#[test]
fn expanding_from_signed() {
type L8 = FixedI8<frac::U0>;
type LL16 = FixedI16<frac::U0>;
type LH16 = FixedI16<frac::U8>;
type LL128 = FixedI128<frac::U0>;
type LH128 = FixedI128<frac::U120>;
type H8 = FixedI8<frac::U8>;
type HL16 = FixedI16<frac::U8>;
type HH16 = FixedI16<frac::U16>;
type HL128 = FixedI128<frac::U8>;
type HH128 = FixedI128<frac::U128>;
let vals: &[i8] = &[0x00, 0x7f, -0x80, -0x01];
for &val in vals {
let val16 = i16::from(val);
let val128 = i128::from(val);
let l = L8::from_bits(val);
assert_eq!(l, L8::from(val));
assert_eq!(LL16::from(l), LL16::from_bits(val16));
assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8));
assert_eq!(LL128::from(l), LL128::from_bits(val128));
assert_eq!(LH128::from(l), LH128::from_bits(val128 << 120));
let h = H8::from_bits(val);
assert_eq!(HL16::from(h), HL16::from_bits(val16));
assert_eq!(HH16::from(h), HH16::from_bits(val16 << 8));
assert_eq!(HL128::from(h), HL128::from_bits(val128));
assert_eq!(HH128::from(h), HH128::from_bits(val128 << 120));
}
}
#[test]
fn expanding_from_unsigned_to_signed() {
type L8 = FixedU8<frac::U0>;
type LL16 = FixedI16<frac::U0>;
type LH16 = FixedI16<frac::U7>;
type LL128 = FixedI128<frac::U0>;
type LH128 = FixedI128<frac::U119>;
type H8 = FixedU8<frac::U8>;
type HL16 = FixedI16<frac::U8>;
type HH16 = FixedI16<frac::U15>;
type HL128 = FixedI128<frac::U8>;
type HH128 = FixedI128<frac::U127>;
let vals: &[u8] = &[0x00, 0x7f, 0x80, 0xff];
for &val in vals {
let val16 = i16::from(val);
let val128 = i128::from(val);
let l = L8::from_bits(val);
assert_eq!(l, L8::from(val));
assert_eq!(LL16::from(l), LL16::from_bits(val16));
assert_eq!(LH16::from(l), LH16::from_bits(val16 << 7));
assert_eq!(LL128::from(l), LL128::from_bits(val128));
assert_eq!(LH128::from(l), LH128::from_bits(val128 << 119));
let h = H8::from_bits(val);
assert_eq!(HL16::from(h), HL16::from_bits(val16));
assert_eq!(HH16::from(h), HH16::from_bits(val16 << 7));
assert_eq!(HL128::from(h), HL128::from_bits(val128));
assert_eq!(HH128::from(h), HH128::from_bits(val128 << 119));
}
}
}

View File

@ -20,12 +20,12 @@ This module reexports items from the [*typenum* crate].
*/
pub use typenum::{
IsLessOrEqual, True, Unsigned, U0, U1, U10, U100, U101, U102, U103, U104, U105, U106, U107,
U108, U109, U11, U110, U111, U112, U113, U114, U115, U116, U117, U118, U119, U12, U120, U121,
U122, U123, U124, U125, U126, U127, U128, U13, U14, U15, U16, U17, U18, U19, U2, U20, U21, U22,
U23, U24, U25, U26, U27, U28, U29, U3, U30, U31, U32, U33, U34, U35, U36, U37, U38, U39, U4,
U40, U41, U42, U43, U44, U45, U46, U47, U48, U49, U5, U50, U51, U52, U53, U54, U55, U56, U57,
U58, U59, U6, U60, U61, U62, U63, U64, U65, U66, U67, U68, U69, U7, U70, U71, U72, U73, U74,
U75, U76, U77, U78, U79, U8, U80, U81, U82, U83, U84, U85, U86, U87, U88, U89, U9, U90, U91,
U92, U93, U94, U95, U96, U97, U98, U99,
IsGreaterOrEqual, IsLessOrEqual, True, Unsigned, U0, U1, U10, U100, U101, U102, U103, U104,
U105, U106, U107, U108, U109, U11, U110, U111, U112, U113, U114, U115, U116, U117, U118, U119,
U12, U120, U121, U122, U123, U124, U125, U126, U127, U128, U13, U14, U15, U16, U17, U18, U19,
U2, U20, U21, U22, U23, U24, U25, U26, U27, U28, U29, U3, U30, U31, U32, U33, U34, U35, U36,
U37, U38, U39, U4, U40, U41, U42, U43, U44, U45, U46, U47, U48, U49, U5, U50, U51, U52, U53,
U54, U55, U56, U57, U58, U59, U6, U60, U61, U62, U63, U64, U65, U66, U67, U68, U69, U7, U70,
U71, U72, U73, U74, U75, U76, U77, U78, U79, U8, U80, U81, U82, U83, U84, U85, U86, U87, U88,
U89, U9, U90, U91, U92, U93, U94, U95, U96, U97, U98, U99,
};

View File

@ -157,6 +157,7 @@ macro_rules! if_unsigned {
mod arith;
mod cmp;
mod convert;
mod display;
mod float;
pub mod frac;