use duper::{
DuperFloat, DuperIdentifier, DuperObject, DuperTemporal, DuperValue,
format::{
format_boolean, format_duper_bytes, format_duper_string, format_float, format_integer,
format_key, format_null, format_temporal,
},
visitor::DuperVisitor,
};
use yoke::Yoke;
use crate::{accessor::DuperAccessor, types::DuperType};
pub(crate) enum FormatterAtom {
Fixed(String),
Dynamic {
accessor: Box<dyn DuperAccessor>,
cast_to: Option<DuperType>,
raw: bool,
},
}
pub(crate) struct Formatter {
atoms: Vec<FormatterAtom>,
}
impl Formatter {
pub(crate) fn new(atoms: Vec<FormatterAtom>) -> Self {
Self {
atoms: atoms
.into_iter()
.filter_map(|atom| match &atom {
FormatterAtom::Fixed(string) if string.is_empty() => None,
_ => Some(atom),
})
.collect(),
}
}
pub(crate) fn format(&mut self, value: Yoke<DuperValue<'static>, String>) -> String {
let mut buf = String::new();
let inner = value.get();
for atom in &self.atoms {
match atom {
FormatterAtom::Fixed(fixed) => buf.push_str(fixed),
FormatterAtom::Dynamic {
accessor,
cast_to,
raw,
} => match accessor.access(inner).next() {
Some(value) => {
if let Some(typ) = cast_to {
if let Some(value) = typ.cast(value) {
DynamicVisitor {
buf: &mut buf,
raw: *raw,
}
.visit(&value);
} else {
buf.push_str("<INVALID CAST>")
}
} else {
DynamicVisitor {
buf: &mut buf,
raw: *raw,
}
.visit(value);
}
}
None => buf.push_str("<MISSING>"),
},
}
}
buf
}
}
struct DynamicVisitor<'buf> {
buf: &'buf mut String,
raw: bool,
}
impl<'buf> DynamicVisitor<'buf> {
pub(crate) fn visit<'a>(mut self, value: &'a DuperValue<'a>) {
value.accept(&mut self);
}
}
impl<'buf> DuperVisitor for DynamicVisitor<'buf> {
type Value = ();
fn visit_object<'a>(
&mut self,
identifier: Option<&DuperIdentifier<'a>>,
object: &DuperObject<'a>,
) -> Self::Value {
let len = object.len();
if !self.raw
&& let Some(identifier) = identifier
{
self.buf.push_str(identifier.as_ref());
self.buf.push_str("({");
for (i, (key, value)) in object.iter().enumerate() {
self.buf.push_str(&format_key(key));
self.buf.push_str(": ");
value.accept(self);
if i < len - 1 {
self.buf.push_str(", ");
}
}
self.buf.push_str("})");
} else {
self.buf.push('{');
for (i, (key, value)) in object.iter().enumerate() {
self.buf.push_str(&format_key(key));
self.buf.push_str(": ");
value.accept(self);
if i < len - 1 {
self.buf.push_str(", ");
}
}
self.buf.push('}');
}
}
fn visit_array<'a>(
&mut self,
identifier: Option<&DuperIdentifier<'a>>,
array: &[DuperValue<'a>],
) -> Self::Value {
let len = array.len();
if !self.raw
&& let Some(identifier) = identifier
{
self.buf.push_str(identifier.as_ref());
self.buf.push_str("([");
for (i, value) in array.iter().enumerate() {
value.accept(self);
if i < len - 1 {
self.buf.push_str(", ");
}
}
self.buf.push_str("])");
} else {
self.buf.push('[');
for (i, value) in array.iter().enumerate() {
value.accept(self);
if i < len - 1 {
self.buf.push_str(", ");
}
}
self.buf.push(']');
}
}
fn visit_tuple<'a>(
&mut self,
identifier: Option<&DuperIdentifier<'a>>,
tuple: &[DuperValue<'a>],
) -> Self::Value {
let len = tuple.len();
if !self.raw
&& let Some(identifier) = identifier
{
self.buf.push_str(identifier.as_ref());
self.buf.push_str("((");
for (i, value) in tuple.iter().enumerate() {
value.accept(self);
if i < len - 1 {
self.buf.push_str(", ");
}
}
self.buf.push_str("))");
} else {
self.buf.push('(');
for (i, value) in tuple.iter().enumerate() {
value.accept(self);
if i < len - 1 {
self.buf.push_str(", ");
}
}
self.buf.push(')');
}
}
fn visit_string<'a>(
&mut self,
identifier: Option<&DuperIdentifier<'a>>,
value: &'a str,
) -> Self::Value {
if self.raw {
self.buf.push_str(value.as_ref());
} else if let Some(identifier) = identifier {
let value = format_duper_string(value);
self.buf.push_str(&format!("{identifier}({value})"));
} else {
self.buf.push_str(&format_duper_string(value));
}
}
fn visit_bytes<'a>(
&mut self,
identifier: Option<&DuperIdentifier<'a>>,
bytes: &'a [u8],
) -> Self::Value {
if !self.raw
&& let Some(identifier) = identifier
{
let bytes = format_duper_bytes(bytes);
self.buf.push_str(&format!("{identifier}({bytes})"));
} else {
self.buf.push_str(&format_duper_bytes(bytes));
}
}
fn visit_temporal<'a>(&mut self, temporal: &DuperTemporal<'a>) -> Self::Value {
let identifier = temporal.identifier();
if self.raw {
self.buf.push_str(temporal.as_ref());
} else if let Some(identifier) = identifier {
let value = format_temporal(temporal);
self.buf.push_str(&format!("{identifier}({value})"));
} else {
self.buf.push_str(&format_temporal(temporal));
}
}
fn visit_integer(
&mut self,
identifier: Option<&DuperIdentifier<'_>>,
integer: i64,
) -> Self::Value {
if !self.raw
&& let Some(identifier) = identifier
{
let value = format_integer(integer);
self.buf.push_str(&format!("{identifier}({value})"));
} else {
self.buf.push_str(&format_integer(integer));
}
}
fn visit_float(
&mut self,
identifier: Option<&DuperIdentifier<'_>>,
float: DuperFloat,
) -> Self::Value {
if !self.raw
&& let Some(identifier) = identifier
{
let value = format_float(float);
self.buf.push_str(&format!("{identifier}({value})"));
} else {
self.buf.push_str(&format_float(float));
}
}
fn visit_boolean(
&mut self,
identifier: Option<&DuperIdentifier<'_>>,
boolean: bool,
) -> Self::Value {
if !self.raw
&& let Some(identifier) = identifier
{
let value = format_boolean(boolean);
self.buf.push_str(&format!("{identifier}({value})"));
} else {
self.buf.push_str(format_boolean(boolean));
}
}
fn visit_null(&mut self, identifier: Option<&DuperIdentifier<'_>>) -> Self::Value {
if !self.raw
&& let Some(identifier) = identifier
{
let value = format_null();
self.buf.push_str(&format!("{identifier}({value})"));
} else {
self.buf.push_str(format_null());
}
}
}