use std::collections::HashMap; extern crate rusty_dsp; use rusty_dsp::error::DspError; const LETTERS: &[u8] = b"\0E\nA SIU\rDRJNFCKTZLWHYPQOBG\0MXV\0"; const FIGURES: &[u8] = b"\03\n- \x0787\r\x054',!:(5\")2#6019?&\0./;\0"; lazy_static! { static ref INV_LETTERS: HashMap = LETTERS .iter() .enumerate() .map(|(c, f)| (*f, c as u8)) .collect(); static ref INV_FIGURES: HashMap = FIGURES .iter() .enumerate() .map(|(c, f)| (*f, c as u8)) .collect(); } fn letter_from_code(code: u8) -> Option { if code >= (LETTERS.len() as u8) { None } else { Some(LETTERS[code as usize]) } } fn figure_from_code(code: u8) -> Option { if code >= (FIGURES.len() as u8) { None } else { Some(FIGURES[code as usize]) } } fn code_from_letter(letter: &u8) -> Option { INV_LETTERS.get(letter).cloned() } fn code_from_figure(figure: &u8) -> Option { INV_FIGURES.get(figure).cloned() } const SHIFT_FIGURES: u8 = 0b11011u8; const SHIFT_LETTERS: u8 = 0b11111u8; #[derive(Copy, Clone)] enum ShiftState { None, Letters, Figures, } pub struct Encoder<'a> { shift_state: ShiftState, buffer: Option, iterator: Box + 'a>, } impl<'a> Encoder<'a> { pub fn from(iterator: I) -> Encoder<'a> where I: Iterator + 'a, { Encoder { shift_state: ShiftState::None, buffer: None, iterator: Box::new(iterator), } } } impl<'a> Iterator for Encoder<'a> { type Item = Result; fn next(&mut self) -> Option { if let Some(c) = self.buffer { self.buffer = None; return Some(Ok(c)); } let byte = match self.iterator.next() { Some(b) => b, None => return None, }; let letter = code_from_letter(&byte); let figure = code_from_figure(&byte); match (letter, figure, self.shift_state) { (Some(l), Some(_), ShiftState::None) => { self.shift_state = ShiftState::Letters; self.buffer = Some(l); Some(Ok(SHIFT_LETTERS)) } (Some(l), Some(_), _) => Some(Ok(l)), (Some(l), None, ShiftState::Letters) => Some(Ok(l)), (Some(l), None, _) => { self.shift_state = ShiftState::Letters; self.buffer = Some(l); Some(Ok(SHIFT_LETTERS)) } (None, Some(f), ShiftState::Figures) => Some(Ok(f)), (None, Some(f), _) => { self.shift_state = ShiftState::Figures; self.buffer = Some(f); Some(Ok(SHIFT_FIGURES)) } (None, None, _) => Some(Err(DspError::Error(format!( "Unable to decode symbol: {:?}", &byte )))), } } } pub fn encode(msg: &str) -> Result, DspError> { let encoder = Encoder::from(msg.to_ascii_uppercase().into_bytes().into_iter()); encoder.collect() } pub struct Decoder<'a> { shift_state: ShiftState, iterator: Box + 'a>, } impl<'a> Decoder<'a> { pub fn from(iterator: I) -> Decoder<'a> where I: Iterator + 'a, { Decoder { shift_state: ShiftState::Letters, iterator: Box::new(iterator), } } } impl<'a> Iterator for Decoder<'a> { // Option> for nice error handling if somebody wants to use collect // See https://doc.rust-lang.org/stable/rust-by-example/error/iter_result.html type Item = Result; fn next(&mut self) -> Option { let mut byte = match self.iterator.next() { Some(b) => b, None => return None, }; match byte { SHIFT_LETTERS => { self.shift_state = ShiftState::Letters; byte = match self.iterator.next() { Some(b) => b, None => return None, }; } SHIFT_FIGURES => { self.shift_state = ShiftState::Figures; byte = match self.iterator.next() { Some(b) => b, None => return None, }; } _ => {} }; match (byte, self.shift_state) { (c, ShiftState::Letters) => match letter_from_code(c) { Some(l) => Some(Ok(l)), None => Some(Err(DspError::Error(format!( "Unable to decode symbol: {:?}", c )))), }, (c, ShiftState::Figures) => match figure_from_code(c) { Some(f) => Some(Ok(f)), None => Some(Err(DspError::Error(format!( "Unable to decode symbol: {:?}", c )))), }, (_, ShiftState::None) => panic!("Shift state is expectedly None"), } } } pub fn decode(msg: &[u8]) -> Result { let decoder = Decoder::from(msg.iter().copied()); match decoder.collect() { Ok(v) => Ok(String::from_utf8(v).unwrap()), Err(c) => Err(c), } } #[cfg(test)] mod tests { use super::*; #[test] fn test_encode() { let encoded = encode("kaufen sie jede woche vier gute bequeme pelze xy 1234567890"); assert_eq!( encoded, Ok(vec![ 31, 15, 3, 7, 13, 1, 12, 4, 5, 6, 1, 4, 11, 1, 9, 1, 4, 19, 24, 14, 20, 1, 4, 30, 6, 1, 10, 4, 26, 7, 16, 1, 4, 25, 1, 23, 7, 1, 28, 1, 4, 22, 1, 18, 17, 1, 4, 29, 21, 4, 27, 23, 19, 1, 10, 16, 21, 7, 6, 24, 22 ]) ); } #[test] fn test_decode() { let kaufen_schleife: Vec = vec![ 31, 15, 3, 7, 13, 1, 12, 4, 5, 6, 1, 4, 11, 1, 9, 1, 4, 19, 24, 14, 20, 1, 4, 30, 6, 1, 10, 4, 26, 7, 16, 1, 4, 25, 1, 23, 7, 1, 28, 1, 4, 22, 1, 18, 17, 1, 4, 29, 21, 4, 27, 23, 19, 1, 10, 16, 21, 7, 6, 24, 22, ]; let decoded = decode(&kaufen_schleife); assert_eq!( Ok(String::from( "KAUFEN SIE JEDE WOCHE VIER GUTE BEQUEME PELZE XY 1234567890" )), decoded ) } }