1use crate::{
6 binary::{
7 decode_combination_finite,
8 decode_significand_trailing_declets,
9 encode_combination_finite,
10 encode_combination_infinity,
11 encode_combination_nan,
12 encode_significand_trailing_digits,
13 is_finite,
14 is_infinite,
15 is_nan,
16 is_quiet_nan,
17 is_sign_negative,
18 BinaryBuf,
19 BinaryExponent,
20 },
21 num::Integer,
22 text::{
23 ParsedDecimal,
24 ParsedDecimalPoint,
25 ParsedFinite,
26 ParsedInfinity,
27 ParsedNan,
28 ParsedNanHeader,
29 ParsedSignificand,
30 TextBuf,
31 },
32 OverflowError,
33};
34use core::{
35 fmt,
36 str,
37};
38
39mod from_binary_float;
40mod from_int;
41mod from_str;
42
43pub(crate) use self::{
44 from_binary_float::*,
45 from_int::*,
46 from_str::*,
47};
48
49pub(crate) fn decimal_from_parsed<D: BinaryBuf, T: TextBuf>(
53 parsed: ParsedDecimal<T>,
54) -> Result<D, OverflowError> {
55 match parsed {
56 ParsedDecimal::Finite(ParsedFinite {
58 finite_buf,
59 finite_significand:
60 ParsedSignificand {
61 significand_is_negative,
62 significand_range,
63 decimal_point,
64 },
65 finite_exponent,
66 }) => {
67 let buf = finite_buf.get_ascii();
68
69 let unbiased_exponent = match finite_exponent {
71 Some(exponent) => D::try_exponent_from_ascii(
76 exponent.exponent_is_negative,
77 buf[exponent.exponent_range].iter().copied(),
78 )?,
79 None => D::default_exponent(),
81 };
82
83 match decimal_point {
84 Some(ParsedDecimalPoint {
86 decimal_point_range,
87 }) => {
88 let integer_range = significand_range.start..decimal_point_range.start;
89 let fractional_range = decimal_point_range.end..significand_range.end;
90
91 let integer_digits = &buf[integer_range];
92 let fractional_digits = &buf[fractional_range];
93
94 let unbiased_integer_exponent =
104 unbiased_exponent.lower(fractional_digits.len());
105
106 let mut buf = D::try_with_at_least_precision(
109 integer_digits.len() + fractional_digits.len(),
110 Some(&unbiased_integer_exponent),
111 )?;
112
113 let msd = encode_significand_trailing_digits(
114 &mut buf,
115 [integer_digits, fractional_digits],
116 );
117
118 encode_combination_finite(
119 &mut buf,
120 significand_is_negative,
121 unbiased_integer_exponent,
122 msd,
123 );
124
125 Ok(buf)
126 }
127 None => {
129 let integer_range = significand_range;
130 let integer_digits = &buf[integer_range];
131
132 let mut buf = D::try_with_at_least_precision(
135 integer_digits.len(),
136 Some(&unbiased_exponent),
137 )?;
138
139 let msd = encode_significand_trailing_digits(&mut buf, [integer_digits]);
140
141 encode_combination_finite(
142 &mut buf,
143 significand_is_negative,
144 unbiased_exponent,
145 msd,
146 );
147
148 Ok(buf)
149 }
150 }
151 }
152 ParsedDecimal::Infinity(ParsedInfinity {
154 is_infinity_negative,
155 }) => {
156 let mut buf = D::try_with_at_least_storage_width_bytes(4)
159 .expect("infinity will always fit in the minimal sized buffer");
160
161 encode_combination_infinity(&mut buf, is_infinity_negative);
162
163 Ok(buf)
164 }
165 ParsedDecimal::Nan(ParsedNan {
167 nan_buf,
168 nan_header:
169 ParsedNanHeader {
170 is_nan_signaling,
171 is_nan_negative,
172 },
173 nan_payload,
174 }) => {
175 if let Some(ParsedSignificand {
179 significand_range, ..
180 }) = nan_payload
181 {
182 let payload_buf = nan_buf.get_ascii();
183
184 let mut buf = D::try_with_at_least_precision(significand_range.len() + 1, None)?;
185
186 encode_significand_trailing_digits(&mut buf, [&payload_buf[significand_range]]);
187
188 encode_combination_nan(&mut buf, is_nan_negative, is_nan_signaling);
189
190 Ok(buf)
191 }
192 else {
195 let mut buf = D::try_with_at_least_storage_width_bytes(4)
196 .expect("a NaN with no payload will always fit in the minimal sized buffer");
197
198 encode_combination_nan(&mut buf, is_nan_negative, is_nan_signaling);
199
200 Ok(buf)
201 }
202 }
203 }
204}
205
206pub(crate) fn decimal_to_fmt<D: BinaryBuf>(
210 decimal: &D,
211 mut out: impl fmt::Write,
212) -> Result<(), fmt::Error> {
213 if is_sign_negative(decimal) {
215 out.write_char('-')?;
216 }
217
218 if is_finite(decimal) {
220 let mut written = 0;
221
222 let (exponent, msd) = decode_combination_finite(decimal);
223 let msd = msd.get_ascii();
224
225 let mut declets = decode_significand_trailing_declets(decimal);
233
234 match exponent.to_i32() {
235 Some(0) => {
237 write_all_as_integer(
238 skip_leading_zeroes(msd, &mut declets),
239 declets,
240 &mut written,
241 &mut out,
242 )?;
243 }
244 Some(exponent) if exponent.is_negative() => {
246 let skipped = skip_leading_zeroes(msd, &mut declets);
248
249 let non_zero_digits =
254 adjusted_precision_digits_with_msd_declet(decimal) - skipped.skipped;
255
256 match non_zero_digits
259 .try_into()
260 .map(|non_zero_digits: i32| {
261 non_zero_digits + exponent
268 })
269 .ok()
270 {
271 Some(integer_digits) if integer_digits > 0 => {
273 let total_integer_digits = integer_digits as usize;
274
275 let mut written_decimal_point = false;
277
278 if let Some((declet, idx)) = skipped.partial_declet {
279 written_decimal_point = write_decimal_digits(
280 &declet[idx..],
281 total_integer_digits,
282 &mut written,
283 &mut out,
284 )?;
285 }
286
287 while !written_decimal_point {
288 written_decimal_point = write_decimal_digits(
289 &declets
290 .next()
291 .expect("ran out of digits before the decimal point"),
292 total_integer_digits,
293 &mut written,
294 &mut out,
295 )?;
296 }
297
298 for declet in declets {
300 write_declet(declet, &mut written, &mut out)?;
301 }
302 }
303 Some(leading_zeroes) => {
305 debug_assert!(leading_zeroes == 0 || leading_zeroes.is_negative());
306
307 const DECIMAL_ZEROES: &str = "0.00000";
310
311 let leading_zeroes = leading_zeroes.unsigned_abs() as usize;
312
313 if leading_zeroes + "0.".len() <= DECIMAL_ZEROES.len() {
316 write_content(
318 &DECIMAL_ZEROES[..leading_zeroes + "0.".len()],
319 leading_zeroes,
320 &mut written,
321 &mut out,
322 )?;
323
324 write_all_as_integer(skipped, declets, &mut written, &mut out)?;
326 }
327 else {
329 write_all_as_scientific(
330 skipped,
331 declets,
332 exponent,
333 &mut written,
334 &mut out,
335 )?;
336 }
337 }
338 None => {
340 write_all_as_scientific(
341 skipped,
342 declets,
343 exponent,
344 &mut written,
345 &mut out,
346 )?;
347 }
348 }
349 }
350 _ => {
352 write_all_as_scientific(
353 skip_leading_zeroes(msd, &mut declets),
354 declets,
355 exponent,
356 &mut written,
357 &mut out,
358 )?;
359 }
360 }
361
362 Ok(())
363 }
364 else if is_infinite(decimal) {
366 out.write_str("inf")
367 }
368 else {
370 debug_assert!(is_nan(decimal));
371
372 if is_quiet_nan(decimal) {
373 out.write_str("nan")?;
374 } else {
375 out.write_str("snan")?;
376 }
377
378 let mut payload = decode_significand_trailing_declets(decimal)
382 .flatten()
383 .peekable();
384
385 while let Some(b'0') = payload.peek() {
387 let _ = payload.next();
388 }
389
390 if payload.peek().is_some() {
392 out.write_char('(')?;
393
394 for digit in payload {
395 out.write_char(digit as char)?;
396 }
397
398 out.write_char(')')?;
399 }
400
401 Ok(())
402 }
403}
404
405fn adjusted_precision_digits_with_msd_declet(decimal: &impl BinaryBuf) -> usize {
406 decimal.precision_digits() + 2
407}
408
409fn skip_leading_zeroes(msd_ascii: u8, declets: impl Iterator<Item = [u8; 3]>) -> LeadingZeroes {
410 let mut skipped = 0;
411
412 if msd_ascii == b'0' {
414 skipped += 3;
415 } else {
416 return LeadingZeroes {
417 skipped: 2,
418 partial_declet: Some(([b'0', b'0', msd_ascii], 2)),
419 };
420 }
421
422 for declet in declets {
423 if declet == [b'0', b'0', b'0'] {
425 skipped += 3;
426 continue;
427 }
428 else {
430 let mut i = 0;
431 for digit in declet {
432 if digit != b'0' {
433 break;
434 }
435
436 i += 1;
437 }
438
439 skipped += i;
440
441 return LeadingZeroes {
442 skipped,
443 partial_declet: Some((declet, i)),
444 };
445 }
446 }
447
448 LeadingZeroes {
449 skipped,
450 partial_declet: None,
451 }
452}
453
454fn write_content(
455 content: &str,
456 digits: usize,
457 written: &mut usize,
458 mut out: impl fmt::Write,
459) -> Result<(), fmt::Error> {
460 *written += digits;
461 out.write_str(content)
462}
463
464fn write_digits(
465 digits: &[u8],
466 written: &mut usize,
467 out: impl fmt::Write,
468) -> Result<(), fmt::Error> {
469 write_content(
470 str::from_utf8(digits).map_err(|_| fmt::Error)?,
471 digits.len(),
472 written,
473 out,
474 )
475}
476
477fn write_declet(
478 declet: [u8; 3],
479 written: &mut usize,
480 out: impl fmt::Write,
481) -> Result<(), fmt::Error> {
482 write_content(
483 str::from_utf8(&declet).map_err(|_| fmt::Error)?,
484 declet.len(),
485 written,
486 out,
487 )
488}
489
490fn write_decimal_digits(
491 digits: &[u8],
492 total_integer_digits: usize,
493 written: &mut usize,
494 mut out: impl fmt::Write,
495) -> Result<bool, fmt::Error> {
496 if *written + digits.len() <= total_integer_digits {
498 write_digits(digits, written, &mut out)?;
499
500 Ok(false)
501 }
502 else if *written == total_integer_digits {
504 out.write_char('.')?;
505 write_digits(digits, written, &mut out)?;
506
507 Ok(true)
508 }
509 else {
511 let decimal_point = total_integer_digits - *written;
512
513 write_digits(&digits[..decimal_point], written, &mut out)?;
514 out.write_char('.')?;
515 write_digits(&digits[decimal_point..], written, &mut out)?;
516
517 Ok(true)
518 }
519}
520
521fn write_all_as_integer(
522 leading_zeroes: LeadingZeroes,
523 declets: impl Iterator<Item = [u8; 3]>,
524 written: &mut usize,
525 mut out: impl fmt::Write,
526) -> Result<(), fmt::Error> {
527 if let LeadingZeroes {
528 partial_declet: Some((declet, idx)),
529 ..
530 } = leading_zeroes
531 {
532 write_digits(&declet[idx..], written, &mut out)?;
533 }
534
535 for declet in declets {
537 write_declet(declet, written, &mut out)?;
538 }
539
540 if *written == 0 {
542 out.write_char('0')?;
543 }
544
545 Ok(())
546}
547
548fn write_all_as_scientific(
549 leading_zeroes: LeadingZeroes,
550 mut declets: impl Iterator<Item = [u8; 3]>,
551 exponent: impl BinaryExponent,
552 written: &mut usize,
553 mut out: impl fmt::Write,
554) -> Result<(), fmt::Error> {
555 if let LeadingZeroes {
557 partial_declet: Some((declet, idx)),
558 ..
559 } = leading_zeroes
560 {
561 write_decimal_digits(&declet[idx..], 1, written, &mut out)?;
562 } else if let Some(declet) = declets.next() {
563 write_content(
564 str::from_utf8(&[declet[0], b'.', declet[1], declet[2]]).map_err(|_| fmt::Error)?,
565 1,
566 written,
567 &mut out,
568 )?;
569 }
570
571 for declet in declets {
573 write_declet(declet, written, &mut out)?;
574 }
575
576 if *written == 0 {
578 out.write_str("0e")?;
579 } else {
580 out.write_char('e')?;
581 }
582
583 let exponent = exponent.raise(written.saturating_sub(1));
587
588 exponent.to_fmt(&mut out)?;
590
591 Ok(())
592}
593
594struct LeadingZeroes {
595 skipped: usize,
596 partial_declet: Option<([u8; 3], usize)>,
597}