extern crate colored;
extern crate serde;
extern crate serde_json;
use colored::Colorize;
use serde::ser::Serialize;
use serde_json::ser::{CharEscape, Formatter, Serializer};
use serde_json::value::Value;
use std::io::{Result, Write};
use std::str;
macro_rules! colorize {
($s:expr, $color:expr) => {{
let colored_string = match *$color {
Color::Black => $s.black(),
Color::Blue => $s.blue(),
Color::Cyan => $s.cyan(),
Color::Green => $s.green(),
Color::Magenta => $s.magenta(),
Color::Purple => $s.purple(),
Color::Red => $s.red(),
Color::White => $s.white(),
Color::Yellow => $s.yellow(),
Color::Plain => $s.normal(),
};
colored_string.to_string()
}};
}
#[derive(Clone)]
pub enum Color {
Black,
Blue,
Cyan,
Green,
Magenta,
Purple,
Red,
White,
Yellow,
Plain,
}
impl Default for Color {
fn default() -> Self {
Color::Plain
}
}
#[derive(Default)]
pub struct ColorizerBuilder {
null: Color,
boolean: Color,
number: Color,
string: Color,
key: Color,
escape_sequence: Color,
}
impl ColorizerBuilder {
fn new() -> Self {
Default::default()
}
pub fn null(&mut self, color: Color) -> &mut Self {
self.null = color;
self
}
pub fn boolean(&mut self, color: Color) -> &mut Self {
self.boolean = color;
self
}
pub fn number(&mut self, color: Color) -> &mut Self {
self.number = color;
self
}
pub fn string(&mut self, color: Color) -> &mut Self {
self.string = color;
self
}
pub fn key(&mut self, color: Color) -> &mut Self {
self.key = color;
self
}
pub fn escape_sequence(&mut self, color: Color) -> &mut Self {
self.escape_sequence = color;
self
}
pub fn build(&self) -> Colorizer {
Colorizer {
null: self.null.clone(),
boolean: self.boolean.clone(),
number: self.number.clone(),
string: self.string.clone(),
key: self.key.clone(),
escape_sequence: self.escape_sequence.clone(),
indent_level: 0,
current_is_key: false,
}
}
}
#[derive(Clone, Default)]
pub struct Colorizer {
pub null: Color,
pub boolean: Color,
pub number: Color,
pub string: Color,
pub key: Color,
escape_sequence: Color,
indent_level: usize,
current_is_key: bool,
}
impl Colorizer {
pub fn new() -> ColorizerBuilder {
ColorizerBuilder::new()
}
pub fn arbitrary() -> Self {
Colorizer::new()
.null(Color::Cyan)
.boolean(Color::Yellow)
.number(Color::Magenta)
.string(Color::Green)
.key(Color::Blue)
.escape_sequence(Color::Red)
.build()
}
pub fn colorize_json_str(&self, s: &str) -> Result<String> {
let value: Value = ::serde_json::from_str(s)?;
let vec = self.to_vec(&value)?;
let string = unsafe { String::from_utf8_unchecked(vec) };
Ok(string)
}
pub fn colorize_to_writer<W>(&self, s: &str, writer: &mut W) -> Result<()>
where
W: Write,
{
let value: Value = ::serde_json::from_str(s)?;
self.to_writer(writer, &value)
}
fn to_vec<T: ?Sized>(&self, value: &T) -> Result<Vec<u8>>
where
T: Serialize,
{
let mut writer = Vec::with_capacity(128);
self.to_writer(&mut writer, value)?;
Ok(writer)
}
fn to_writer<W: ?Sized, T: ?Sized>(&self, writer: &mut W, value: &T) -> Result<()>
where
W: Write,
T: Serialize,
{
let mut ser = Serializer::with_formatter(writer, self.clone());
value.serialize(&mut ser)?;
Ok(())
}
#[inline]
fn get_indentation(&self) -> String {
(0..self.indent_level * 2).map(|_| ' ').collect()
}
#[inline]
fn get_string_color(&self) -> &Color {
if self.current_is_key {
&self.key
} else {
&self.string
}
}
}
impl Formatter for Colorizer {
fn write_null<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
write!(writer, "{}", colorize!("null", &self.null))
}
fn write_bool<W: ?Sized>(&mut self, writer: &mut W, value: bool) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.boolean))
}
fn write_i8<W: ?Sized>(&mut self, writer: &mut W, value: i8) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_i16<W: ?Sized>(&mut self, writer: &mut W, value: i16) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_i32<W: ?Sized>(&mut self, writer: &mut W, value: i32) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_i64<W: ?Sized>(&mut self, writer: &mut W, value: i64) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_u8<W: ?Sized>(&mut self, writer: &mut W, value: u8) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_u16<W: ?Sized>(&mut self, writer: &mut W, value: u16) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_u32<W: ?Sized>(&mut self, writer: &mut W, value: u32) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_u64<W: ?Sized>(&mut self, writer: &mut W, value: u64) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_f32<W: ?Sized>(&mut self, writer: &mut W, value: f32) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn write_f64<W: ?Sized>(&mut self, writer: &mut W, value: f64) -> Result<()>
where
W: Write,
{
let value_as_string = format!("{}", value);
write!(writer, "{}", colorize!(&value_as_string, &self.number))
}
fn begin_string<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
write!(writer, "{}", colorize!("\"", self.get_string_color()))
}
fn end_string<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
write!(writer, "{}", colorize!("\"", self.get_string_color()))
}
fn write_string_fragment<W: ?Sized>(&mut self, writer: &mut W, fragment: &str) -> Result<()>
where
W: Write,
{
write!(writer, "{}", colorize!(fragment, self.get_string_color()))
}
fn write_char_escape<W: ?Sized>(
&mut self,
writer: &mut W,
char_escape: CharEscape,
) -> Result<()>
where
W: Write,
{
let s = match char_escape {
CharEscape::Quote => "\\\"",
CharEscape::ReverseSolidus => "\\\\",
CharEscape::Solidus => "\\/",
CharEscape::Backspace => "\\b",
CharEscape::FormFeed => "\\f",
CharEscape::LineFeed => "\\n",
CharEscape::CarriageReturn => "\\r",
CharEscape::Tab => "\\t",
CharEscape::AsciiControl(byte) => {
let hex_digits = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
];
let mut bytes = "\\u00".to_string();
bytes.push(hex_digits[(byte >> 4) as usize]);
bytes.push(hex_digits[(byte & 0xF) as usize]);
return write!(writer, "{}", colorize!(bytes, &self.escape_sequence));
}
};
write!(writer, "{}", colorize!(s, &self.escape_sequence))
}
fn begin_array<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
self.indent_level += 1;
write!(writer, "[")
}
fn end_array<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
self.indent_level -= 1;
write!(writer, "\n{}]", self.get_indentation())
}
fn begin_array_value<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> Result<()>
where
W: Write,
{
if !first {
write!(writer, ",")?;
}
write!(writer, "\n{}", self.get_indentation())
}
fn begin_object_key<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> Result<()>
where
W: Write,
{
if !first {
write!(writer, ",")?;
}
self.current_is_key = true;
write!(writer, "\n{}", self.get_indentation())
}
fn end_object_key<W: ?Sized>(&mut self, _writer: &mut W) -> Result<()>
where
W: Write,
{
self.current_is_key = false;
Ok(())
}
fn begin_object_value<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
write!(writer, ": ")
}
fn begin_object<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
self.indent_level += 1;
write!(writer, "{{")
}
fn end_object<W: ?Sized>(&mut self, writer: &mut W) -> Result<()>
where
W: Write,
{
self.indent_level -= 1;
write!(writer, "\n{}}}", self.get_indentation())
}
}