#![allow(unused)]
use core::str;
use std::fmt::{
Write,
Formatter,
};
use std::str::FromStr;
use crate::{error::*, Number};
use crate::{
Value,
ValueMap,
};
impl std::fmt::Display for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
&Number::Float(float) => write!(f, "{}", float),
&Number::Int(int) => write!(f, "{}", int),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Indent {
Spaces(u8),
Tabs(u8),
}
impl std::fmt::Display for Indent {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
const SPACES: &'static str = unsafe { str::from_utf8_unchecked(&[b' '; 256]) };
const TABS: &'static str = unsafe { str::from_utf8_unchecked(&[b'\t'; 256]) };
match self {
&Self::Spaces(count) => write!(f, "{}", &SPACES[..count as usize]),
&Self::Tabs(count) => write!(f, "{}", &TABS[..count as usize]),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
struct JsonFormatter {
sameline: bool,
spacing: bool,
indent: Indent,
indent_level: u32,
}
struct Indentation<'a>(&'a JsonFormatter);
impl<'a> std::fmt::Display for Indentation<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for _ in 0..self.0.indent_level {
write!(f, "{}", self.0.indent)?;
}
Ok(())
}
}
impl JsonFormatter {
fn new(sameline: bool, spacing: bool, indent: Indent) -> Self {
Self::new_indented(0, sameline, spacing, indent)
}
fn new_indented(indent_level: u32, sameline: bool, spacing: bool, indent: Indent) -> Self {
Self {
sameline,
spacing,
indent,
indent_level: indent_level,
}
}
fn indent(&self) -> Self {
let mut indent = self.clone();
indent.indent_level += 1;
indent
}
#[inline(always)]
fn indentation(&self) -> Indentation<'_> {
Indentation(self)
}
fn write_indent<W: Write>(&self, writer: &mut W) -> std::fmt::Result {
write!(writer, "{}", self.indentation())
}
fn write_separator<W: Write>(&self, writer: &mut W) -> std::fmt::Result {
write!(writer, ",")?;
if !self.sameline {
write!(writer, "\n")?;
} else if self.spacing {
write!(writer, " ")?;
}
Ok(())
}
}
impl std::fmt::Display for JsonFormatter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if !self.sameline {
self.write_indent(f)?;
}
Ok(())
}
}
impl Default for Indent {
fn default() -> Self {
Self::Spaces(4)
}
}
fn hex_char(value: u16, slot: usize, lower_case: bool) -> char {
const HEX_CHARS_UPPER: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
const HEX_CHARS_LOWER: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
let shift = slot * 4;
let index = ((value & (0xf << shift)) >> shift) as usize;
if lower_case {
HEX_CHARS_LOWER[index]
} else {
HEX_CHARS_UPPER[index]
}
}
pub fn measure_escaped_string<S: AsRef<str>>(s: S) -> usize {
s.as_ref().chars().map(|c| {
match c {
'\\' => 2,
'"' => 2,
'\u{000c}' => 2,
'\u{0008}' => 2,
'\n' => 2,
'\r' => 2,
'\t' => 2,
'\u{0000}'..='\u{001f}' => 6,
_ => c.len_utf8(),
}
}).sum()
}
pub fn escape_string<S: AsRef<str>>(s: S) -> String {
let mut buffer = String::with_capacity(measure_escaped_string(s.as_ref()));
write_escaped_string(&mut buffer, s).unwrap();
buffer
}
fn write_escaped_string<W: Write, S: AsRef<str>>(writer: &mut W, s: S) -> std::fmt::Result {
s.as_ref().chars().try_for_each(|c| {
match c {
'\\' => write!(writer, "\\\\")?,
'"' => write!(writer, "\\\"")?,
'\u{000c}' => write!(writer, "\\f")?,
'\u{0008}' => write!(writer, "\\b")?,
'\n' => write!(writer, "\\n")?,
'\r' => write!(writer, "\\r")?,
'\t' => write!(writer, "\\t")?,
'\u{0000}'..='\u{001f}' => {
let hex = c as u16;
write!(writer, "\\u")?;
for i in (0..4).rev() {
write!(writer, "{}", hex_char(hex, i, true))?;
}
}
_ => write!(writer, "{c}")?,
}
Ok(())
})
}
fn write_null<W: Write>(writer: &mut W) -> std::fmt::Result {
write!(writer, "null")
}
fn write_boolean<W: Write>(writer: &mut W, value: bool) -> std::fmt::Result {
write!(writer, "{value}")
}
fn write_number<W: Write>(writer: &mut W, value: Number) -> std::fmt::Result {
write!(writer, "{value}")
}
fn write_string<W: Write>(writer: &mut W, value: &str) -> std::fmt::Result {
write!(writer, "\"")?;
write_escaped_string(writer, value)?;
write!(writer, "\"")
}
fn write_array<W: Write>(writer: &mut W, array: &[Value], formatter: JsonFormatter) -> std::fmt::Result {
write!(writer, "[")?;
if !formatter.sameline {
write!(writer, "\n")?;
}
let indented_formatter = formatter.indent();
array.iter().enumerate().try_for_each(|(index, value)| {
if !indented_formatter.sameline {
write!(writer, "{}", indented_formatter.indentation())?;
}
write_value(writer, value, indented_formatter)?;
if index + 1 != array.len() {
indented_formatter.write_separator(writer)?;
}
Ok(())
})?;
if !formatter.sameline {
write!(writer, "\n")?;
write!(writer, "{}", formatter.indentation())?;
}
write!(writer, "]")
}
fn write_object<W: Write>(writer: &mut W, object: &ValueMap, formatter: JsonFormatter) -> std::fmt::Result {
write!(writer, "{{")?;
if !formatter.sameline {
write!(writer, "\n")?;
}
let indent = formatter.indent();
object.iter().enumerate().try_for_each(|(index, (key, value))| {
if !indent.sameline {
write!(writer, "{}", indent.indentation())?;
}
write_string(writer, key)?;
if indent.spacing {
write!(writer, " : ")?;
} else {
write!(writer, ":")?;
}
write_value(writer, value, indent)?;
if index + 1 != object.len() {
indent.write_separator(writer)?;
}
Ok(())
})?;
if !formatter.sameline {
write!(writer, "\n")?;
write!(writer, "{}", formatter.indentation())?;
}
write!(writer, "}}")
}
fn write_value<W: Write>(writer: &mut W, value: &Value, formatter: JsonFormatter) -> std::fmt::Result {
match value {
Value::Null => write_null(writer),
&Value::Boolean(boolean) => write_boolean(writer, boolean),
&Value::Number(number) => write_number(writer, number),
Value::String(string) => write_string(writer, string),
Value::Array(array) => write_array(writer, array, formatter),
Value::Object(object) => write_object(writer, object, formatter),
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write_value(f, self, JsonFormatter::new(true, false, Indent::Spaces(0)))
}
}
pub struct PrettyPrint<'a>(&'a Value, Indent, bool);
impl<'a> std::fmt::Display for PrettyPrint<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write_value(f, self.0, JsonFormatter::new(false, self.2, self.1))
}
}
impl Value {
pub fn pretty_print_format(&self, indent: Indent, spacing: bool) -> PrettyPrint<'_> {
PrettyPrint(self, indent, spacing)
}
pub fn pretty_print(&self) -> PrettyPrint<'_> {
PrettyPrint(self, Indent::Spaces(4), true)
}
}