use crate::digits::Digits;
mod digits;
const MINIMUM: u8 = '+' as u8;
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Base79(String);
#[derive(Debug, Eq, PartialEq)]
pub enum ParseError {
InvalidChar,
EmptyNotAllowed,
}
impl Base79 {
pub fn mid() -> Self {
Digits::mid().into()
}
pub fn avg(lhs: &Self, rhs: &Self) -> Self {
Digits::avg(&lhs.into(), &rhs.into()).into()
}
pub fn avg_with_zero(n: &Self) -> Self {
Digits::avg(&Digits::zero(), &n.into()).into()
}
pub fn avg_with_one(n: &Self) -> Self {
Digits::avg(&Digits::one(), &n.into()).into()
}
pub fn raw_digits(&self) -> Vec<u8> {
Digits::from(self).0
}
}
impl ToString for Base79 {
fn to_string(&self) -> String {
self.0.clone()
}
}
impl std::str::FromStr for Base79 {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
Err(ParseError::EmptyNotAllowed)
} else if s.chars().any(|c| !c.is_ascii() || c.is_ascii_control()) {
Err(ParseError::InvalidChar)
} else {
Ok(Base79(s.to_owned()))
}
}
}
impl From<Digits> for Base79 {
fn from(digits: Digits) -> Self {
Self(String::from_utf8(digits.0.iter().map(|x| x + MINIMUM).collect()).unwrap())
}
}
impl From<&Base79> for Digits {
fn from(base79: &Base79) -> Self {
Self(base79.0.as_bytes().iter().map(|x| x - MINIMUM).collect())
}
}
impl From<Base79> for String {
fn from(base79: Base79) -> Self {
base79.0
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::*;
#[test]
fn test_from_str() {
assert_eq!(Base79::from_str(""), Err(ParseError::EmptyNotAllowed));
assert_eq!(Base79::from_str("한글"), Err(ParseError::InvalidChar));
assert_eq!(Base79::from_str("R").unwrap(), Base79::mid());
}
}