add infallible conversions from other Fixed and from primitives
This commit is contained in:
parent
4e98c8ddd4
commit
266f2910ce
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
16
src/frac.rs
16
src/frac.rs
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -157,6 +157,7 @@ macro_rules! if_unsigned {
|
|||
|
||||
mod arith;
|
||||
mod cmp;
|
||||
mod convert;
|
||||
mod display;
|
||||
mod float;
|
||||
pub mod frac;
|
||||
|
|
Loading…
Reference in New Issue