use core::fmt;
use printer::JsonPrinter;
use sizes::JsonSizesVisitor;
use crate::visitor::JsonVisit;
mod printer;
pub(crate) mod sizes;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Indent {
Spaces(u8),
Tabs(u8),
}
impl Indent {
pub fn by(self, n: usize) -> IndentBy {
IndentBy(self, n)
}
}
impl fmt::Display for Indent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Spaces(n) => {
for _ in 0..*n {
f.write_str(" ")?
}
}
Self::Tabs(n) => {
for _ in 0..*n {
f.write_str("\t")?
}
}
}
Ok(())
}
}
pub struct IndentBy(Indent, usize);
impl fmt::Display for IndentBy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for _ in 0..self.1 {
self.0.fmt(f)?
}
Ok(())
}
}
pub struct Spaces(pub usize);
impl fmt::Display for Spaces {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for _ in 0..self.0 {
f.write_str(" ")?
}
Ok(())
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Padding {
Spaces(u8),
NewLine,
}
impl fmt::Display for Padding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Spaces(n) => {
for _ in 0..*n {
f.write_str(" ")?
}
}
Self::NewLine => f.write_str("\n")?,
}
Ok(())
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Limit {
Always,
Item(usize),
Width(usize),
ItemOrWidth(usize, usize),
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub struct JsonPrintOptions {
pub indent: Indent,
pub array_begin: usize,
pub array_end: usize,
pub array_empty: usize,
pub array_before_comma: usize,
pub array_after_comma: usize,
pub array_limit: Option<Limit>,
pub object_begin: usize,
pub object_end: usize,
pub object_empty: usize,
pub object_before_comma: usize,
pub object_after_comma: usize,
pub object_before_colon: usize,
pub object_after_colon: usize,
pub object_limit: Option<Limit>,
}
impl JsonPrintOptions {
pub const PRETTY: Self = Self {
indent: Indent::Spaces(2),
array_begin: 1,
array_end: 1,
array_empty: 0,
array_before_comma: 0,
array_after_comma: 1,
array_limit: Some(Limit::ItemOrWidth(1, 16)),
object_begin: 1,
object_end: 1,
object_empty: 0,
object_before_comma: 0,
object_after_comma: 1,
object_before_colon: 0,
object_after_colon: 1,
object_limit: Some(Limit::ItemOrWidth(1, 16)),
};
pub const COMPACT: Self = Self {
indent: Indent::Spaces(0),
array_begin: 0,
array_end: 0,
array_empty: 0,
array_before_comma: 0,
array_after_comma: 0,
array_limit: None,
object_begin: 0,
object_end: 0,
object_empty: 0,
object_before_comma: 0,
object_after_comma: 0,
object_before_colon: 0,
object_after_colon: 0,
object_limit: None,
};
pub const INLINE: Self = Self {
indent: Indent::Spaces(0),
array_begin: 1,
array_end: 1,
array_empty: 0,
array_before_comma: 0,
array_after_comma: 1,
array_limit: None,
object_begin: 1,
object_end: 1,
object_empty: 0,
object_before_comma: 0,
object_after_comma: 1,
object_before_colon: 0,
object_after_colon: 1,
object_limit: None,
};
}
pub trait JsonPrint {
#[inline(always)]
fn pretty_print(&self) -> Printed<'_, 'static, Self> {
self.print_with(&JsonPrintOptions::PRETTY)
}
#[inline(always)]
fn compact_print(&self) -> Printed<'_, 'static, Self> {
self.print_with(&JsonPrintOptions::COMPACT)
}
#[inline(always)]
fn inline_print(&self) -> Printed<'_, 'static, Self> {
self.print_with(&JsonPrintOptions::INLINE)
}
#[inline(always)]
fn print_with<'o>(&self, options: &'o JsonPrintOptions) -> Printed<'_, 'o, Self> {
Printed(self, options, 0)
}
fn fmt_with(
&self,
f: &mut fmt::Formatter,
options: &JsonPrintOptions,
indent: usize,
) -> fmt::Result;
}
impl<T: JsonVisit> JsonPrint for T {
fn fmt_with(
&self,
f: &mut fmt::Formatter,
options: &JsonPrintOptions,
indent: usize,
) -> fmt::Result {
let mut sizes = Vec::new();
self.visit(JsonSizesVisitor::new(options, &mut sizes));
let mut offset = 0;
self.visit(JsonPrinter::new(options, &sizes, &mut offset, indent, f))
}
}
pub struct Printed<'t, 'o, T: ?Sized>(&'t T, &'o JsonPrintOptions, usize);
impl<T: JsonPrint> fmt::Display for Printed<'_, '_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt_with(f, self.1, self.2)
}
}