Skip to main content

cryptography_breaker/
validator.rs

1//! Validator
2//! 
3//! Provide functions to validate input
4
5use std::{collections::HashSet, fmt::Display};
6
7use crate::normalizer;
8
9/// Errors that validate_alphabet() may return
10pub enum ValidateAlphabetError {
11    /// The same character exists in the alphabet but in different case
12    CharacterExistInDifferentCase(char),
13    /// The same character exists in the alphabet
14    DuplicateCharacter(char),
15    /// Not alowed character (in theory it should never be returned)
16    InvalidCharacter(char),
17    /// Provided alphabet is empty
18    EmptyAlphabet,
19}
20impl Display for ValidateAlphabetError {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        match self {
23            ValidateAlphabetError::CharacterExistInDifferentCase(c) => write!(
24                f,
25                "There is already the same character but in different case: {}",
26                c
27            ),
28            ValidateAlphabetError::DuplicateCharacter(c) => {
29                write!(f, "There is already the same character: {}", c)
30            }
31            ValidateAlphabetError::InvalidCharacter(c) => {
32                write!(f, "Invalid character: {}", c)
33            }
34            ValidateAlphabetError::EmptyAlphabet => {
35                write!(f, "Alphabet cannot be empty")
36            }
37        }
38    }
39}
40/// Errors that validate_input_text() may return
41pub enum ValidateInputTextError {
42    /// Provided character is not in the alphabet
43    CharacterNotInAlphabet(char),
44    /// Provided character is lowercase which isn't allowed for given configuration
45    LowerCaseCharacter(char),
46}
47impl Display for ValidateInputTextError {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        match self {
50            ValidateInputTextError::CharacterNotInAlphabet(c) => {
51                write!(f, "There is no such a character inside the alphabet: {}", c)
52            }
53            ValidateInputTextError::LowerCaseCharacter(c) => {
54                write!(
55                    f,
56                    "Lower case characters are not allowed for your configuration. Consider using CaseSensitive option: {}",
57                    c
58                )
59            }
60        }
61    }
62}
63/// Function that validates alphabet
64pub fn validate_alphabet(
65    alphabet: &[char],
66    case_strategy: normalizer::CaseStrategy,
67) -> Result<(), ValidateAlphabetError> {
68    if alphabet.is_empty() {
69        return Err(ValidateAlphabetError::EmptyAlphabet)
70    }
71    match case_strategy {
72        normalizer::CaseStrategy::CaseSensitive => {
73            let mut checked = HashSet::new();
74            for c in alphabet {
75                if !checked.insert(c) {
76                    return Err(ValidateAlphabetError::DuplicateCharacter(*c));
77                }
78            }
79            Ok(())
80        }
81        normalizer::CaseStrategy::CaseUnsensitive => {
82            let mut checked = HashSet::new();
83            for c in alphabet {
84                if !checked.insert(*c) {
85                    return Err(ValidateAlphabetError::DuplicateCharacter(*c));
86                } else {
87                    let c = c
88                        .to_uppercase()
89                        .next()
90                        .ok_or(ValidateAlphabetError::InvalidCharacter(*c))?;
91                    if !checked.insert(c) {
92                        return Err(ValidateAlphabetError::CharacterExistInDifferentCase(c));
93                    }
94                }
95            }
96            Ok(())
97        }
98
99        normalizer::CaseStrategy::Preserve => {
100            let mut checked = HashSet::new();
101            for c in alphabet {
102                if !checked.insert(*c) {
103                    return Err(ValidateAlphabetError::DuplicateCharacter(*c));
104                } else {
105                    let upper_c = c
106                        .to_uppercase()
107                        .next()
108                        .ok_or(ValidateAlphabetError::InvalidCharacter(*c))?;
109                    if !checked.insert(upper_c) {
110                        return Err(ValidateAlphabetError::CharacterExistInDifferentCase(
111                            upper_c,
112                        ));
113                    }
114                }
115            }
116            Ok(())
117        }
118    }
119}
120
121/// Function that validates input text
122pub fn validate_input_text(
123    input_text: &str,
124    case_strategy: normalizer::CaseStrategy,
125    alphabet: &[char],
126    preserve_whitespaces: bool,
127    preserve_other_characters: bool,
128) -> Result<(), ValidateInputTextError> {
129    // If allowed to preserve character outside the alphabet, then every input will be valid as rust won't accept character outside utf-8
130    if preserve_other_characters {
131        return Ok(());
132    }
133
134    match case_strategy {
135        normalizer::CaseStrategy::CaseSensitive => {
136            for c in input_text.chars() {
137                if preserve_whitespaces && c.is_whitespace() {
138                    return Ok(());
139                }
140                if !alphabet.contains(&c) {
141                    return Err(ValidateInputTextError::CharacterNotInAlphabet(c));
142                }
143            }
144            Ok(())
145        }
146        normalizer::CaseStrategy::CaseUnsensitive => {
147            for c in input_text.chars() {
148                if preserve_whitespaces && c.is_whitespace() {
149                    return Ok(());
150                }
151                if c.is_lowercase() {
152                    return Err(ValidateInputTextError::LowerCaseCharacter(c));
153                }
154                if !alphabet.contains(&c) {
155                    return Err(ValidateInputTextError::CharacterNotInAlphabet(c));
156                }
157            }
158            Ok(())
159        }
160        normalizer::CaseStrategy::Preserve => {
161            for c in input_text.chars() {
162                if preserve_whitespaces && c.is_whitespace() {
163                    return Ok(());
164                }
165                if c.is_lowercase() {
166                    return Err(ValidateInputTextError::LowerCaseCharacter(c));
167                }
168                if !alphabet.contains(&c) {
169                    return Err(ValidateInputTextError::CharacterNotInAlphabet(c));
170                }
171            }
172            Ok(())
173        }
174    }
175}
176
177/// TODO: 
178/// Function that validates key
179pub fn validate_key() {}