use core::fmt;
#[derive(Clone, Copy)]
pub struct Alphabet {
pub(crate) encode: [u8; 58],
pub(crate) decode: [u8; 128],
}
#[non_exhaustive]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Error {
DuplicateCharacter {
character: char,
first: usize,
second: usize,
},
NonAsciiCharacter {
index: usize,
},
}
impl Alphabet {
pub const BITCOIN: &'static Self =
&Self::new_unwrap(b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
pub const MONERO: &'static Self =
&Self::new_unwrap(b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
pub const RIPPLE: &'static Self =
&Self::new_unwrap(b"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz");
pub const FLICKR: &'static Self =
&Self::new_unwrap(b"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ");
pub const DEFAULT: &'static Self = Self::BITCOIN;
pub const fn new(base: &[u8; 58]) -> Result<Self, Error> {
let mut encode = [0x00; 58];
let mut decode = [0xFF; 128];
let mut i = 0;
while i < encode.len() {
if base[i] >= 128 {
return Err(Error::NonAsciiCharacter { index: i });
}
if decode[base[i] as usize] != 0xFF {
return Err(Error::DuplicateCharacter {
character: base[i] as char,
first: decode[base[i] as usize] as usize,
second: i,
});
}
encode[i] = base[i];
decode[base[i] as usize] = i as u8;
i += 1;
}
Ok(Self { encode, decode })
}
pub const fn new_unwrap(base: &[u8; 58]) -> Self {
let result = Self::new(base);
#[allow(unconditional_panic)] [][match result {
Ok(alphabet) => return alphabet,
Err(_) => 0,
}]
}
}
impl fmt::Debug for Alphabet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Ok(s) = core::str::from_utf8(&self.encode) {
f.debug_tuple("Alphabet").field(&s).finish()
} else {
unreachable!()
}
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::DuplicateCharacter {
character,
first,
second,
} => write!(
f,
"alphabet contained a duplicate character `{}` at indexes {} and {}",
character, first, second,
),
Error::NonAsciiCharacter { index } => {
write!(f, "alphabet contained a non-ascii character at {}", index)
}
}
}
}
const _: () = {
let _ = Alphabet::BITCOIN;
let _ = Alphabet::MONERO;
let _ = Alphabet::RIPPLE;
let _ = Alphabet::FLICKR;
let _ = Alphabet::DEFAULT;
};
#[test]
#[should_panic]
fn test_new_unwrap_does_panic() {
Alphabet::new_unwrap(b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}