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
pub use std::convert::TryInto; /// Contains fields to be used by a generator that produces keys to transform plaintext /// using the given keyword. #[derive(Debug)] pub struct KeyGenerator { /// The word whose letters will be used as keys in a cipher keyword: String, /// Whether to retain the case of current letter (as opposed to converting all to uppercase). retain_case: bool, /// The current position of the "cursor" within the keyword position: i16, } /// A lazy generator that produces keys to use to shift plaintext to ciphertext using each letter /// of the given keyword. /// /// When the cursor reaches the end of the keyword, it loops back to the beginning. impl KeyGenerator { /// Creates a new `KeyGenerator` with the given keyword and sets the cursor to its first letter. /// /// # Example /// /// ``` /// let keygen = KeyGenerator::new(String::from("Queen"), true); /// ``` pub fn new(keyword: String, retain_case: bool) -> KeyGenerator { KeyGenerator { keyword, retain_case, position: -1, } } } impl Iterator for KeyGenerator { type Item = char; /// Generates the next key from the keyword as a `char`. /// /// # Example /// /// ``` /// let keygen = KeyGenerator::new(String::from("Queen", true)); /// let key: char = keygen.next().unwrap(); /// ``` fn next(&mut self) -> Option<char> { if self.position as usize >= self.keyword.len() { self.position = 0; } else { self.position += 1; } if self.retain_case { // let code_point: u32 = self.keyword.chars().nth(self.position).unwrap() as u32; let code_point: u32 = self .keyword .chars() .nth(self.position.try_into().unwrap()) .unwrap() as u32; println!("next codepoint: {:?}", code_point); Some(std::char::from_u32(code_point + 32).unwrap()) } else { Some( self.keyword .chars() .nth(self.position.try_into().unwrap()) .unwrap(), ) } } }