const TAG: u8 = 14;
#[derive(Debug, thiserror::Error)]
pub enum SymbolError {
#[error(
"Returned when attempting to form a Symbol from a string with more than 9 characters."
)]
TooLong(usize),
#[error("Used bad characters")]
BadChar(char),
}
pub struct Symbol(pub u64);
impl Symbol {
pub fn from_body(body: u64) -> Self {
Symbol((body << 8) | (TAG as u64))
}
fn encode_char(ch: char) -> Result<u64, SymbolError> {
let v = match ch {
'_' => 1,
'0'..='9' => 2 + ((ch as u64) - ('0' as u64)),
'A'..='Z' => 12 + ((ch as u64) - ('A' as u64)),
'a'..='z' => 38 + ((ch as u64) - ('a' as u64)),
_ => return Err(SymbolError::BadChar(ch)),
};
Ok(v)
}
pub fn try_from_bytes(b: &[u8]) -> Result<Self, SymbolError> {
let mut n = 0;
let mut accum: u64 = 0;
while n < b.len() {
let ch = b[n] as char;
if n >= 9 {
return Err(SymbolError::TooLong(b.len()));
}
n += 1;
accum <<= 6;
let v = match Self::encode_char(ch) {
Ok(v) => v,
Err(e) => return Err(e),
};
accum |= v;
}
Ok(Self::from_body(accum))
}
}