use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use core::fmt;
#[cfg(test)]
mod tests;
pub const MAX_BASE: usize = 64;
pub const ALPHANUMERIC_ONLY: usize = 62;
pub const CASE_INSENSITIVE: usize = 36;
const BASE_64: [u8; MAX_BASE] = {
let bytes = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
assert!(bytes.is_ascii());
*bytes
};
pub struct BaseNString {
start: usize,
buf: [u8; 128],
}
impl BaseNString {
fn as_str(&self) -> &str {
let digits = &self.buf[self.start..];
unsafe { core::str::from_utf8_unchecked(digits) }
}
}
impl core::ops::Deref for BaseNString {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for BaseNString {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl fmt::Display for BaseNString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self)
}
}
pub trait ToBaseN: Into<u128> {
fn encoded_len(base: usize) -> usize;
fn to_base_fixed_len(self, base: usize) -> BaseNString {
let mut encoded = self.to_base(base);
encoded.start = encoded.buf.len() - Self::encoded_len(base);
encoded
}
fn to_base(self, base: usize) -> BaseNString {
let mut output = [b'0'; 128];
let mut n: u128 = self.into();
let mut index = output.len();
loop {
index -= 1;
output[index] = BASE_64[(n % base as u128) as usize];
n /= base as u128;
if n == 0 {
break;
}
}
assert_eq!(n, 0);
BaseNString { start: index, buf: output }
}
}
impl ToBaseN for u128 {
fn encoded_len(base: usize) -> usize {
let mut max = u128::MAX;
let mut len = 0;
while max > 0 {
len += 1;
max /= base as u128;
}
len
}
}
impl ToBaseN for u64 {
fn encoded_len(base: usize) -> usize {
let mut max = u64::MAX;
let mut len = 0;
while max > 0 {
len += 1;
max /= base as u64;
}
len
}
}
impl ToBaseN for u32 {
fn encoded_len(base: usize) -> usize {
let mut max = u32::MAX;
let mut len = 0;
while max > 0 {
len += 1;
max /= base as u32;
}
len
}
}