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
use crate::cipher::Asymmetric;
use crate::lang::Language;

const LETTERS: [char; 37] = [
    ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
    's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
];
const MORSE: [&str; 37] = [
    "/", ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..",
    "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--",
    "--..", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.",
    "-----",
];

pub struct Morse {}

impl Asymmetric for Morse {
    fn encrypt(&self, _language: &mut Language, msg: &str) -> String {
        msg.to_lowercase()
            .chars()
            .filter(|c| LETTERS.contains(c))
            .map(|c| MORSE[LETTERS.iter().position(|x| *x == c).unwrap()])
            .fold(String::new(), |mut acc, x| {
                acc.push_str(x);
                acc.push(' ');
                acc
            })
            .trim()
            .to_string()
    }
    fn decrypt(&self, _language: &mut Language, msg: &str) -> String {
        msg.split('/')
            .map(|word| {
                word.replace('_', "-")
                    .trim()
                    .split(' ')
                    .map(|letter| MORSE.iter().position(|&x| x == letter))
                    .filter(|&x| x != None)
                    .map(|pos| LETTERS[pos.unwrap()])
                    .fold(String::new(), |mut acc, x| {
                        acc.push(x);
                        acc
                    })
            })
            .fold(String::new(), |mut acc, x| {
                acc.push_str(&x);
                acc.push(' ');
                acc
            })
            .trim()
            .to_string()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn encrypt() {
        let msg = String::from("morse code");
        let mut language = Default::default();
        let morse = Morse {};
        let encrypted = morse.encrypt(&mut language, &msg);
        assert_eq!(encrypted, "-- --- .-. ... . / -.-. --- -.. .");
    }

    #[test]
    fn decrypt() {
        let msg = String::from("-- --- .-. ... . / -.-. --- -.. .");
        let mut language = Default::default();
        let morse = Morse {};
        let decrypted = morse.decrypt(&mut language, &msg);
        assert_eq!(decrypted, "morse code");
    }
}