tomq 0.1.2

jq, but from TOML
use crate::pager::{Bat, PagerHandleWriter};
use std::io::{Read, Write};

struct StdoutOutput;
struct BatOutput(String);
struct WriteOutput<W>(W);

pub(crate) fn output_to_stdout() -> impl CopyFromReader + Output {
    StdoutOutput
}

pub(crate) fn output_to_bat(language: &str) -> impl CopyFromReader + Output {
    BatOutput(language.to_string())
}

#[allow(dead_code)]
pub(crate) fn output_to_write<W: Write>(write: W) -> impl CopyFromReader {
    WriteOutput(write)
}

pub(crate) trait CopyFromReader {
    fn copy_from_reader<R: Read>(&mut self, reader: R) -> crate::error::Result<()>;
}

impl CopyFromReader for StdoutOutput {
    fn copy_from_reader<R: Read>(&mut self, mut reader: R) -> crate::error::Result<()> {
        let mut stdout = std::io::stdout().lock();
        std::io::copy(&mut reader, &mut stdout)?;
        Ok(())
    }
}

impl CopyFromReader for BatOutput {
    fn copy_from_reader<R: Read>(&mut self, reader: R) -> crate::error::Result<()> {
        let handle = Bat::new_handle(&self.0)?;
        handle.handle_read(reader)?;
        Ok(())
    }
}

impl<W: Write> CopyFromReader for WriteOutput<W> {
    fn copy_from_reader<R: Read>(&mut self, mut reader: R) -> crate::error::Result<()> {
        std::io::copy(&mut reader, &mut self.0)?;
        Ok(())
    }
}

pub(crate) trait Output {
    type Writer: OutputWriter;
    fn create_output_writer(&self) -> crate::error::Result<Self::Writer>
    where
        Self: Sized;
}

impl Output for StdoutOutput {
    type Writer = std::io::StdoutLock<'static>;
    fn create_output_writer(&self) -> crate::error::Result<Self::Writer> {
        Ok(std::io::stdout().lock())
    }
}

impl Output for BatOutput {
    type Writer = PagerHandleWriter;

    fn create_output_writer(&self) -> crate::error::Result<Self::Writer>
    where
        Self: Sized,
    {
        let handle = Bat::new_handle(&self.0)?;
        Ok(handle.into_writer())
    }
}

pub(crate) trait OutputWriter: Write {
    fn wait(self) -> crate::error::Result<i32>;
}

impl OutputWriter for std::io::StdoutLock<'static> {
    fn wait(self) -> crate::error::Result<i32> {
        Ok(0)
    }
}