scratch-server 1.0.1

Simple HTTP Server
Documentation
use std::{error::Error, io::Write};

use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

pub struct Logger {
    out_writer: BufferWriter,
    err_writer: BufferWriter,
}

impl Logger {
    pub fn new() -> Logger {
        Logger {
            out_writer: BufferWriter::stdout(ColorChoice::Auto),
            err_writer: BufferWriter::stderr(ColorChoice::Auto),
        }
    }

    #[allow(dead_code)]
    pub fn log_stderr(
        &self,
        fmtstr: &str,
        args: Vec<(String, Option<Color>)>,
    ) -> Result<(), Box<dyn Error>> {
        self.log(fmtstr, args, &self.err_writer)?;
        Ok(())
    }

    #[allow(dead_code)]
    pub fn log_stdout(
        &self,
        fmtstr: &str,
        args: Vec<(String, Option<Color>)>,
    ) -> Result<(), Box<dyn Error>> {
        self.log(fmtstr, args, &self.out_writer)?;
        Ok(())
    }

    fn log(
        &self,
        fmtstr: &str,
        args: Vec<(String, Option<Color>)>,
        writer: &BufferWriter,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let mut buffer = writer.buffer();
        let mut arg_iter = args.iter();
        let mut char_iter = fmtstr.chars();
        let mut current = char_iter.next();
        let mut count = 0;
        let mut color_spec = ColorSpec::new();
        while let Some(c) = current {
            match c {
                '{' => {
                    let c = char_iter.next();
                    match c {
                        Some('}') => {
                            if let Some((s, color)) = arg_iter.next() {
                                if !s.is_empty() {
                                    color_spec.set_fg(*color);
                                    buffer.set_color(&color_spec)?;
                                    buffer.write_all(s.as_bytes())?;
                                    if color.is_some() {
                                        buffer.reset()?;
                                    }
                                }
                                count += 1;
                            } else {
                                return Err(Box::from(format!(
                                    "Not enough arguments (need more than {})",
                                    count
                                )));
                            }
                        }
                        Some('{') => {
                            buffer.write_all(b"{")?;
                        }
                        _ => {
                            return Err(Box::from("{{ not closed"));
                        }
                    }
                }
                '}' => {
                    let c = char_iter.next();
                    match c {
                        Some('}') => {
                            buffer.write_all(b"}")?;
                        }
                        _ => {
                            return Err(Box::from("}} not closed"));
                        }
                    }
                }
                c => {
                    let mut buf = [0; 4];
                    buffer.write_all(c.encode_utf8(&mut buf).as_bytes())?;
                }
            }
            current = char_iter.next();
        }
        buffer.write_all(b"\n")?;
        self.out_writer.print(&buffer)?;
        Ok(())
    }
}

impl Default for Logger {
    fn default() -> Self {
        Logger::new()
    }
}