use crate::error::{Error, Result};
use crate::value::Value;
use super::helpers::{needs_raw_marker, push_indent};
use super::object::render_object_body;
fn has_sole_terminator_line(s: &str, term: &str) -> bool {
s.split('\n').any(|line| line.trim() == term)
}
pub(super) fn render_array_item(value: &Value, indent: usize, out: &mut String) -> Result<()> {
push_indent(out, indent);
match value {
Value::Null => {
out.push_str("null\n");
}
Value::Bool(b) => {
out.push_str(if *b { "true" } else { "false" });
out.push('\n');
}
Value::Integer(s) => {
out.push_str(":i ");
out.push_str(s);
out.push('\n');
}
Value::Float(s) => {
out.push_str(":f ");
out.push_str(s);
out.push('\n');
}
Value::String(s) => {
if s.contains('\n') {
let has_sole_single = has_sole_terminator_line(s, ")");
let has_sole_double = has_sole_terminator_line(s, "))");
let has_leading_ws = s
.split('\n')
.any(|line| !line.is_empty() && line.starts_with(|c: char| c.is_whitespace()));
let stripped_ok = !has_sole_single && !has_leading_ws;
let verbatim_ok = !has_sole_double;
if !stripped_ok && !verbatim_ok {
return Err(Error::Message(
"String cannot round-trip through Ktav 0.1.0 — content \
has both a sole-`)` line and a sole-`))` line; \
neither multi-line form can hold both (§ 5.6.1)."
.into(),
));
}
if stripped_ok {
out.push_str("(\n");
let content_indent = indent + 1;
for line in s.split('\n') {
if !line.is_empty() {
push_indent(out, content_indent);
out.push_str(line);
}
out.push('\n');
}
push_indent(out, indent);
out.push_str(")\n");
} else {
out.push_str("((\n");
out.push_str(s);
out.push('\n');
push_indent(out, indent);
out.push_str("))\n");
}
} else if s.is_empty() {
out.push_str("::\n");
} else {
if needs_raw_marker(s) {
out.push_str(":: ");
}
out.push_str(s);
out.push('\n');
}
}
Value::Array(items) => {
if items.is_empty() {
out.push_str("[]\n");
} else {
out.push_str("[\n");
for item in items {
render_array_item(item, indent + 1, out)?;
}
push_indent(out, indent);
out.push_str("]\n");
}
}
Value::Object(obj) => {
if obj.is_empty() {
out.push_str("{}\n");
} else {
out.push_str("{\n");
render_object_body(obj, indent + 1, out)?;
push_indent(out, indent);
out.push_str("}\n");
}
}
}
Ok(())
}