use core::any::type_name;
use crate::{
binary::{
decode_combination_finite,
decode_significand_trailing_declets,
is_finite,
is_infinite,
is_nan,
is_sign_negative,
is_signaling_nan,
BinaryBuf,
},
convert::decimal_from_parsed,
num::{
Float,
Integer,
},
text::{
FiniteParser,
ParsedDecimal,
ParsedInfinity,
ParsedNan,
ParsedNanHeader,
StrTextBuf,
},
ConvertError,
OverflowError,
};
pub(crate) fn decimal_to_binary_float<F: Float, D: BinaryBuf>(
decimal: &D,
) -> Result<F, ConvertError> {
if is_finite(decimal) {
let (exp, msd) = decode_combination_finite(decimal);
let trailing_significand = decode_significand_trailing_declets(decimal);
let f = F::try_finite_from_ascii(
is_sign_negative(decimal),
Some(msd.get_ascii())
.into_iter()
.chain(trailing_significand.flatten()),
exp,
)
.ok_or_else(|| ConvertError::would_overflow(type_name::<F>()))?;
if f.is_finite() {
Ok(f)
}
else {
Err(ConvertError::would_overflow(type_name::<F>()))
}
} else if is_infinite(decimal) {
Ok(F::infinity(is_sign_negative(decimal)))
} else {
debug_assert!(is_nan(decimal));
let payload = decode_significand_trailing_declets(decimal);
let payload = F::NanPayload::try_from_ascii(false, payload.flatten())
.ok_or_else(|| ConvertError::would_overflow(type_name::<F>()))?;
Ok(F::nan(
is_sign_negative(decimal),
is_signaling_nan(decimal),
payload,
))
}
}
pub(crate) fn decimal_from_binary_float<D: BinaryBuf, F: Float + ryu::Float>(
float: F,
) -> Result<D, OverflowError> {
if float.is_finite() {
let mut buf = ryu::Buffer::new();
let f = buf.format_finite(float);
decimal_from_parsed(ParsedDecimal::Finite(
FiniteParser::parse_str(f).expect("f64 can always be parsed"),
))
} else if float.is_infinite() {
decimal_from_parsed(ParsedDecimal::<StrTextBuf>::Infinity(ParsedInfinity {
is_infinity_negative: float.is_sign_negative(),
}))
} else {
debug_assert!(float.is_nan());
let buf = F::TextWriter::default();
let (nan_buf, nan_payload) = if let Some(payload) = float.nan_payload() {
let payload = FiniteParser::parse(buf, payload.as_display())
.expect("integers can always be parsed");
(payload.finite_buf, Some(payload.finite_significand))
} else {
(buf, None)
};
decimal_from_parsed(ParsedDecimal::Nan(ParsedNan {
nan_buf,
nan_header: ParsedNanHeader {
is_nan_signaling: float.is_nan_signaling(),
is_nan_negative: float.is_sign_negative(),
},
nan_payload,
}))
}
}