use std::fmt;
pub use fmt::Result;
pub use fmt::Write;
use serde::Serialize;
pub struct IndentWriter<'i, W> {
writer: W,
indent: &'i str,
level: usize,
need_indent: bool,
}
impl<W> fmt::Debug for IndentWriter<'_, W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result {
f.debug_struct("IndentWriter")
.field("writer", &"W")
.field("indent", &self.indent)
.field("level", &self.level)
.field("need_indent", &self.need_indent)
.finish()
}
}
impl<W> IndentWriter<'_, W>
where
W: fmt::Write,
{
fn write_indent(&mut self) -> fmt::Result {
if self.level > 0 {
self.writer.write_str(self.indent)?;
}
Ok(())
}
}
impl<'i, W> IndentWriter<'i, W> {
pub fn new(indent: &'i str, writer: W) -> Self {
IndentWriter {
writer,
indent,
level: 0,
need_indent: true,
}
}
pub fn indent_str(&self) -> &str {
self.indent
}
}
impl<'i, W: fmt::Write> IndentWriter<'i, W> {
pub fn indent(&mut self) -> IndentWriter<'i, &mut IndentWriter<'i, W>> {
let indent = self.indent;
let level = self.level + 1;
IndentWriter {
writer: self,
indent,
level,
need_indent: true,
}
}
pub fn indent_skip_first(&mut self) -> IndentWriter<'i, &mut IndentWriter<'i, W>> {
let indent = self.indent;
let level = self.level + 1;
IndentWriter {
writer: self,
indent,
level,
need_indent: false,
}
}
pub fn write_json<T: Serialize>(&mut self, data: &T) -> fmt::Result {
let mut writer = Vec::with_capacity(128);
let fmt = serde_json::ser::PrettyFormatter::with_indent(self.indent_str().as_bytes());
let mut ser = serde_json::ser::Serializer::with_formatter(&mut writer, fmt);
data.serialize(&mut ser).unwrap();
#[allow(unsafe_code)]
let data = unsafe { String::from_utf8_unchecked(writer) };
self.write_str(&data)
}
}
impl<W> fmt::Write for IndentWriter<'_, W>
where
W: fmt::Write,
{
fn write_str(&mut self, mut s: &str) -> fmt::Result {
loop {
match self.need_indent {
false => match s.as_bytes().iter().position(|&b| b == b'\n') {
None => break self.writer.write_str(s),
Some(len) => {
let (head, tail) = s.split_at(len + 1);
self.writer.write_str(head)?;
self.need_indent = true;
s = tail;
}
},
true => match s.as_bytes().iter().position(|&b| b != b'\n') {
None => break self.writer.write_str(s),
Some(len) => {
let (head, tail) = s.split_at(len);
self.writer.write_str(head)?;
self.write_indent()?;
self.need_indent = false;
s = tail;
}
},
}
}
}
fn write_char(&mut self, c: char) -> fmt::Result {
if self.need_indent && c != '\n' {
self.write_indent()?;
self.need_indent = false;
}
if !self.need_indent && c == '\n' {
self.need_indent = true;
}
self.writer.write_char(c)
}
}
pub trait JWTFormat {
fn fmt<W: fmt::Write>(&self, f: &mut IndentWriter<'_, W>) -> fmt::Result;
fn fmt_indented<W: fmt::Write>(&self, f: &mut IndentWriter<'_, W>) -> fmt::Result {
let mut f = f.indent();
self.fmt(&mut f)
}
fn fmt_indented_skip_first<W: fmt::Write>(&self, f: &mut IndentWriter<'_, W>) -> fmt::Result {
let mut f = f.indent_skip_first();
self.fmt(&mut f)
}
fn formatted(&self) -> JWTFormatted<'_, Self> {
JWTFormatted(self)
}
}
pub struct JWTFormatted<'a, T: JWTFormat + ?Sized>(&'a T);
impl<T> fmt::Display for JWTFormatted<'_, T>
where
T: JWTFormat,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut formatter = IndentWriter::new(" ", f);
<T as JWTFormat>::fmt(self.0, &mut formatter)
}
}