p101_enc 0.11.0

Library to convert Olivetti P101 program to and from different encodings
Documentation
mod codepage437;
mod larini_decoder;

pub use codepage437::*;
pub use larini_decoder::*;

use p101_is::*;
use crate::encoding::*;

pub struct Decoder<E: Encoding> {
    encoding: E,
    cai_mode: bool
}

impl<E> Decoder<E> where E: Encoding + Default {
    pub fn new() -> Self {
        Decoder {
            encoding: Default::default(),
            cai_mode: false
        }
    }

    pub fn decode(&mut self, text: &str) -> Result<Vec<Instruction>, String> {
        let mut program = Vec::new();
        let mut line_number = 1;

        for line in text.lines() {
            match self.decode_line(line) {
                DecodeResult::Ok(i) => {
                    self.set_mode(&i);
                    program.push(i)
                },
                DecodeResult::None => (),
                DecodeResult::Err(e) => {
                    return Err(format!("{} at line {}", e, line_number))
                }
            }

            line_number += 1
        }

        if !program.is_empty() {
            Ok(program)
        } else {
            Err("No text to decode".into())
        }
    }

    fn decode_line(&self, line: &str) -> DecodeResult {
        if self.cai_mode {
            self.encoding.decode_cai(line)
        } else {
            self.encoding.decode_instr(line)
        }
    }

    fn set_mode(&mut self, i: &Instruction) {
        match i {
            Instruction::Cai(_, order, _, _) => {
                self.cai_mode = *order == CaiOrder::Low;
            },
            Instruction::CaiStart => self.cai_mode = true,
            _ => ()
        }
    }
}

impl<E> Default for Decoder<E> where E: Encoding + Default {
    fn default() -> Self {
        Self::new()
    }
}