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}