use std::str::FromStr;
use std::fmt::{self, Display, Formatter};
pub struct OGM {
data: u64,
}
impl OGM {
pub fn calculate_check(&self) -> u8 {
match self.data % 97 {
0 => 97,
x => x as u8,
}
}
pub fn new(input: u64) -> Result<OGM, &'static str> {
use num::PrimInt;
if input >= 10.pow(10) {
return Err("Seed larger than 10^10-1");
}
Ok(OGM {
data: input
})
}
}
impl FromStr for OGM {
type Err = &'static str;
fn from_str(input: &str) -> Result<OGM, Self::Err> {
if input.len() != 3+4+5 + 2+6 {
return Err("Input has invalid format");
}
if ! (input.starts_with("+++") || input.starts_with("***")) {
return Err("Should start with +++")
}
if ! (input.ends_with("+++") || input.ends_with("***")) {
return Err("Should end with +++")
}
let input = &input[3..17];
let mut data = input[0..3].parse().map_err(|_| "Triple is not numerical")?;
data *= 10000;
data += input[4..8].parse::<u64>().map_err(|_| "Quad is not numerical")?;
data *= 1000;
data += input[9..12].parse::<u64>().map_err(|_| "Last part is not numerical")?;
let check: u8 = input[12..14].parse::<u8>().map_err(|_| "Check is not numerical")?;
let ogm = OGM {
data: data,
};
if ogm.calculate_check() != check {
return Err("Incorrect control number");
}
Ok(ogm)
}
}
impl Display for OGM {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
let i = format!("{:010}", self.data);
write!(f, "+++{}/{}/{}{}+++", &i[0..3], &i[3..7], &i[7..], self.calculate_check())
}
}
#[cfg(test)]
mod tests {
use super::OGM;
#[test]
fn test_ogm_from_str_to_string() {
let tests = vec![
("+++090/9337/55493+++", 909337554),
];
for (input, output) in tests {
let OGM {
data
} = input.parse().unwrap();
assert_eq!(data, output);
let result = OGM {
data: output
}.to_string();
assert_eq!(result, input);
}
}
}