use specta::{
Types,
datatype::{Fields, Struct, UnnamedFields},
};
use crate::{
Error, Exporter,
module::ModuleImports,
types::{
NDT,
fields::{self, datatype_with_inline_attr},
primitive::{INDENT, NULL},
},
};
pub fn render<E: Exporter>(
s: &mut String,
imports: &mut ModuleImports,
exporter: &E,
types: &Types,
ndt: &NDT,
st: &Struct,
parent_name: Option<&str>,
) -> Result<(), Error> {
match &st.fields {
Fields::Unit => s.push_str(NULL),
Fields::Unnamed(unnamed) => unnamed_fields_datatype(
s,
imports,
exporter,
types,
ndt,
&unnamed,
parent_name,
false,
)?,
Fields::Named(named) => {
let fields = named
.fields
.iter()
.filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty))))
.collect::<Vec<_>>();
if fields.is_empty() {
return Ok(());
}
let mut unflattened_fields: Vec<String> = Vec::with_capacity(fields.len());
for (key, (field, ty)) in fields {
let mut other = String::new();
let mut field_location = Vec::from(&[ndt.rust_type_path()]);
field_location.push(key.clone());
fields::render(
&mut other,
imports,
exporter,
types,
ndt,
key.clone(),
(field, ty),
parent_name,
false,
None,
)?;
unflattened_fields.push(other);
}
let mut unflattened_fields = unflattened_fields.iter().peekable();
if let Some(first) = unflattened_fields.next() {
let first_field = format!("\n{INDENT}{{ {first}");
s.push_str(&first_field);
} else {
panic!("no fields on struct")
}
while unflattened_fields.peek().is_some() {
let field = unflattened_fields.next().unwrap();
let field = format!("\n{INDENT}, {field}");
s.push_str(&field);
}
s.push(' ');
s.push('}');
}
}
Ok(())
}
fn unnamed_fields_datatype<E: Exporter>(
s: &mut String,
imports: &mut ModuleImports,
exporter: &E,
types: &Types,
ndt: &NDT,
fields: &UnnamedFields,
parent_name: Option<&str>,
force_inline: bool,
) -> Result<(), Error> {
let lonely_tuple_is_really_just_an_alias = fields.fields.len() == 1;
let fields = fields.fields.clone();
let mut field_dts = fields.into_iter().filter_map(|f| f.ty).peekable();
if !lonely_tuple_is_really_just_an_alias {
s.push_str(&format!("\n{INDENT}( "));
}
while let Some(dt) = field_dts.next() {
datatype_with_inline_attr(
s,
imports,
exporter,
types,
&dt,
ndt,
parent_name,
force_inline,
)?;
if field_dts.peek().is_some() {
s.push_str(", ");
}
}
if !lonely_tuple_is_really_just_an_alias {
s.push_str(" )");
}
Ok(())
}