#![doc(hidden)]
#![unstable(feature = "flt2dec",
reason = "internal routines only exposed for testing",
issue = "0")]
use i16;
pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded};
pub mod estimator;
pub mod decoder;
pub mod strategy {
pub mod dragon;
pub mod grisu;
}
pub const MAX_SIG_DIGITS: usize = 17;
#[doc(hidden)]
pub fn round_up(d: &mut [u8], n: usize) -> Option<u8> {
match d[..n].iter().rposition(|&c| c != b'9') {
Some(i) => { d[i] += 1;
for j in i+1..n { d[j] = b'0'; }
None
}
None if n > 0 => { d[0] = b'1';
for j in 1..n { d[j] = b'0'; }
Some(b'0')
}
None => { Some(b'1')
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Part<'a> {
Zero(usize),
Num(u16),
Copy(&'a [u8]),
}
impl<'a> Part<'a> {
pub fn len(&self) -> usize {
match *self {
Part::Zero(nzeroes) => nzeroes,
Part::Num(v) => if v < 1_000 { if v < 10 { 1 } else if v < 100 { 2 } else { 3 } }
else { if v < 10_000 { 4 } else { 5 } },
Part::Copy(buf) => buf.len(),
}
}
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
let len = self.len();
if out.len() >= len {
match *self {
Part::Zero(nzeroes) => {
for c in &mut out[..nzeroes] { *c = b'0'; }
}
Part::Num(mut v) => {
for c in out[..len].iter_mut().rev() {
*c = b'0' + (v % 10) as u8;
v /= 10;
}
}
Part::Copy(buf) => {
out[..buf.len()].copy_from_slice(buf);
}
}
Some(len)
} else {
None
}
}
}
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct Formatted<'a> {
pub sign: &'static [u8],
pub parts: &'a [Part<'a>],
}
impl<'a> Formatted<'a> {
pub fn len(&self) -> usize {
let mut len = self.sign.len();
for part in self.parts {
len += part.len();
}
len
}
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
if out.len() < self.sign.len() { return None; }
out[..self.sign.len()].copy_from_slice(self.sign);
let mut written = self.sign.len();
for part in self.parts {
match part.write(&mut out[written..]) {
Some(len) => { written += len; }
None => { return None; }
}
}
Some(written)
}
}
fn digits_to_dec_str<'a>(buf: &'a [u8], exp: i16, frac_digits: usize,
parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] {
assert!(!buf.is_empty());
assert!(buf[0] > b'0');
assert!(parts.len() >= 4);
if exp <= 0 {
let minus_exp = -(exp as i32) as usize;
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(minus_exp);
parts[2] = Part::Copy(buf);
if frac_digits > buf.len() && frac_digits - buf.len() > minus_exp {
parts[3] = Part::Zero((frac_digits - buf.len()) - minus_exp);
&parts[..4]
} else {
&parts[..3]
}
} else {
let exp = exp as usize;
if exp < buf.len() {
parts[0] = Part::Copy(&buf[..exp]);
parts[1] = Part::Copy(b".");
parts[2] = Part::Copy(&buf[exp..]);
if frac_digits > buf.len() - exp {
parts[3] = Part::Zero(frac_digits - (buf.len() - exp));
&parts[..4]
} else {
&parts[..3]
}
} else {
parts[0] = Part::Copy(buf);
parts[1] = Part::Zero(exp - buf.len());
if frac_digits > 0 {
parts[2] = Part::Copy(b".");
parts[3] = Part::Zero(frac_digits);
&parts[..4]
} else {
&parts[..2]
}
}
}
}
fn digits_to_exp_str<'a>(buf: &'a [u8], exp: i16, min_ndigits: usize, upper: bool,
parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] {
assert!(!buf.is_empty());
assert!(buf[0] > b'0');
assert!(parts.len() >= 6);
let mut n = 0;
parts[n] = Part::Copy(&buf[..1]);
n += 1;
if buf.len() > 1 || min_ndigits > 1 {
parts[n] = Part::Copy(b".");
parts[n + 1] = Part::Copy(&buf[1..]);
n += 2;
if min_ndigits > buf.len() {
parts[n] = Part::Zero(min_ndigits - buf.len());
n += 1;
}
}
let exp = exp as i32 - 1; if exp < 0 {
parts[n] = Part::Copy(if upper { b"E-" } else { b"e-" });
parts[n + 1] = Part::Num(-exp as u16);
} else {
parts[n] = Part::Copy(if upper { b"E" } else { b"e" });
parts[n + 1] = Part::Num(exp as u16);
}
&parts[..n + 2]
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Sign {
Minus, MinusRaw, MinusPlus, MinusPlusRaw, }
fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static [u8] {
match (*decoded, sign) {
(FullDecoded::Nan, _) => b"",
(FullDecoded::Zero, Sign::Minus) => b"",
(FullDecoded::Zero, Sign::MinusRaw) => if negative { b"-" } else { b"" },
(FullDecoded::Zero, Sign::MinusPlus) => b"+",
(FullDecoded::Zero, Sign::MinusPlusRaw) => if negative { b"-" } else { b"+" },
(_, Sign::Minus) | (_, Sign::MinusRaw) => if negative { b"-" } else { b"" },
(_, Sign::MinusPlus) | (_, Sign::MinusPlusRaw) => if negative { b"-" } else { b"+" },
}
}
pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T,
sign: Sign, frac_digits: usize, _upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
assert!(parts.len() >= 4);
assert!(buf.len() >= MAX_SIG_DIGITS);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if frac_digits > 0 { parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
Formatted { sign: sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
Formatted { sign: sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
let (len, exp) = format_shortest(decoded, buf);
Formatted { sign: sign,
parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
}
}
}
pub fn to_shortest_exp_str<'a, T, F>(mut format_shortest: F, v: T,
sign: Sign, dec_bounds: (i16, i16), upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
assert!(parts.len() >= 6);
assert!(buf.len() >= MAX_SIG_DIGITS);
assert!(dec_bounds.0 <= dec_bounds.1);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 {
Part::Copy(b"0")
} else {
Part::Copy(if upper { b"0E0" } else { b"0e0" })
};
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Finite(ref decoded) => {
let (len, exp) = format_shortest(decoded, buf);
let vis_exp = exp as i32 - 1;
let parts = if dec_bounds.0 as i32 <= vis_exp && vis_exp < dec_bounds.1 as i32 {
digits_to_dec_str(&buf[..len], exp, 0, parts)
} else {
digits_to_exp_str(&buf[..len], exp, 0, upper, parts)
};
Formatted { sign: sign, parts: parts }
}
}
}
fn estimate_max_buf_len(exp: i16) -> usize {
21 + ((if exp < 0 { -12 } else { 5 } * exp as i32) as usize >> 4)
}
pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T,
sign: Sign, ndigits: usize, upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
assert!(parts.len() >= 6);
assert!(ndigits > 0);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if ndigits > 1 { parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(ndigits - 1);
parts[2] = Part::Copy(if upper { b"E0" } else { b"e0" });
Formatted { sign: sign, parts: &parts[..3] }
} else {
parts[0] = Part::Copy(if upper { b"0E0" } else { b"0e0" });
Formatted { sign: sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
let maxlen = estimate_max_buf_len(decoded.exp);
assert!(buf.len() >= ndigits || buf.len() >= maxlen);
let trunc = if ndigits < maxlen { ndigits } else { maxlen };
let (len, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN);
Formatted { sign: sign,
parts: digits_to_exp_str(&buf[..len], exp, ndigits, upper, parts) }
}
}
}
pub fn to_exact_fixed_str<'a, T, F>(mut format_exact: F, v: T,
sign: Sign, frac_digits: usize, _upper: bool,
buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a>
where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
assert!(parts.len() >= 4);
let (negative, full_decoded) = decode(v);
let sign = determine_sign(sign, &full_decoded, negative);
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
Formatted { sign: sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if frac_digits > 0 { parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
Formatted { sign: sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
Formatted { sign: sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
let maxlen = estimate_max_buf_len(decoded.exp);
assert!(buf.len() >= maxlen);
let limit = if frac_digits < 0x8000 { -(frac_digits as i16) } else { i16::MIN };
let (len, exp) = format_exact(decoded, &mut buf[..maxlen], limit);
if exp <= limit {
debug_assert_eq!(len, 0);
if frac_digits > 0 { parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
Formatted { sign: sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
Formatted { sign: sign, parts: &parts[..1] }
}
} else {
Formatted { sign: sign,
parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) }
}
}
}
}