1#![no_std]
6
7extern crate dtoa;
8
9use core::fmt::Write;
10use core::{fmt, str};
11
12#[inline]
14pub fn write<W: Write, V: Floating>(dest: &mut W, value: V) -> DtoaResult {
15 Floating::write(value, dest)
16}
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
20pub struct Notation {
21 pub decimal_point: bool,
23 pub scientific: bool,
25}
26
27impl Notation {
28 fn integer() -> Self {
29 Notation {
30 decimal_point: false,
31 scientific: false,
32 }
33 }
34}
35
36pub type DtoaResult = Result<Notation, fmt::Error>;
38
39pub trait Floating : dtoa::Float {
40 fn write<W: Write>(self, dest: &mut W) -> DtoaResult;
41}
42
43impl Floating for f32 {
44 fn write<W: Write>(self, dest: &mut W) -> DtoaResult {
45 write_with_prec(dest, self, 6)
46 }
47}
48
49impl Floating for f64 {
50 fn write<W: Write>(self, dest: &mut W) -> DtoaResult {
51 write_with_prec(dest, self, 15)
52 }
53}
54
55fn write_with_prec<W, V>(dest: &mut W, value: V, prec: usize) -> DtoaResult
56where
57 W: Write,
58 V: dtoa::Float
59{
60 let mut buf = dtoa::Buffer::new();
61 let str = buf.format_finite(value);
62
63 const SCRATCH_LEN: usize = core::mem::size_of::<dtoa::Buffer>() + 1;
64 let mut scratch = [b'\0'; SCRATCH_LEN];
65 debug_assert!(str.len() < SCRATCH_LEN);
66 unsafe {
67 core::ptr::copy_nonoverlapping(str.as_bytes().as_ptr(), scratch.as_mut_ptr().offset(1), str.len());
68 }
69 let (result, notation) = restrict_prec(&mut scratch[0..str.len() + 1], prec);
70 dest.write_str(if cfg!(debug_assertions) {
71 str::from_utf8(result).unwrap()
72 } else {
73 unsafe { str::from_utf8_unchecked(result) }
75 })?;
76 Ok(notation)
77}
78
79fn restrict_prec(buf: &mut [u8], prec: usize) -> (&[u8], Notation) {
80 let len = buf.len();
81 debug_assert!(buf[0] == b'\0', "Caller must prepare an empty byte for us");
83 buf[0] = b'0';
84 let sign = match buf[1] {
86 s @ b'+' | s @ b'-' => {
87 buf[1] = b'0';
88 Some(s)
89 }
90 _ => None,
91 };
92 let mut pos_dot = None;
94 let mut pos_exp = None;
95 let mut prec_start = None;
96 for i in 1..len {
97 if buf[i] == b'.' {
98 debug_assert!(pos_dot.is_none());
99 pos_dot = Some(i);
100 } else if buf[i] == b'e' {
101 pos_exp = Some(i);
102 break;
104 } else if prec_start.is_none() && buf[i] != b'0' {
105 debug_assert!(buf[i] >= b'1' && buf[i] <= b'9');
106 prec_start = Some(i);
107 }
108 }
109 let prec_start = match prec_start {
110 Some(i) => i,
111 None => return (&buf[0..1], Notation::integer()),
113 };
114 let coeff_end = pos_exp.unwrap_or(len);
116 let pos_dot = pos_dot.unwrap_or(coeff_end);
119 let prec_end = {
121 let end = prec_start + prec;
122 if pos_dot > prec_start && pos_dot <= end {
123 end + 1
124 } else {
125 end
126 }
127 };
128 let mut new_coeff_end = coeff_end;
129 if prec_end < coeff_end {
130 let next_char = buf[prec_end];
132 new_coeff_end = prec_end;
133 if next_char >= b'5' {
134 for i in (0..prec_end).rev() {
135 if buf[i] == b'.' {
136 continue;
137 }
138 if buf[i] != b'9' {
139 buf[i] += 1;
140 new_coeff_end = i + 1;
141 break;
142 }
143 buf[i] = b'0';
144 }
145 }
146 }
147 if new_coeff_end < pos_dot {
148 for i in new_coeff_end..pos_dot {
151 buf[i] = b'0';
152 }
153 new_coeff_end = pos_dot;
154 } else {
155 for i in (0..new_coeff_end).rev() {
157 if buf[i] != b'0' {
158 if buf[i] == b'.' {
159 new_coeff_end = i;
160 }
161 break;
162 }
163 new_coeff_end = i;
164 }
165 }
166 let real_end = if let Some(pos_exp) = pos_exp {
168 let exp_len = len - pos_exp;
169 if new_coeff_end != pos_exp {
170 for i in 0..exp_len {
171 buf[new_coeff_end + i] = buf[pos_exp + i];
172 }
173 }
174 new_coeff_end + exp_len
175 } else {
176 new_coeff_end
177 };
178 let result = if let Some(sign) = sign {
180 if buf[1] == b'0' && buf[2] != b'.' {
181 buf[1] = sign;
182 &buf[1..real_end]
183 } else {
184 debug_assert!(buf[0] == b'0');
185 buf[0] = sign;
186 &buf[0..real_end]
187 }
188 } else {
189 if buf[0] == b'0' && buf[1] != b'.' {
190 &buf[1..real_end]
191 } else {
192 &buf[0..real_end]
193 }
194 };
195 let notation = Notation {
197 decimal_point: pos_dot < new_coeff_end,
198 scientific: pos_exp.is_some(),
199 };
200 (result, notation)
201}