#![deny(
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
unreachable_pub,
unused_must_use,
unused_qualifications
)]
#![forbid(unsafe_code)]
#![no_std]
#[cfg(test)]
extern crate std;
#[rustfmt::skip]
#[allow(clippy::all, trivial_numeric_casts, unreachable_pub, unused_qualifications)]
mod core_num;
#[cfg(test)]
mod tests;
mod sealed {
pub trait Sealed {}
}
pub const PREFORMAT_SHORTEST_BUF_LEN: usize = core_num::flt2dec::MAX_SIG_DIGITS;
pub const PREFORMAT_EXACT_FIXED_BASE_BUF_LEN: usize = 826;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PreFormatted<'a> {
NaN,
Inf(bool),
Zero(bool),
Finite(bool, &'a [u8], i16),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct PreParsed<'a> {
pub sign: bool,
pub int_digits: &'a [u8],
pub frac_digits: &'a [u8],
pub exp: i16,
}
pub trait FloatExt: sealed::Sealed + Sized {
fn preformat_shortest(self, buf: &mut [u8]) -> PreFormatted<'_>;
fn preformat_exact_exp(self, buf: &mut [u8], num_digits: usize) -> PreFormatted<'_>;
fn preformat_exact_fixed(self, buf: &mut [u8], num_frac_digits: usize) -> PreFormatted<'_>;
fn from_preparsed(preparsed: PreParsed<'_>) -> Option<Self>;
}
mod generic {
use crate::core_num::flt2dec::decoder::DecodableFloat;
use crate::{core_num, PreFormatted, PreParsed};
pub(crate) fn preformat_shortest<T: DecodableFloat>(v: T, buf: &mut [u8]) -> PreFormatted<'_> {
let (sign, full_decoded) = core_num::flt2dec::decoder::decode(v);
match full_decoded {
core_num::flt2dec::decoder::FullDecoded::Nan => PreFormatted::NaN,
core_num::flt2dec::decoder::FullDecoded::Infinite => PreFormatted::Inf(sign),
core_num::flt2dec::decoder::FullDecoded::Zero => PreFormatted::Zero(sign),
core_num::flt2dec::decoder::FullDecoded::Finite(ref decoded) => {
let (digits, exp) =
core_num::flt2dec::strategy::grisu::format_shortest(decoded, buf);
PreFormatted::Finite(sign, &buf[..digits], exp)
}
}
}
pub(crate) fn preformat_exact_exp<T: DecodableFloat>(
v: T,
buf: &mut [u8],
ndigits: usize,
) -> PreFormatted<'_> {
let (sign, full_decoded) = core_num::flt2dec::decoder::decode(v);
match full_decoded {
core_num::flt2dec::decoder::FullDecoded::Nan => PreFormatted::NaN,
core_num::flt2dec::decoder::FullDecoded::Infinite => PreFormatted::Inf(sign),
core_num::flt2dec::decoder::FullDecoded::Zero => PreFormatted::Zero(sign),
core_num::flt2dec::decoder::FullDecoded::Finite(ref decoded) => {
let maxlen = core_num::flt2dec::estimate_max_buf_len(decoded.exp);
let trunc = if ndigits < maxlen { ndigits } else { maxlen };
let (digits, exp) = core_num::flt2dec::strategy::grisu::format_exact(
decoded,
&mut buf[..trunc],
i16::min_value(),
);
for chr in buf[digits..ndigits].iter_mut() {
*chr = b'0';
}
PreFormatted::Finite(sign, &buf[..ndigits], exp)
}
}
}
pub(crate) fn preformat_exact_fixed<T: DecodableFloat>(
v: T,
buf: &mut [u8],
frac_digits: usize,
) -> PreFormatted<'_> {
let (sign, full_decoded) = core_num::flt2dec::decoder::decode(v);
match full_decoded {
core_num::flt2dec::decoder::FullDecoded::Nan => PreFormatted::NaN,
core_num::flt2dec::decoder::FullDecoded::Infinite => PreFormatted::Inf(sign),
core_num::flt2dec::decoder::FullDecoded::Zero => PreFormatted::Zero(sign),
core_num::flt2dec::decoder::FullDecoded::Finite(ref decoded) => {
let maxlen = core_num::flt2dec::estimate_max_buf_len(decoded.exp);
let limit = if frac_digits < 0x8000 {
-(frac_digits as i16)
} else {
i16::min_value()
};
let (len, exp) = core_num::flt2dec::strategy::grisu::format_exact(
decoded,
&mut buf[..maxlen],
limit,
);
if exp <= limit {
PreFormatted::Zero(sign)
} else {
let ndigits = if exp > 0 {
let ndigits = frac_digits + exp as usize;
for c in buf[len..ndigits].iter_mut() {
*c = b'0';
}
ndigits
} else {
len
};
PreFormatted::Finite(sign, &buf[..ndigits], exp)
}
}
}
}
pub(crate) fn from_preparsed<T: core_num::dec2flt::rawfp::RawFloat>(
preparsed: PreParsed<'_>,
) -> Option<T> {
let parsed = core_num::dec2flt::parse::Decimal::new(
preparsed.int_digits,
preparsed.frac_digits,
i64::from(preparsed.exp),
);
let v = core_num::dec2flt::convert::<T>(parsed).ok()?;
if preparsed.sign {
Some(-v)
} else {
Some(v)
}
}
}
impl sealed::Sealed for f32 {}
impl sealed::Sealed for f64 {}
impl FloatExt for f32 {
fn preformat_shortest(self, buf: &mut [u8]) -> PreFormatted<'_> {
generic::preformat_shortest(self, buf)
}
fn preformat_exact_exp(self, buf: &mut [u8], num_digits: usize) -> PreFormatted<'_> {
generic::preformat_exact_exp(self, buf, num_digits)
}
fn preformat_exact_fixed(self, buf: &mut [u8], num_frac_digits: usize) -> PreFormatted<'_> {
generic::preformat_exact_fixed(self, buf, num_frac_digits)
}
fn from_preparsed(preparsed: PreParsed<'_>) -> Option<Self> {
generic::from_preparsed(preparsed)
}
}
impl FloatExt for f64 {
fn preformat_shortest(self, buf: &mut [u8]) -> PreFormatted<'_> {
generic::preformat_shortest(self, buf)
}
fn preformat_exact_exp(self, buf: &mut [u8], num_digits: usize) -> PreFormatted<'_> {
generic::preformat_exact_exp(self, buf, num_digits)
}
fn preformat_exact_fixed(self, buf: &mut [u8], num_frac_digits: usize) -> PreFormatted<'_> {
generic::preformat_exact_fixed(self, buf, num_frac_digits)
}
fn from_preparsed(preparsed: PreParsed<'_>) -> Option<Self> {
generic::from_preparsed(preparsed)
}
}