morse_code_cipher/
lib.rs

1static DECRYPTION_MAP: phf::Map<&str, char> = phf::phf_map! {
2    ".-" => 'A',
3    "-..." => 'B',
4    "-.-." => 'C',
5    "-.." => 'D',
6    "." => 'E',
7    "..-." => 'F',
8    "--." => 'G',
9    "...." => 'H',
10    ".." => 'I',
11    ".---" => 'J',
12    "-.-" => 'K',
13    ".-.." => 'L',
14    "--" => 'M',
15    "-." => 'N',
16    "---" => 'O',
17    ".--." => 'P',
18    "--.-" => 'Q',
19    ".-." => 'R',
20    "..." => 'S',
21    "-" => 'T',
22    "..-" => 'U',
23    "...-" => 'V',
24    ".--" => 'W',
25    "-..-" => 'X',
26    "-.--" => 'Y',
27    "--.." => 'Z',
28    ".----" => '1',
29    "..---" => '2',
30    "...--" => '3',
31    "....-" => '4',
32    "....." => '5',
33    "-...." => '6',
34    "--..." => '7',
35    "---.." => '8',
36    "----." => '9',
37    "-----" => '0',
38    "/" => ' ',
39    "--..--" => ',' ,
40    ".-.-.-" => '.' ,
41    "-.-.-" => ';' ,
42    "---..." => ':' ,
43    "-..-." => '/' ,
44    "-....-" => '-' ,
45    ".----." => '\'' ,
46    "-.--." => '(' ,
47    "-.--.-" => ')' ,
48    "..--.-" => '_' ,
49    ".--.-." => '@' ,
50    "-.-.--" => '!' ,
51    ".-..." => '&' ,
52    "-...-" => '=' ,
53    ".-.-." => '+' ,
54    ".-..-." => '"' ,
55    "...-..-" => '$' ,
56};
57
58static ENCRYPTION_MAP: phf::Map<char, &str> = phf::phf_map! {
59    'A'=> ".-" ,
60    'B'=> "-..." ,
61    'C'=> "-.-." ,
62    'D'=> "-.." ,
63    'E'=> "." ,
64    'F'=> "..-.",
65    'G'=> "--." ,
66    'H'=> "...." ,
67    'I'=> ".." ,
68    'J'=> ".---" ,
69    'K'=> "-.-" ,
70    'L'=> ".-.." ,
71    'M'=> "--" ,
72    'N'=> "-." ,
73    'O'=> "---" ,
74    'P'=> ".--." ,
75    'Q'=> "--.-" ,
76    'R'=> ".-." ,
77    'S'=> "..." ,
78    'T'=> "-" ,
79    'U'=> "..-" ,
80    'V'=> "...-" ,
81    'W'=> ".--" ,
82    'X'=> "-..-" ,
83    'Y'=> "-.--" ,
84    'Z'=> "--.." ,
85    '1'=> ".----" ,
86    '2'=> "..---" ,
87    '3'=> "...--" ,
88    '4'=> "....-" ,
89    '5'=> "....." ,
90    '6'=> "-...." ,
91    '7'=> "--..." ,
92    '8'=> "---.." ,
93    '9'=> "----." ,
94    '0'=> "-----" ,
95    ' ' => "/",
96    ',' => "--..--",
97    '.' => ".-.-.-",
98    ';' => "-.-.-",
99    ':' => "---...",
100    '/' => "-..-.",
101    '-' => "-....-",
102    '\'' => ".----.",
103    '(' => "-.--.",
104    ')' => "-.--.-",
105    '_' => "..--.-",
106    '@' => ".--.-.",
107    '!' => "-.-.--",
108    '&' => ".-...",
109    '=' => "-...-",
110    '+' => ".-.-.",
111    '"' => ".-..-.",
112    '$' => "...-..-"
113};
114
115pub struct MorseCode;
116
117impl MorseCode {
118    pub fn decrypt(ciphertext: &str) -> String {
119        ciphertext
120            .replace('_', "-")
121            .split_whitespace()
122            .map(|segment| DECRYPTION_MAP.get(segment).map(|encoding| encoding.to_string()).unwrap_or(segment.to_owned()))
123            .collect()
124    }
125
126    pub fn encrypt(plaintext: &str) -> String {
127        plaintext
128            .to_uppercase()
129            .chars()
130            .map(|character| ENCRYPTION_MAP.get(&character).cloned().unwrap_or(&character.to_string()).to_owned())
131            .collect::<Vec<_>>()
132            .join(" ")
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use crate::MorseCode;
139
140    #[test]
141    fn encrypt_decrypt() {
142        let plaintext = "Pack my box with five dozen liquor jugs.";
143        let ciphertext = ".--. .- -.-. -.- / -- -.-- / -... --- -..- / .-- .. - .... / ..-. .. ...- . / -.. --- --.. . -. / .-.. .. --.- ..- --- .-. / .--- ..- --. ... .-.-.-";
144
145        assert_eq!(ciphertext, MorseCode::encrypt(plaintext));
146        assert_eq!(plaintext.to_uppercase(), MorseCode::decrypt(ciphertext));
147    }
148}