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}