Move to streaming style encoders and decoders
This commit is contained in:
parent
1624db615b
commit
7fc5be5f03
167
src/baudot.rs
167
src/baudot.rs
|
@ -50,63 +50,140 @@ enum ShiftState {
|
||||||
Figures,
|
Figures,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(msg: &str) -> Result<Vec<u8>, u8> {
|
struct Encoder<'a> {
|
||||||
let mut res = Vec::<u8>::new();
|
shift_state: ShiftState,
|
||||||
|
buffer: Option<u8>,
|
||||||
let mut shift = ShiftState::None;
|
iterator: Box<dyn Iterator<Item = u8> + 'a>,
|
||||||
|
|
||||||
for &byte in msg.to_ascii_uppercase().as_bytes().iter() {
|
|
||||||
let letter = code_from_letter(&byte);
|
|
||||||
let figure = code_from_figure(&byte);
|
|
||||||
match (letter, figure, shift) {
|
|
||||||
(Some(l), Some(_), ShiftState::None) => {
|
|
||||||
res.push(SHIFT_LETTERS);
|
|
||||||
shift = ShiftState::Letters;
|
|
||||||
res.push(l);
|
|
||||||
}
|
|
||||||
(Some(l), Some(_), _) => res.push(l),
|
|
||||||
(Some(l), None, ShiftState::Letters) => res.push(l),
|
|
||||||
(Some(l), None, _) => {
|
|
||||||
res.push(SHIFT_LETTERS);
|
|
||||||
shift = ShiftState::Letters;
|
|
||||||
res.push(l);
|
|
||||||
}
|
|
||||||
(None, Some(f), ShiftState::Figures) => res.push(f),
|
|
||||||
(None, Some(f), _) => {
|
|
||||||
res.push(SHIFT_FIGURES);
|
|
||||||
shift = ShiftState::Figures;
|
|
||||||
res.push(f);
|
|
||||||
}
|
|
||||||
(None, None, _) => return Err(byte),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(msg: &Vec<u8>) -> Result<String, u8> {
|
impl<'a> Encoder<'a> {
|
||||||
let mut res = String::new();
|
pub fn from<I>(iterator: I) -> Encoder<'a>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = u8> + 'a,
|
||||||
|
{
|
||||||
|
Encoder {
|
||||||
|
shift_state: ShiftState::None,
|
||||||
|
buffer: None,
|
||||||
|
iterator: Box::new(iterator),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Lets assume this is a sane starting point.
|
impl<'a> Iterator for Encoder<'a> {
|
||||||
let mut shift = ShiftState::Letters;
|
type Item = Result<u8, u8>;
|
||||||
|
|
||||||
for &code in msg.iter() {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match (code, shift) {
|
if let Some(c) = self.buffer {
|
||||||
(SHIFT_LETTERS, _) => shift = ShiftState::Letters,
|
self.buffer = None;
|
||||||
(SHIFT_FIGURES, _) => shift = ShiftState::Figures,
|
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(byte)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode(msg: &str) -> Result<Vec<u8>, u8> {
|
||||||
|
let encoder = Encoder::from(msg.to_ascii_uppercase().into_bytes().into_iter());
|
||||||
|
encoder.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Decoder<'a> {
|
||||||
|
shift_state: ShiftState,
|
||||||
|
iterator: Box<dyn Iterator<Item = u8> + 'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Decoder<'a> {
|
||||||
|
pub fn from<I>(iterator: I) -> Decoder<'a>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = u8> + 'a,
|
||||||
|
{
|
||||||
|
Decoder {
|
||||||
|
shift_state: ShiftState::Letters,
|
||||||
|
iterator: Box::new(iterator),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for Decoder<'a> {
|
||||||
|
// Option<Result<u8, u8>> 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<u8, u8>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
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) {
|
(c, ShiftState::Letters) => match letter_from_code(c) {
|
||||||
Some(l) => res.push(l as char),
|
Some(l) => Some(Ok(l)),
|
||||||
None => return Err(c),
|
None => Some(Err(c)),
|
||||||
},
|
},
|
||||||
(c, ShiftState::Figures) => match figure_from_code(c) {
|
(c, ShiftState::Figures) => match figure_from_code(c) {
|
||||||
Some(l) => res.push(l as char),
|
Some(f) => Some(Ok(f)),
|
||||||
None => return Err(c),
|
None => Some(Err(c)),
|
||||||
},
|
},
|
||||||
(_, ShiftState::None) => panic!("Shift state is expectedly None"),
|
(_, ShiftState::None) => panic!("Shift state is expectedly None"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(res)
|
pub fn decode(msg: &Vec<u8>) -> Result<String, u8> {
|
||||||
|
let decoder = Decoder::from(msg.iter().copied());
|
||||||
|
match decoder.collect() {
|
||||||
|
Ok(v) => Ok(String::from_utf8(v).unwrap()),
|
||||||
|
Err(c) => Err(c),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue