use crate::serde::byte_keys_as_strings;
use crate::serde::bytes_as_string;
use crate::value::Value;
use crate::value::error::Error;
use crate::value::list::List;
use crate::value::map::Map;
use indexmap::IndexMap;
use serde::Serialize;
pub fn json(value: Value) -> Result<Vec<u8>, Error> {
serde_json::to_vec(&Strategy::new(value)).map_err(|e| Error::Format(e.to_string()))
}
pub fn json_pretty(value: Value) -> Result<Vec<u8>, Error> {
serde_json::to_vec_pretty(&Strategy::new(value)).map_err(|e| Error::Format(e.to_string()))
}
pub fn json_string(value: Value) -> Result<String, Error> {
serde_json::to_string(&Strategy::new(value)).map_err(|e| Error::Format(e.to_string()))
}
pub fn json_string_pretty(value: Value) -> Result<String, Error> {
serde_json::to_string_pretty(&Strategy::new(value)).map_err(|e| Error::Format(e.to_string()))
}
pub fn yaml(value: Value) -> Result<String, Error> {
serde_yaml::to_string(&Strategy::new(value)).map_err(|e| Error::Format(e.to_string()))
}
#[derive(Serialize)]
#[serde(untagged)]
enum Strategy {
Default(Box<Value>),
Simple(Simple),
}
impl Strategy {
fn new(value: Value) -> Strategy {
match value.meta().get(b"internal-serialize") == Some(b"simple") {
true => Strategy::Simple(Simple::new(value)),
false => Strategy::Default(Box::new(value)),
}
}
}
#[derive(Serialize)]
#[serde(untagged)]
enum Simple {
Bytes(SimpleBytes),
List(SimpleList),
Map(SimpleMap),
}
impl Simple {
fn new(value: Value) -> Self {
match value {
Value::List(v) if should_concat(&value) => Simple::Bytes(SimpleBytes(v.join())),
Value::Map(v) if should_concat(&value) => Simple::Bytes(SimpleBytes(v.join())),
Value::Bytes(v) => Simple::Bytes(SimpleBytes(v.join())),
Value::List(v) => Simple::List(SimpleList::new(v)),
Value::Map(v) => Simple::Map(SimpleMap::new(v)),
}
}
}
#[derive(Serialize)]
struct SimpleBytes(#[serde(with = "bytes_as_string")] Vec<u8>);
#[derive(Serialize)]
struct SimpleList(Vec<Simple>);
impl SimpleList {
fn new(value: List) -> Self {
SimpleList(value.data.into_iter().map(Simple::new).collect())
}
}
#[derive(Serialize)]
pub(crate) struct SimpleMap(
#[serde(with = "byte_keys_as_strings")] IndexMap<Vec<u8>, Simple, ahash::RandomState>,
);
impl SimpleMap {
fn new(value: Map) -> Self {
SimpleMap(
value
.data
.into_iter()
.map(|(k, v)| (k, Simple::new(v)))
.collect(),
)
}
}
fn should_concat(value: &Value) -> bool {
value.meta().get(b"internal-format") == Some(b"concat")
}