while n > 0 {
symbol.push(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
.chars()
.nth(((n - 1) % 26) as usize)
.unwrap(),
);
n = (n - 1) / 26;
}
for c in symbol.chars().rev() {
write!(f, "{c}")?;
}
Ok(())
}
}
impl FromStr for Rune {
type Err = crate::Error;
fn from_str(s: &str) -> crate::Result<Self> {
let mut x = 0u128;
for (i, c) in s.chars().enumerate() {
if i > 0 {
x += 1;
}
x *= 26;
match c {
'A'..='Z' => {
x = x
.checked_add(c as u128 - 'A' as u128)
.ok_or_else(|| anyhow!("out of range"))?;
}
_ => bail!("invalid character in rune name: {c}"),
}
}
Ok(Rune(x))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip() {
fn case(n: u128, s: &str) {
assert_eq!(Rune(n).to_string(), s);
assert_eq!(s.parse::<Rune>().unwrap(), Rune(n));
}
case(0, "A");
case(1, "B");
case(2, "C");