common.rs (1758B)
1 use std::fmt; 2 use std::ops; 3 use std::cmp; 4 5 pub struct Snafu { 6 d: Vec<i8> 7 } 8 9 impl Snafu { 10 const DIGITS: [char; 5] = ['=', '-', '0', '1', '2']; 11 12 fn digit_to_i8(c: char) -> i8 { 13 for i in 0..5 { 14 if c == Snafu::DIGITS[i] { return i as i8 - 2; } 15 } 16 panic!("Invalid Snafu digit '{}'", c); 17 } 18 19 fn i8_to_digit(i: i8) -> char { 20 if i < -2 || i > 2 { 21 panic!("Invalid Snafu digit value {}", i); 22 } 23 Snafu::DIGITS[(i + 2) as usize] 24 } 25 26 pub fn ndigits(&self) -> usize { 27 self.d.len() 28 } 29 30 pub fn zero() -> Snafu { 31 Snafu { d: vec![0] } 32 } 33 34 pub fn from_str(s: &str) -> Snafu { 35 let mut d = vec![]; 36 for c in s.chars() { d.push(Self::digit_to_i8(c)); } 37 d.reverse(); 38 Snafu { d } 39 } 40 } 41 42 impl fmt::Display for Snafu { 43 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 // Strip leading zeros 45 let mut n = self.ndigits()-1; 46 while self.d[n] == 0 { n -= 1; } 47 48 for i in (0..=n).rev() { 49 write!(f, "{}", Self::i8_to_digit(self.d[i]))?; 50 } 51 Ok(()) 52 } 53 } 54 55 impl ops::AddAssign<&Snafu> for Snafu { 56 fn add_assign(&mut self, other: &Snafu) { 57 for i in 0..cmp::max(self.ndigits(), other.ndigits()) { 58 if i < other.ndigits() { 59 self.d[i] += other.d[i]; 60 } 61 62 // Carry over, both ways 63 if i == self.ndigits()-1 { self.d.push(0); } 64 while self.d[i] > 2 { self.d[i+1] += 1; self.d[i] -= 5; } 65 while self.d[i] < -2 { self.d[i+1] -= 1; self.d[i] += 5; } 66 } 67 68 for i in 0..self.ndigits() { 69 if self.d[i] == 0 { self.d.pop(); } else { break; } 70 } 71 } 72 }