use crate::e2e::escape::go_string_literal;
use super::super::json_values::json_to_go;
use super::{GoFieldSite, GoValueContext, go_named_field_expression, qualified_go_type};
pub(super) fn go_slice_expression(
element: &crate::core::ir::TypeRef,
value: &serde_json::Value,
context: GoValueContext<'_>,
site: GoFieldSite<'_>,
) -> anyhow::Result<Option<String>> {
let Some(items) = value.as_array() else {
return Ok(None);
};
let element_type = match element {
crate::core::ir::TypeRef::String | crate::core::ir::TypeRef::Path => "string".to_string(),
crate::core::ir::TypeRef::Primitive(_) => {
crate::backends::go::type_map::go_struct_field_type(element).into_owned()
}
crate::core::ir::TypeRef::Named(name) => qualified_go_type(context.import_alias, name),
_ => return Ok(None),
};
let mut rendered = Vec::with_capacity(items.len());
for (index, item) in items.iter().enumerate() {
let item_pointer = format!("{}/{index}", site.pointer);
let item_site = GoFieldSite {
pointer: &item_pointer,
..site
};
let expression = match element {
crate::core::ir::TypeRef::Named(name) => go_named_field_expression(item, name, context, item_site, false)?,
crate::core::ir::TypeRef::Primitive(_) if item.is_number() || item.is_boolean() => json_to_go(item),
crate::core::ir::TypeRef::String | crate::core::ir::TypeRef::Path => match item.as_str() {
Some(text) => go_string_literal(text),
None => return Ok(None),
},
_ => return Ok(None),
};
rendered.push(expression);
}
if rendered.iter().all(|expression| !expression.contains('\n')) {
return Ok(Some(format!("[]{element_type}{{{}}}", rendered.join(", "))));
}
let elements = rendered
.iter()
.map(|expression| format!("\t{},", expression.replace('\n', "\n\t")))
.collect::<Vec<_>>()
.join("\n");
Ok(Some(format!("[]{element_type}{{\n{elements}\n}}")))
}
pub(super) fn field_paddings(field_values: &[(String, String)]) -> Vec<usize> {
let mut paddings = vec![0usize; field_values.len()];
let mut run_start = 0;
while run_start < field_values.len() {
if field_values[run_start].1.contains('\n') {
run_start += 1;
continue;
}
let run_end = field_values[run_start..]
.iter()
.position(|(_, expression)| expression.contains('\n'))
.map_or(field_values.len(), |offset| run_start + offset);
let widest = field_values[run_start..run_end]
.iter()
.map(|(name, _)| name.len())
.max()
.unwrap_or_default();
for (padding, (name, _)) in paddings[run_start..run_end]
.iter_mut()
.zip(&field_values[run_start..run_end])
{
*padding = widest - name.len();
}
run_start = run_end;
}
paddings
}