1#[derive(Copy, Clone)]
3pub enum Mode {
4 Encrypt,
6 Decrypt,
8}
9
10fn get_first_alphabet_position(letter: u8) -> u8 {
16 if letter.is_ascii_uppercase() {
18 b'A'
19 } else {
20 b'a'
21 }
22}
23
24fn get_letter_position(letter: u8) -> u8 {
27 let a_position = get_first_alphabet_position(letter);
28 letter - a_position
29}
30
31pub fn rot_letter(mode: Mode, letter: u8, rotation: u8) -> u8 {
51 let a_position = get_first_alphabet_position(letter);
52 let letter_position = get_letter_position(letter);
53
54 let shifted_position = match mode {
55 Mode::Encrypt => (letter_position + rotation) % 26,
56 Mode::Decrypt => {
57 if letter_position < rotation {
58 26 - (rotation - letter_position)
59 } else {
60 letter_position - rotation
61 }
62 }
63 };
64
65 a_position + shifted_position
66}
67
68pub fn rot(mode: Mode, inputs: &[u8], rotation: u8) -> Vec<u8> {
85 inputs
86 .iter()
87 .map(|&input| {
88 if input.is_ascii_alphabetic() {
90 rot_letter(mode, input, rotation)
91 } else {
92 input
93 }
94 })
95 .collect()
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn first_alphabet_position() {
104 assert_eq!(65, get_first_alphabet_position(b'A'));
105 assert_eq!(b'A', get_first_alphabet_position(b'A'));
106
107 assert_eq!(97, get_first_alphabet_position(b'a'));
108 assert_eq!(b'a', get_first_alphabet_position(b'a'));
109 }
110
111 #[test]
112 fn letter_position() {
113 assert_eq!(0, get_letter_position(b'A'));
114 assert_eq!(0, get_letter_position(b'a'));
115
116 assert_eq!(25, get_letter_position(b'Z'));
117 assert_eq!(25, get_letter_position(b'z'));
118 }
119
120 #[test]
121 fn rot13_letter_encrypt() {
122 let rotation = 13;
123
124 let encrypted = rot(Mode::Encrypt, b"a", rotation);
125 assert_eq!(b"n".as_slice(), &encrypted);
126
127 let encrypted = rot(Mode::Encrypt, b"A", rotation);
128 assert_eq!(b"N".as_slice(), &encrypted);
129
130 let encrypted = rot(Mode::Encrypt, b"Z", rotation);
131 assert_eq!(b"M".as_slice(), &encrypted);
132 }
133
134 #[test]
135 fn rot13_letter_decrypt() {
136 let rotation = 13;
137
138 let encrypted = rot(Mode::Decrypt, b"n", rotation);
139 assert_eq!(b"a".as_slice(), &encrypted);
140
141 let encrypted = rot(Mode::Decrypt, b"N", rotation);
142 assert_eq!(b"A".as_slice(), &encrypted);
143
144 let encrypted = rot(Mode::Decrypt, b"M", rotation);
145 assert_eq!(b"Z".as_slice(), &encrypted);
146 }
147
148 #[test]
149 fn rot13_encrypt() {
150 let rotation = 13;
151
152 let encrypted = rot(Mode::Encrypt, b"rust", rotation);
153 assert_eq!(b"ehfg".as_slice(), &encrypted);
154
155 let encrypted = rot(Mode::Encrypt, b"Hello, World!", rotation);
156 assert_eq!(b"Uryyb, Jbeyq!".as_slice(), &encrypted);
157 }
158
159 #[test]
160 fn rot13_dencrypt() {
161 let rotation = 13;
162
163 let encrypted = rot(Mode::Decrypt, b"ehfg", rotation);
164 assert_eq!(b"rust".as_slice(), &encrypted);
165
166 let encrypted = rot(Mode::Decrypt, b"Uryyb, Jbeyq!", rotation);
167 assert_eq!(b"Hello, World!".as_slice(), &encrypted);
168 }
169
170 #[test]
171 fn all_rotations_encrypt() {
172 let pairs = vec![(1, b"svtu"), (12, b"dgef"), (25, b"qtrs")];
173
174 for (rotation, expected) in pairs {
175 let encrypted = rot(Mode::Encrypt, b"rust", rotation);
176 assert_eq!(expected.as_slice(), &encrypted);
177 }
178 }
179
180 #[test]
181 fn offsite() {
182 let encrypted = rot(Mode::Encrypt, b"a", 0);
183 assert_eq!(b"a".as_slice(), &encrypted);
184
185 let encrypted = rot(Mode::Encrypt, b"a", 26);
186 assert_eq!(b"a".as_slice(), &encrypted);
187 }
188}