rustc_data_structures/
base_n.rs

1//! Converts unsigned integers into a string representation with some base.
2//! Bases up to and including 36 can be used for case-insensitive things.
3
4use std::{ascii, fmt};
5
6#[cfg(test)]
7mod tests;
8
9pub const MAX_BASE: usize = 64;
10pub const ALPHANUMERIC_ONLY: usize = 62;
11pub const CASE_INSENSITIVE: usize = 36;
12
13const BASE_64: [ascii::Char; MAX_BASE] = {
14    let bytes = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
15    let Some(ascii) = bytes.as_ascii() else { panic!() };
16    *ascii
17};
18
19pub struct BaseNString {
20    start: usize,
21    buf: [ascii::Char; 128],
22}
23
24impl std::ops::Deref for BaseNString {
25    type Target = str;
26
27    fn deref(&self) -> &str {
28        self.buf[self.start..].as_str()
29    }
30}
31
32impl AsRef<str> for BaseNString {
33    fn as_ref(&self) -> &str {
34        self.buf[self.start..].as_str()
35    }
36}
37
38impl fmt::Display for BaseNString {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.write_str(self)
41    }
42}
43
44// This trait just lets us reserve the exact right amount of space when doing fixed-length
45// case-insensitive encoding. Add any impls you need.
46pub trait ToBaseN: Into<u128> {
47    fn encoded_len(base: usize) -> usize;
48
49    fn to_base_fixed_len(self, base: usize) -> BaseNString {
50        let mut encoded = self.to_base(base);
51        encoded.start = encoded.buf.len() - Self::encoded_len(base);
52        encoded
53    }
54
55    fn to_base(self, base: usize) -> BaseNString {
56        let mut output = [ascii::Char::Digit0; 128];
57
58        let mut n: u128 = self.into();
59
60        let mut index = output.len();
61        loop {
62            index -= 1;
63            output[index] = BASE_64[(n % base as u128) as usize];
64            n /= base as u128;
65
66            if n == 0 {
67                break;
68            }
69        }
70        assert_eq!(n, 0);
71
72        BaseNString { start: index, buf: output }
73    }
74}
75
76impl ToBaseN for u128 {
77    fn encoded_len(base: usize) -> usize {
78        let mut max = u128::MAX;
79        let mut len = 0;
80        while max > 0 {
81            len += 1;
82            max /= base as u128;
83        }
84        len
85    }
86}
87
88impl ToBaseN for u64 {
89    fn encoded_len(base: usize) -> usize {
90        let mut max = u64::MAX;
91        let mut len = 0;
92        while max > 0 {
93            len += 1;
94            max /= base as u64;
95        }
96        len
97    }
98}
99
100impl ToBaseN for u32 {
101    fn encoded_len(base: usize) -> usize {
102        let mut max = u32::MAX;
103        let mut len = 0;
104        while max > 0 {
105            len += 1;
106            max /= base as u32;
107        }
108        len
109    }
110}