]> git.lizzy.rs Git - rust.git/blob - library/core/src/num/fmt.rs
Auto merge of #95454 - randomicon00:fix95444, r=wesleywiser
[rust.git] / library / core / src / num / 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)]
11 pub 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
20 impl<'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) => {
26                 if v < 1_000 {
27                     if v < 10 {
28                         1
29                     } else if v < 100 {
30                         2
31                     } else {
32                         3
33                     }
34                 } else {
35                     if v < 10_000 { 4 } else { 5 }
36                 }
37             }
38             Part::Copy(buf) => buf.len(),
39         }
40     }
41
42     /// Writes a part into the supplied buffer.
43     /// Returns the number of written bytes, or `None` if the buffer is not enough.
44     /// (It may still leave partially written bytes in the buffer; do not rely on that.)
45     pub fn write(&self, out: &mut [u8]) -> Option<usize> {
46         let len = self.len();
47         if out.len() >= len {
48             match *self {
49                 Part::Zero(nzeroes) => {
50                     for c in &mut out[..nzeroes] {
51                         *c = b'0';
52                     }
53                 }
54                 Part::Num(mut v) => {
55                     for c in out[..len].iter_mut().rev() {
56                         *c = b'0' + (v % 10) as u8;
57                         v /= 10;
58                     }
59                 }
60                 Part::Copy(buf) => {
61                     out[..buf.len()].copy_from_slice(buf);
62                 }
63             }
64             Some(len)
65         } else {
66             None
67         }
68     }
69 }
70
71 /// Formatted result containing one or more parts.
72 /// This can be written to the byte buffer or converted to the allocated string.
73 #[allow(missing_debug_implementations)]
74 #[derive(Clone)]
75 pub struct Formatted<'a> {
76     /// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
77     pub sign: &'static str,
78     /// Formatted parts to be rendered after a sign and optional zero padding.
79     pub parts: &'a [Part<'a>],
80 }
81
82 impl<'a> Formatted<'a> {
83     /// Returns the exact byte length of combined formatted result.
84     pub fn len(&self) -> usize {
85         let mut len = self.sign.len();
86         for part in self.parts {
87             len += part.len();
88         }
89         len
90     }
91
92     /// Writes all formatted parts into the supplied buffer.
93     /// Returns the number of written bytes, or `None` if the buffer is not enough.
94     /// (It may still leave partially written bytes in the buffer; do not rely on that.)
95     pub fn write(&self, out: &mut [u8]) -> Option<usize> {
96         if out.len() < self.sign.len() {
97             return None;
98         }
99         out[..self.sign.len()].copy_from_slice(self.sign.as_bytes());
100
101         let mut written = self.sign.len();
102         for part in self.parts {
103             let len = part.write(&mut out[written..])?;
104             written += len;
105         }
106         Some(written)
107     }
108 }