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