yason 0.0.2

Encoding and decoding support for YASON in Rust
Documentation
//! PrettyFormatter

use crate::format::{FormatResult, Formatter, WriteExt};
use crate::yason::LazyValue;
use crate::DataType;
use std::fmt;

struct PrettyOptions<'a> {
    indent: usize,
    newline_in_empty: bool,
    newline_in_nested: bool,
    kv_delimiter: &'a [u8],
}

impl<'a> PrettyOptions<'a> {
    #[inline]
    const fn new(indent: usize, newline_in_empty: bool, newline_in_nested: bool, kv_delimiter: &'a [u8]) -> Self {
        Self {
            indent,
            newline_in_empty,
            newline_in_nested,
            kv_delimiter,
        }
    }
}

pub struct PrettyFormatter<'a> {
    options: PrettyOptions<'a>,
    cur_indent_level: usize,
    has_value: bool,
}

impl<'a> PrettyFormatter<'a> {
    #[inline]
    pub(crate) const fn new() -> Self {
        Self {
            options: PrettyOptions::new(2, true, true, b" : "),
            cur_indent_level: 0,
            has_value: false,
        }
    }
}

impl Formatter for PrettyFormatter<'_> {
    #[inline]
    fn write_object_value<W: fmt::Write, const IN_ARRAY: bool>(
        &mut self,
        key: &str,
        value: &LazyValue<IN_ARRAY>,
        first: bool,
        writer: &mut W,
    ) -> FormatResult<()> {
        self.begin_object_key(first, writer)?;
        self.write_string(key, writer)?;
        self.end_object_key(writer)?;
        self.begin_object_value(writer)?;

        if matches!(value.data_type(), DataType::Object | DataType::Array) && self.options.newline_in_nested {
            writer.write_bytes(b"\n")?;
            indent(self.cur_indent_level, self.options.indent, writer)?;
        }

        self.write_lazy_value(value, writer)?;
        self.end_object_value(writer)
    }

    #[inline]
    fn begin_array<W: fmt::Write>(&mut self, writer: &mut W) -> FormatResult<()> {
        self.cur_indent_level += 1;
        self.has_value = false;
        writer.write_bytes(b"[")?;
        Ok(())
    }

    #[inline]
    fn end_array<W: fmt::Write>(&mut self, writer: &mut W) -> FormatResult<()> {
        self.cur_indent_level -= 1;

        if self.options.newline_in_empty || self.has_value {
            writer.write_bytes(b"\n")?;
            indent(self.cur_indent_level, self.options.indent, writer)?;
        }
        writer.write_bytes(b"]")?;
        Ok(())
    }

    #[inline]
    fn begin_array_value<W: fmt::Write>(&mut self, first: bool, writer: &mut W) -> FormatResult<()> {
        if first {
            writer.write_bytes(b"\n")?;
        } else {
            writer.write_bytes(b",\n")?;
        }
        indent(self.cur_indent_level, self.options.indent, writer)
    }

    #[inline]
    fn end_array_value<W: fmt::Write>(&mut self, _writer: &mut W) -> FormatResult<()> {
        self.has_value = true;
        Ok(())
    }

    #[inline]
    fn begin_object<W: fmt::Write>(&mut self, writer: &mut W) -> FormatResult<()> {
        self.cur_indent_level += 1;
        self.has_value = false;
        writer.write_bytes(b"{")?;
        Ok(())
    }

    #[inline]
    fn end_object<W: fmt::Write>(&mut self, writer: &mut W) -> FormatResult<()> {
        self.cur_indent_level -= 1;
        if self.options.newline_in_empty || self.has_value {
            writer.write_bytes(b"\n")?;
            indent(self.cur_indent_level, self.options.indent, writer)?;
        }
        writer.write_bytes(b"}")?;
        Ok(())
    }

    #[inline]
    fn begin_object_key<W: fmt::Write>(&mut self, first: bool, writer: &mut W) -> FormatResult<()> {
        if first {
            writer.write_bytes(b"\n")?;
        } else {
            writer.write_bytes(b",\n")?;
        }
        indent(self.cur_indent_level, self.options.indent, writer)
    }

    #[inline]
    fn begin_object_value<W: fmt::Write>(&mut self, writer: &mut W) -> FormatResult<()> {
        writer.write_bytes(self.options.kv_delimiter)?;
        Ok(())
    }

    #[inline]
    fn end_object_value<W: fmt::Write>(&mut self, _writer: &mut W) -> FormatResult<()> {
        self.has_value = true;
        Ok(())
    }
}

#[inline]
fn indent<W: fmt::Write>(level: usize, indent: usize, writer: &mut W) -> FormatResult<()> {
    const SPACE_BUF: [u8; 200] = [b' '; 200];
    writer.write_bytes(&SPACE_BUF[..level * indent])?;
    Ok(())
}