pdbtbx/structs/
helper.rs

1/// Checks if a char is allowed in a PDB file.
2/// The char has to be ASCII graphic or a space.
3/// Returns `true` if the char is valid.
4pub const fn check_char(c: char) -> bool {
5    (c as u32) < 127 && c as u32 > 31
6}
7
8/// Checks a string using `check_char`.
9/// Returns `true` if the text is valid.
10pub fn valid_text(text: impl AsRef<str>) -> bool {
11    text.as_ref().chars().all(check_char)
12}
13
14/// Checks a string using `check_char`.
15/// Returns `true` if the text is valid.
16pub fn valid_identifier(text: impl AsRef<str>) -> bool {
17    text.as_ref().chars().all(check_char)
18}
19
20/// Creates a valid identifier from the given string slice.
21/// Also turns the identifier to uppercase.
22pub fn prepare_identifier_uppercase(text: impl AsRef<str>) -> Option<String> {
23    let text = text.as_ref();
24    prepare_identifier(text).map(|s| s.to_uppercase())
25}
26
27/// Creates a valid identifier from the given string slice.
28/// Does not change the case.
29pub fn prepare_identifier(text: impl AsRef<str>) -> Option<String> {
30    let text = text.as_ref();
31    (valid_identifier(text) && !text.trim().is_empty()).then(|| text.trim().to_string())
32}
33
34const ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
35
36/// Converts a number into a base26 with only the alphabet as possible chars
37#[allow(clippy::unwrap_used)]
38pub fn number_to_base26(mut num: usize) -> String {
39    let mut output = vec![ALPHABET.chars().nth(num % 26).unwrap()];
40    num /= 26;
41    while num != 0 {
42        output.push(ALPHABET.chars().nth(num % 26).unwrap());
43        num /= 26;
44    }
45    output.iter().rev().collect::<String>()
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    #[test]
52    fn correct_examples() {
53        assert!(check_char('a'));
54        assert!(check_char('9'));
55        assert!(check_char('*'));
56        assert!(check_char('@'));
57        assert!(check_char('O'));
58        assert!(valid_text("ResidueName"));
59        assert!(valid_text("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>? "));
60    }
61    #[test]
62    fn incorrect_examples() {
63        assert!(!check_char('̊'));
64        assert!(!check_char('∞'));
65        assert!(!check_char('👍'));
66        assert!(!check_char('ÿ'));
67        assert!(!check_char('\u{0}'));
68        assert!(!valid_text("ResidueName∞"));
69        assert!(!valid_text("Escape\u{0}"));
70    }
71    #[test]
72    fn number_to_base26_test() {
73        assert_eq!(number_to_base26(26), "BA");
74        assert_eq!(number_to_base26(0), "A");
75        assert_eq!(number_to_base26(234), "JA");
76        assert_eq!(number_to_base26(25), "Z");
77        assert_eq!(number_to_base26(457), "RP");
78        assert_eq!(number_to_base26(15250), "WOO");
79        assert_eq!(number_to_base26(396514), "WOOO");
80    }
81}