summaryrefslogtreecommitdiffstats
path: root/library/core/src/num/fmt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/num/fmt.rs')
-rw-r--r--library/core/src/num/fmt.rs108
1 files changed, 108 insertions, 0 deletions
diff --git a/library/core/src/num/fmt.rs b/library/core/src/num/fmt.rs
new file mode 100644
index 000000000..ed6119715
--- /dev/null
+++ b/library/core/src/num/fmt.rs
@@ -0,0 +1,108 @@
+//! Shared utilities used by both float and integer formatting.
+#![doc(hidden)]
+#![unstable(
+ feature = "numfmt",
+ reason = "internal routines only exposed for testing",
+ issue = "none"
+)]
+
+/// Formatted parts.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Part<'a> {
+ /// Given number of zero digits.
+ Zero(usize),
+ /// A literal number up to 5 digits.
+ Num(u16),
+ /// A verbatim copy of given bytes.
+ Copy(&'a [u8]),
+}
+
+impl<'a> Part<'a> {
+ /// Returns the exact byte length of given part.
+ 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(),
+ }
+ }
+
+ /// Writes a part into the supplied buffer.
+ /// Returns the number of written bytes, or `None` if the buffer is not enough.
+ /// (It may still leave partially written bytes in the buffer; do not rely on that.)
+ 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
+ }
+ }
+}
+
+/// Formatted result containing one or more parts.
+/// This can be written to the byte buffer or converted to the allocated string.
+#[allow(missing_debug_implementations)]
+#[derive(Clone)]
+pub struct Formatted<'a> {
+ /// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
+ pub sign: &'static str,
+ /// Formatted parts to be rendered after a sign and optional zero padding.
+ pub parts: &'a [Part<'a>],
+}
+
+impl<'a> Formatted<'a> {
+ /// Returns the exact byte length of combined formatted result.
+ pub fn len(&self) -> usize {
+ let mut len = self.sign.len();
+ for part in self.parts {
+ len += part.len();
+ }
+ len
+ }
+
+ /// Writes all formatted parts into the supplied buffer.
+ /// Returns the number of written bytes, or `None` if the buffer is not enough.
+ /// (It may still leave partially written bytes in the buffer; do not rely on that.)
+ 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.as_bytes());
+
+ let mut written = self.sign.len();
+ for part in self.parts {
+ let len = part.write(&mut out[written..])?;
+ written += len;
+ }
+ Some(written)
+ }
+}