1use std::collections::BTreeMap;23use jrsonnet_evaluator::{4 IStr, ObjValue, Result, ResultExt, Val,5 manifest::{ManifestFormat, ToStringFormat},6 typed::{FromUntyped, Typed},7};89pub struct IniFormat {10 #[cfg(feature = "exp-preserve-order")]11 preserve_order: bool,12 final_newline: bool,13}1415impl IniFormat {16 pub fn std(#[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> Self {17 Self {18 #[cfg(feature = "exp-preserve-order")]19 preserve_order,20 final_newline: true,21 }22 }23 pub fn cli(#[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> Self {24 Self {25 #[cfg(feature = "exp-preserve-order")]26 preserve_order,27 final_newline: false,28 }29 }30}3132impl ManifestFormat for IniFormat {33 fn manifest_buf(&self, val: Val, buf: &mut String) -> Result<()> {34 manifest_ini_obj(35 self,36 IniObj::from_untyped(val).description("ini object structure")?,37 buf,38 )39 }40}4142fn manifest_ini_body(43 #[cfg(feature = "exp-preserve-order")] format: &IniFormat,44 body: ObjValue,45 out: &mut String,46) -> Result<()> {47 for (i, (key, value)) in body48 .iter(49 #[cfg(feature = "exp-preserve-order")]50 format.preserve_order,51 )52 .enumerate()53 {54 if i != 0 || !out.is_empty() {55 out.push('\n');56 }57 let value = value.with_description(|| format!("field <{key}> evaluation"))?;58 let manifest_desc = || format!("field <{key}> manifestification");59 if let Some(arr) = value.as_arr() {60 for (i, ele) in arr.iter().enumerate() {61 if i != 0 {62 out.push('\n');63 }64 let ele = ele65 .with_description(|| format!("elem <{i}> evaluation"))66 .with_description(manifest_desc)?;67 out.push_str(&key);68 out.push_str(" = ");69 ToStringFormat70 .manifest_buf(ele, out)71 .with_description(manifest_desc)?;72 }73 } else {74 out.push_str(&key);75 out.push_str(" = ");76 ToStringFormat77 .manifest_buf(value, out)78 .with_description(manifest_desc)?;79 }80 }81 Ok(())82}8384#[derive(Typed, FromUntyped)]85struct IniObj {86 main: Option<ObjValue>,87 88 sections: BTreeMap<IStr, ObjValue>,89}9091fn manifest_ini_obj(format: &IniFormat, obj: IniObj, out: &mut String) -> Result<()> {92 if let Some(main) = obj.main {93 manifest_ini_body(94 #[cfg(feature = "exp-preserve-order")]95 format,96 main,97 out,98 )99 .description("<main> manifestification")?;100 }101 for (i, (section, val)) in obj.sections.into_iter().enumerate() {102 if i != 0 || !out.is_empty() {103 out.push('\n');104 }105 out.push('[');106 out.push_str(§ion);107 out.push(']');108 manifest_ini_body(109 #[cfg(feature = "exp-preserve-order")]110 format,111 val,112 out,113 )114 .with_description(|| format!("<{section}> section manifestification"))?;115 }116 if format.final_newline {117 out.push('\n');118 }119 Ok(())120}