use serde_json::{Map, Value};
use crate::wire;
#[cfg(test)]
mod tests;
pub(crate) const MAX_DEPTH: usize = 10;
pub(crate) const MAX_BREADTH: usize = 100;
pub(crate) const MAX_STRING_LENGTH: usize = 32_768;
const MAX_PROPERTIES: &str = "[MaxProperties ~]";
const TRUNCATION_SUFFIX: &str = "...";
pub(crate) fn normalize(
value: &Value,
depth: usize,
max_breadth: usize,
max_string_length: usize,
) -> Value {
match value {
Value::String(text) => {
if wire::utf16_len(text) > max_string_length {
let mut cut = wire::cut_utf16(text, max_string_length).to_owned();
cut.push_str(TRUNCATION_SUFFIX);
Value::String(cut)
} else {
value.clone()
}
}
Value::Array(items) => {
if depth == 0 {
return Value::String("[Array]".to_owned());
}
let mut result: Vec<Value> = items
.iter()
.take(max_breadth)
.map(|item| normalize(item, depth - 1, max_breadth, max_string_length))
.collect();
if items.len() > max_breadth {
result.push(Value::String(MAX_PROPERTIES.to_owned()));
}
Value::Array(result)
}
Value::Object(map) => {
if depth == 0 {
return Value::String("[Object]".to_owned());
}
let mut result = Map::new();
for (count, (key, item)) in wire::own_entries(map).enumerate() {
if count >= max_breadth {
result.insert("...".to_owned(), Value::String(MAX_PROPERTIES.to_owned()));
break;
}
let kept = normalize(item, depth - 1, max_breadth, max_string_length);
result.insert(key.clone(), kept);
}
Value::Object(result)
}
Value::Null | Value::Bool(_) | Value::Number(_) => value.clone(),
}
}