p101_enc 0.11.0

Library to convert Olivetti P101 program to and from different encodings
Documentation
use crate::filter::*;

/// General options of the filter pipeline.
#[derive(Default)]
pub struct PipelineOptions {
    /// Filters will display error messages if the flag is set.
    pub display_errors: bool,

    /// Filters will display info messages if the flag is set.
    pub display_messages: bool,    
}

/// The stage is the pipeline work unit.
/// It defines the filter to apply to input data and
/// if the result should be saved for later inspection.
pub struct Stage {
    /// The filter to apply
    filter: Box<dyn Filter>,

    /// This flag will instruct the pipeline runner 
    /// to save filter output for later inspection.
    /// It is meant to be used to debug filters.
    inspect: bool
}

impl Stage {
    pub fn new(filter: Box<dyn Filter>, inspect: bool) -> Self {
        Self {
            filter,
            inspect
        }
    }
}

/// The filter pipeline defines how to transform input data
/// in the desired output. It executes a sequence of filters
/// piping a filter output to the next filter input.
pub struct Pipeline {
    /// Sequence of filters to apply
    stages: Vec<Stage>,

    /// Pileline running options
    options: PipelineOptions
}

pub struct PipelineOutput {
    pub output: EncodingData,
    pub inspections: Vec<EncodingData>,
}

impl Pipeline {
    /// Creates a new filter pipelines
    pub fn new(stages: Vec<Stage>, options: PipelineOptions) -> Pipeline {
        Self {
            stages,
            options,
        }
    }

    /// Run the filter pipeline consuming the input data to produce a new encoding data.
    /// If some filtering stage requires inspection, the result will contain a vector of
    /// filter output data.
    pub fn run(&self, data: EncodingData) -> std::result::Result<PipelineOutput, String> {
        let mut stage_data = Ok(data);
        let mut inspections: Vec::<EncodingData> = Vec::new();

        for stage in &self.stages {
            match stage_data {
                Ok(data) => {
                    self.message(&format!("running {}", stage.filter.name()));

                    stage_data = stage.filter.map(data);

                    if stage.inspect && stage_data.is_ok() {
                        inspections.push(stage_data.clone().unwrap());
                    }
                },
                Err(e) => {
                    self.error(&e);
                    return Err(e);
                },
            }
        }
    
        stage_data.map(|output| PipelineOutput {
            output,
            inspections,
        })
    }

    fn message(&self, text: &str) {
        if self.options.display_messages {
            println!("{}", text);
        }
    }

    fn error(&self, text: &str) {
        if self.options.display_errors {
            println!("error: {}", text);
        }
    }
}