1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Char { c: u8, } impl Char { pub const MAX: u8 = 26; pub fn to_upper(self) -> char { (self.c as u8 + b'A') as char } pub fn to_lower(self) -> char { (self.c as u8 + b'a') as char } } impl Add<u8> for Char { type Output = Char; fn add(self, other: u8) -> Char { Char { c: (self.c + other) % Char::MAX, } } } impl AddAssign<u8> for Char { fn add_assign(&mut self, other: u8) { *self = *self + other; } } impl Sub<u8> for Char { type Output = Char; fn sub(self, other: u8) -> Char { let a = self.c as i32 - other as i32; let b = a + (Char::MAX as i32 * std::u8::MAX as i32); let c = b % (Char::MAX as i32); Char { c: c as u8 } } } impl SubAssign<u8> for Char { fn sub_assign(&mut self, other: u8) { *self = *self - other; } } impl Mul<u8> for Char { type Output = Char; fn mul(self, other: u8) -> Char { Char { c: (self.c * other) % Char::MAX, } } } impl MulAssign<u8> for Char { fn mul_assign(&mut self, other: u8) { *self = *self * other; } } impl From<u8> for Char { fn from(c: u8) -> Char { debug_assert!(c < Char::MAX); Char { c } } } impl From<char> for Char { fn from(c: char) -> Char { debug_assert!(c.is_ascii() && c.is_alphabetic()); if c.is_uppercase() { Char { c: c as u8 - b'A' } } else { Char { c: c as u8 - b'a' } } } } impl From<Char> for u8 { fn from(c: Char) -> u8 { c.c } } impl From<Char> for char { fn from(c: Char) -> char { c.to_upper() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_upper_lower() { let c = Char { c: 0 }; assert_eq!(c.to_upper(), 'A'); assert_eq!(c.to_lower(), 'a'); } #[test] fn test_conversions() { let a = Char { c: 0 }; let k = Char { c: 10 }; assert_eq!(0, u8::from(a)); assert_eq!(10, u8::from(k)); assert_eq!('A', char::from(a)); assert_eq!('K', char::from(k)); assert_eq!(a, Char::from(0)); assert_eq!(k, Char::from(10)); assert_eq!(a, Char::from('A')); assert_eq!(a, Char::from('a')); assert_eq!(k, Char::from('K')); assert_eq!(k, Char::from('k')); } #[test] fn test_ops() { let a = Char { c: 0 }; assert_eq!(a, a + 0); assert_eq!(a, a - 0); assert_eq!(a, a + Char::MAX); assert_eq!(a, a - Char::MAX); assert_eq!(Char::from(1), a + 1); assert_eq!(Char::from(10), a + 10); assert_eq!(Char::from(23), a - 3); assert_eq!(Char::from(10), a + Char::MAX + 10); assert_eq!(Char::from(16), a - Char::MAX - 10); assert_eq!(a, a * 123); assert_eq!(Char { c: 4 }, Char { c: 1 } * 30); } }