dirscan 1.2.0

A high performance tool for summarizing large directories or drives
use csv;
use std::fs::File;
use std::io;

use crate::directory_stat::DirectoryStat;
use std::io::Write;
use strum_macros::{Display, EnumString, EnumVariantNames};

#[derive(EnumString, EnumVariantNames, Display)]
#[strum(serialize_all = "kebab_case")]
pub enum Format {
    JSON,
    CSV,
}

impl Format {
    pub fn parse_file(&self, file: File) -> Box<dyn Iterator<Item = DirectoryStat>> {
        let reader = io::BufReader::new(file);
        match self {
            Self::JSON => Box::new(
                serde_json::Deserializer::from_reader(reader)
                    .into_iter::<DirectoryStat>()
                    .map(|f| f.unwrap()),
            ),
            Self::CSV => Box::new(
                csv::Reader::from_reader(reader)
                    .into_deserialize::<DirectoryStat>()
                    .map(|f| f.unwrap()),
            ),
        }
    }

    pub fn get_writer(&self, file: Box<dyn io::Write>) -> Box<dyn FormatWriter> {
        match self {
            Self::JSON => Box::new(JsonWriter::new(file)),
            Self::CSV => Box::new(CSVWriter::new(file)),
        }
    }
}

pub trait FormatWriter {
    fn new(_: Box<dyn io::Write>) -> Self
    where
        Self: Sized;
    fn write_stat(&mut self, stat: &DirectoryStat) -> io::Result<()>;
}

pub struct JsonWriter {
    writer: Box<dyn io::Write>,
}

impl FormatWriter for JsonWriter {
    fn new(writer: Box<dyn io::Write>) -> Self {
        JsonWriter { writer }
    }

    fn write_stat(&mut self, stat: &DirectoryStat) -> io::Result<()> {
        let res = serde_json::to_vec(stat).expect("Error serializing directory stat");
        self.writer.write_all(&res)?;
        writeln!(self.writer)?;
        Ok(())
    }
}

pub struct CSVWriter {
    csv_writer: csv::Writer<Box<dyn io::Write>>,
}

impl FormatWriter for CSVWriter {
    fn new(writer: Box<dyn Write>) -> Self {
        let csv_writer = csv::WriterBuilder::new()
            .has_headers(true)
            .from_writer(writer);
        CSVWriter { csv_writer }
    }

    fn write_stat(&mut self, stat: &DirectoryStat) -> io::Result<()> {
        self.csv_writer.serialize(stat)?;
        Ok(())
    }
}