diff --git a/Cargo.toml b/Cargo.toml index 6d682c9..77e0491 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,8 @@ edition = "2018" [package.metadata.docs.rs] features = ["std", "num-bigint-std", "serde"] -[dependencies] +[dependencies.paste] +version = "1.0" [dependencies.num-bigint] optional = true diff --git a/build.rs b/build.rs index df5e310..356f767 100644 --- a/build.rs +++ b/build.rs @@ -4,5 +4,14 @@ fn main() { println!("cargo:rustc-cfg=has_int_exp_fmt"); } + let std = if ac.probe_sysroot_crate("std") { + "std" + } else { + "core" + }; + if ac.probe_path(&format!("{}::convert::TryFrom", std)) { + autocfg::emit("has_try_from"); + } + autocfg::rerun_path("build.rs"); } diff --git a/src/from.rs b/src/from.rs new file mode 100644 index 0000000..ea417fc --- /dev/null +++ b/src/from.rs @@ -0,0 +1,84 @@ +use crate::{FromPrimitive, Ratio}; + +#[cfg(has_try_from)] +use crate::{approximate_float, approximate_float_unsigned}; +#[cfg(has_try_from)] +use core::convert::TryFrom; + +macro_rules! impl_try_from { + ( $($name:ty),* => $into:ty ; $approx:ident) => { + $( + #[cfg(has_try_from)] + impl TryFrom<$name> for Ratio<$into> { + type Error = (); + paste::paste! { + fn try_from(n: $name) -> Result { + <$into as FromPrimitive>::[](n) + .map(Ratio::from_integer) + .ok_or(()) + } + } + } + )* + + #[cfg(has_try_from)] + impl TryFrom for Ratio<$into> { + type Error = (); + fn try_from(n: f32) -> Result { + $approx(n, 10e-20, 30).ok_or(()) + } + } + + #[cfg(has_try_from)] + impl TryFrom for Ratio<$into> { + type Error = (); + fn try_from(n: f64) -> Result { + $approx(n, 10e-20, 30).ok_or(()) + } + } + + }; +} + +impl_try_from!(i8, u16, i16, u32, i32, u64, i64, u128, i128 => u8 ; approximate_float_unsigned); +impl_try_from!(u8, u16, i16, u32, i32, u64, i64, u128, i128 => i8 ; approximate_float); + +impl_try_from!(i16, u32, i32, u64, i64, u128, i128 => u16 ; approximate_float_unsigned); +impl_try_from!(u16, u32, i32, u64, i64, u128, i128 => i16 ; approximate_float); + +impl_try_from!(i32, u64, i64, u128, i128 => u32 ; approximate_float_unsigned); +impl_try_from!(u32, u64, i64, u128, i128 => i32 ; approximate_float); + +impl_try_from!(i64, u128, i128 => u64 ; approximate_float_unsigned); +impl_try_from!(u64, u128, i128 => i64 ; approximate_float); + +impl_try_from!(i128 => u128 ; approximate_float_unsigned); +impl_try_from!(u128 => i128 ; approximate_float); + +macro_rules! impl_from { + ( $($name:ty),* => $into:ty) => { + $( + impl From<$name> for Ratio<$into> { + paste::paste! { + fn from(n: $name) -> Self { + <$into as FromPrimitive>::[< from_ $name>](n) + .map(Ratio::from_integer) + .unwrap() + } + } + } + )* + }; +} + +impl_from!(u8, u16, u32, u64 => u128); +impl_from!(u8, i8, u16, i16, u32, i32, u64, i64 => i128); + +impl_from!(u8, u16, u32 => u64); +impl_from!(u8, i8, u16, i16, u32, i32 => i64); + +impl_from!(u8, u16 => u32); +impl_from!(u8, i8, u16, i16 => i32); + +impl_from!(u8 => u16); +impl_from!(u8, i8 => i16); diff --git a/src/lib.rs b/src/lib.rs index ee2f8d3..04bbad1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,7 @@ use num_traits::{ Pow, Signed, Zero, }; +mod from; mod pow; /// Represents the ratio between two numbers.