1use crate::cbig::CBig;
8use dashu_base::ConversionError;
9use dashu_float::round::Round;
10use dashu_float::{FBig, Repr};
11use dashu_int::{IBig, UBig, Word};
12
13impl<R: Round, const B: Word> From<FBig<R, B>> for CBig<R, B> {
14 #[inline]
16 fn from(re: FBig<R, B>) -> Self {
17 let fctx = re.context();
18 Self {
19 re: re.into_repr(),
20 im: Repr::zero(),
21 context: crate::repr::Context(fctx),
22 }
23 }
24}
25
26impl<R: Round, const B: Word> From<UBig> for CBig<R, B> {
27 #[inline]
29 fn from(v: UBig) -> Self {
30 FBig::from(v).into()
31 }
32}
33
34impl<R: Round, const B: Word> From<IBig> for CBig<R, B> {
35 #[inline]
37 fn from(v: IBig) -> Self {
38 FBig::from(v).into()
39 }
40}
41
42impl<R: Round, const B: Word> TryFrom<CBig<R, B>> for FBig<R, B> {
43 type Error = ConversionError;
44
45 #[inline]
49 fn try_from(z: CBig<R, B>) -> Result<Self, Self::Error> {
50 if z.im.is_pos_zero() || z.im.is_neg_zero() {
51 Ok(FBig::from_repr(z.re, z.context.float()))
52 } else {
53 Err(ConversionError::LossOfPrecision)
54 }
55 }
56}
57
58impl<R: Round, const B: Word> TryFrom<CBig<R, B>> for IBig {
59 type Error = ConversionError;
60
61 #[inline]
65 fn try_from(z: CBig<R, B>) -> Result<Self, Self::Error> {
66 let re: FBig<R, B> = FBig::try_from(z)?;
67 IBig::try_from(re)
68 }
69}
70
71impl<R: Round, const B: Word> TryFrom<CBig<R, B>> for UBig {
72 type Error = ConversionError;
73
74 #[inline]
77 fn try_from(z: CBig<R, B>) -> Result<Self, Self::Error> {
78 let re: FBig<R, B> = FBig::try_from(z)?;
79 UBig::try_from(re)
80 }
81}
82
83macro_rules! impl_cbig_int_conv {
87 ($($t:ty)*) => {$(
88 impl<R: Round, const B: Word> From<$t> for CBig<R, B> {
89 #[inline]
90 fn from(v: $t) -> Self {
91 FBig::from(v).into()
92 }
93 }
94
95 impl<R: Round, const B: Word> TryFrom<CBig<R, B>> for $t {
96 type Error = ConversionError;
97
98 #[inline]
99 fn try_from(z: CBig<R, B>) -> Result<Self, Self::Error> {
100 let re: FBig<R, B> = FBig::try_from(z)?;
101 re.try_into()
102 }
103 }
104 )*};
105}
106impl_cbig_int_conv!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
107
108macro_rules! impl_cbig_float_conv {
112 ($($t:ty)*) => {$(
113 impl<R: Round> TryFrom<$t> for CBig<R, 2> {
114 type Error = ConversionError;
115
116 #[inline]
117 fn try_from(f: $t) -> Result<Self, Self::Error> {
118 Ok(CBig::from(FBig::try_from(f)?))
119 }
120 }
121
122 impl<R: Round> TryFrom<CBig<R, 2>> for $t {
123 type Error = ConversionError;
124
125 #[inline]
126 fn try_from(z: CBig<R, 2>) -> Result<Self, Self::Error> {
127 let re: FBig<R, 2> = FBig::try_from(z)?;
128 re.try_into()
129 }
130 }
131 )*};
132}
133impl_cbig_float_conv!(f32 f64);
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use dashu_float::round::mode;
139
140 type C = CBig<mode::HalfAway, 10>;
141 type F = FBig<mode::HalfAway, 10>;
142
143 #[test]
144 fn from_fbig_is_purely_real() {
145 let z = C::from(F::from(7));
146 assert!(z.im().is_pos_zero() || z.im().is_neg_zero());
147 assert_eq!(z.re().significand(), &7.into());
148 }
149
150 #[test]
151 fn from_integers() {
152 let z: C = UBig::from(5u32).into();
153 assert_eq!(z.re().significand(), &5.into());
154 let z: C = IBig::from(-3).into();
155 assert_eq!(z.re().significand(), &(-3i32).into());
156 }
157
158 #[test]
159 fn try_from_fbig_ok_iff_purely_real() {
160 let z = C::from_parts(7.into(), 0.into());
161 let re: F = F::try_from(z).unwrap();
162 assert_eq!(re.repr().significand(), &7.into());
163
164 let z = C::from_parts(3.into(), 4.into());
165 assert_eq!(F::try_from(z), Err(ConversionError::LossOfPrecision));
166 }
167
168 #[test]
169 fn try_from_ibig_composes() {
170 let z: C = IBig::from(9).into();
171 let i: IBig = IBig::try_from(z).unwrap();
172 assert_eq!(i, 9.into());
173
174 let z = C::from(F::from_parts(123.into(), -2)); assert_eq!(IBig::try_from(z), Err(ConversionError::LossOfPrecision));
177
178 let z = C::from_parts(9.into(), 1.into());
180 assert_eq!(IBig::try_from(z), Err(ConversionError::LossOfPrecision));
181 }
182
183 #[test]
184 fn try_from_ubig_composes() {
185 let z: C = IBig::from(9).into();
186 let u: UBig = UBig::try_from(z).unwrap();
187 assert_eq!(u, UBig::from(9u8));
188
189 let z: C = IBig::from(-9).into();
191 assert_eq!(UBig::try_from(z), Err(ConversionError::OutOfBounds));
192
193 let z = C::from(F::from_parts(123.into(), -2)); assert_eq!(UBig::try_from(z), Err(ConversionError::LossOfPrecision));
196
197 let z = C::from_parts(9.into(), 1.into());
199 assert_eq!(UBig::try_from(z), Err(ConversionError::LossOfPrecision));
200 }
201
202 #[test]
203 fn primitive_conversions() {
204 let z: C = 7u8.into();
206 assert_eq!(z.re().significand(), &7.into());
207 let z: C = (-3i8).into();
208 assert_eq!(z.re().significand(), &(-3i32).into());
209
210 let z = CBig::<mode::HalfAway, 2>::try_from(2.5f64).unwrap();
212 assert_eq!(z.re().significand(), &5.into()); assert!(CBig::<mode::HalfAway, 2>::try_from(f32::NAN).is_err());
214
215 assert_eq!(u8::try_from(C::from(9u8)), Ok(9u8));
217 assert_eq!(u8::try_from(C::from(-9i8)), Err(ConversionError::OutOfBounds));
218 assert_eq!(u8::try_from(C::from(300u16)), Err(ConversionError::OutOfBounds));
219 assert_eq!(i8::try_from(C::from(-9i8)), Ok(-9i8));
220 assert_eq!(
221 i8::try_from(C::from(F::from_parts(123.into(), -2))), Err(ConversionError::LossOfPrecision)
223 );
224
225 let z = CBig::<mode::HalfAway, 2>::try_from(2.5f64).unwrap();
227 assert_eq!(f64::try_from(z), Ok(2.5));
228 }
229}