core/num/imp/fmt.rs
1//! Shared utilities used by both float and integer formatting.
2#![doc(hidden)]
3#![unstable(
4 feature = "numfmt",
5 reason = "internal routines only exposed for testing",
6 issue = "none"
7)]
8
9/// Formatted parts.
10#[derive(Copy, Clone, PartialEq, Eq, Debug)]
11pub enum Part<'a> {
12 /// Given number of zero digits.
13 Zero(usize),
14 /// A literal number up to 5 digits.
15 Num(u16),
16 /// A verbatim copy of given bytes.
17 Copy(&'a [u8]),
18}
19
20impl<'a> Part<'a> {
21 /// Returns the exact byte length of given part.
22 pub fn len(&self) -> usize {
23 match *self {
24 Part::Zero(nzeroes) => nzeroes,
25 Part::Num(v) => v.checked_ilog10().unwrap_or_default() as usize + 1,
26 Part::Copy(buf) => buf.len(),
27 }
28 }
29
30 /// Writes a part into the supplied buffer.
31 /// Returns the number of written bytes, or `None` if the buffer is not enough.
32 /// (It may still leave partially written bytes in the buffer; do not rely on that.)
33 pub fn write(&self, out: &mut [u8]) -> Option<usize> {
34 let len = self.len();
35 if out.len() >= len {
36 match *self {
37 Part::Zero(nzeroes) => {
38 for c in &mut out[..nzeroes] {
39 *c = b'0';
40 }
41 }
42 Part::Num(mut v) => {
43 for c in out[..len].iter_mut().rev() {
44 *c = b'0' + (v % 10) as u8;
45 v /= 10;
46 }
47 }
48 Part::Copy(buf) => {
49 out[..buf.len()].copy_from_slice(buf);
50 }
51 }
52 Some(len)
53 } else {
54 None
55 }
56 }
57}
58
59/// Formatted result containing one or more parts.
60/// This can be written to the byte buffer or converted to the allocated string.
61#[allow(missing_debug_implementations)]
62#[derive(Clone)]
63pub struct Formatted<'a> {
64 /// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
65 pub sign: &'static str,
66 /// Formatted parts to be rendered after a sign and optional zero padding.
67 pub parts: &'a [Part<'a>],
68}
69
70impl<'a> Formatted<'a> {
71 /// Returns the byte length of combined formatted result.
72 ///
73 /// Saturates at `usize::MAX` if the actual length is larger.
74 ///
75 /// This matters on 16-bit targets, where exponential formatting can exceed
76 /// `usize::MAX` by emitting `u16::MAX` trailing zeroes plus `"1."` / `"e0"`.
77 pub fn len(&self) -> usize {
78 self.parts.iter().fold(self.sign.len(), |len, part| len.saturating_add(part.len()))
79 }
80
81 /// Writes all formatted parts into the supplied buffer.
82 /// Returns the number of written bytes, or `None` if the buffer is not enough.
83 /// (It may still leave partially written bytes in the buffer; do not rely on that.)
84 pub fn write(&self, out: &mut [u8]) -> Option<usize> {
85 out.get_mut(..self.sign.len())?.copy_from_slice(self.sign.as_bytes());
86
87 let mut written = self.sign.len();
88 for part in self.parts {
89 let len = part.write(&mut out[written..])?;
90 written += len;
91 }
92 Some(written)
93 }
94}