machin 0.5.1

Machin is a cli program that simplifies file conversions and batch processing. It's inspired from filter/map/reduce
use image::imageops;
use image::io::Reader as ImageReader;
use image::DynamicImage::{ImageLuma8, ImageRgba8};
use std::error::Error;

use colored::Colorize;

use crate::machconvert::errors::{ArgConvertError, UnsupportedRotateError};
use crate::machconvert::{ConvertArgs, ConvertFlip};

impl<'a> ImageInputFile<'a> {
    pub fn new(input_file: &'a str, output_file: &'a str) -> ImageInputFile<'a> {
        ImageInputFile {
            input_file,
            output_file,
        }
    }
}

impl<'a> InputTo<'a> for ImageInputFile<'a> {
    fn convert(&self, args: &ConvertArgs) -> Result<String, Box<dyn Error + 'a>> {
        let e = UnsupportedRotateError {};
        let arg_e = ArgConvertError {};

        if None == args.color && None == args.flip && None == args.rotate {
            return Err(Box::new(arg_e));
        }

        let mut step = 1;
        let mut img = ImageReader::open(&self.input_file)?.decode()?;

        if args.color.is_some() {
            img = ImageLuma8(imageops::grayscale(&img));
            colored_success!(format!(
                "Step {} : apply a grayscale of {} to {}",
                step, self.input_file, self.output_file,
            ));
            step += 1;
        }

        if let Some(flip_value) = &args.flip {
            match flip_value {
                ConvertFlip::Horizontal => {
                    img = ImageRgba8(imageops::flip_horizontal(&img));
                    colored_success!(format!(
                        "Step {} : apply an horizontal flip of {} to {}",
                        step, self.input_file, self.output_file,
                    ));
                }
                ConvertFlip::Vertical => {
                    img = ImageRgba8(imageops::flip_vertical(&img));
                    colored_success!(format!(
                        "Step {} : apply a vertical flip of {} to {}",
                        step, self.input_file, self.output_file,
                    ));
                }
            }
            step += 1;
        }

        if let Some(r_value) = args.rotate {
            match r_value.parse::<i16>() {
                Ok(r) => {
                    if r == 90 || r == 180 || r == 270 {
                        if r == 90 {
                            img = ImageRgba8(imageops::rotate90(&img));
                        } else if r == 180 {
                            img = ImageRgba8(imageops::rotate180(&img));
                        } else {
                            img = ImageRgba8(imageops::rotate270(&img));
                        }
                        colored_success!(format!(
                            "Step {} : apply a {} degree rotation of {} to {}",
                            step, r_value, self.input_file, self.output_file,
                        ));
                    } else {
                        return Err(Box::new(e));
                    }
                }
                Err(_e) => return Err(Box::new(e)),
            };
        }

        img.save(self.output_file)?;
        Ok(String::new())
    }
}

#[macro_export]
macro_rules! create_convert_input {
    ($struct_name:ident) => {
        pub struct $struct_name<'a> {
            input_file: &'a str,
            output_file: &'a str,
        }
    };
}

pub trait InputTo<'a> {
    fn convert(&self, args: &ConvertArgs) -> Result<String, Box<dyn Error + 'a>>;
}

create_convert_input!(ImageInputFile);