difftreelog
doc: wrap examples in code fences
in: master
1 file changed
crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth1use crate::error::Error::*;2use crate::error::Result;3use crate::{throw, Val};45#[derive(PartialEq, Clone, Copy)]6pub enum ManifestType {7 // Applied in manifestification8 Manifest,9 /// Used for std.manifestJson10 /// Empty array/objects extends to "[\n\n]" instead of "[ ]" as in manifest11 Std,12 /// No line breaks, used in `obj+''`13 ToString,14 /// Minified json15 Minify,16}1718pub struct ManifestJsonOptions<'s> {19 pub padding: &'s str,20 pub mtype: ManifestType,21}2223pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {24 let mut out = String::new();25 manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?;26 Ok(out)27}28fn manifest_json_ex_buf(29 val: &Val,30 buf: &mut String,31 cur_padding: &mut String,32 options: &ManifestJsonOptions<'_>,33) -> Result<()> {34 use std::fmt::Write;35 let mtype = options.mtype;36 match val {37 Val::Bool(v) => {38 if *v {39 buf.push_str("true");40 } else {41 buf.push_str("false");42 }43 }44 Val::Null => buf.push_str("null"),45 Val::Str(s) => escape_string_json_buf(s, buf),46 Val::Num(n) => write!(buf, "{}", n).unwrap(),47 Val::Arr(items) => {48 buf.push('[');49 if !items.is_empty() {50 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {51 buf.push('\n');52 }5354 let old_len = cur_padding.len();55 cur_padding.push_str(options.padding);56 for (i, item) in items.iter().enumerate() {57 if i != 0 {58 buf.push(',');59 if mtype == ManifestType::ToString {60 buf.push(' ');61 } else if mtype != ManifestType::Minify {62 buf.push('\n');63 }64 }65 buf.push_str(cur_padding);66 manifest_json_ex_buf(&item?, buf, cur_padding, options)?;67 }68 cur_padding.truncate(old_len);6970 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {71 buf.push('\n');72 buf.push_str(cur_padding);73 }74 } else if mtype == ManifestType::Std {75 buf.push_str("\n\n");76 buf.push_str(cur_padding);77 } else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {78 buf.push(' ');79 }80 buf.push(']');81 }82 Val::Obj(obj) => {83 obj.run_assertions()?;84 buf.push('{');85 let fields = obj.fields();86 if !fields.is_empty() {87 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {88 buf.push('\n');89 }9091 let old_len = cur_padding.len();92 cur_padding.push_str(options.padding);93 for (i, field) in fields.into_iter().enumerate() {94 if i != 0 {95 buf.push(',');96 if mtype == ManifestType::ToString {97 buf.push(' ');98 } else if mtype != ManifestType::Minify {99 buf.push('\n');100 }101 }102 buf.push_str(cur_padding);103 escape_string_json_buf(&field, buf);104 buf.push_str(": ");105 crate::push(106 None,107 || format!("field <{}> manifestification", field.clone()),108 || {109 let value = obj.get(field.clone())?.unwrap();110 manifest_json_ex_buf(&value, buf, cur_padding, options)111 },112 )?;113 }114 cur_padding.truncate(old_len);115116 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {117 buf.push('\n');118 buf.push_str(cur_padding);119 }120 } else if mtype == ManifestType::Std {121 buf.push_str("\n\n");122 buf.push_str(cur_padding);123 } else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {124 buf.push(' ');125 }126 buf.push('}');127 }128 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),129 };130 Ok(())131}132133pub fn escape_string_json(s: &str) -> String {134 let mut buf = String::new();135 escape_string_json_buf(s, &mut buf);136 buf137}138139fn escape_string_json_buf(s: &str, buf: &mut String) {140 use std::fmt::Write;141 buf.push('"');142 for c in s.chars() {143 match c {144 '"' => buf.push_str("\\\""),145 '\\' => buf.push_str("\\\\"),146 '\u{0008}' => buf.push_str("\\b"),147 '\u{000c}' => buf.push_str("\\f"),148 '\n' => buf.push_str("\\n"),149 '\r' => buf.push_str("\\r"),150 '\t' => buf.push_str("\\t"),151 c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {152 write!(buf, "\\u{:04x}", c as u32).unwrap()153 }154 c => buf.push(c),155 }156 }157 buf.push('"');158}159160pub struct ManifestYamlOptions<'s> {161 /// Padding before fields, i.e162 /// a:163 /// b:164 /// ^^ this165 pub padding: &'s str,166 /// Padding before array elements in objects167 /// a:168 /// - 1169 /// ^^ this170 pub arr_element_padding: &'s str,171}172173pub fn manifest_yaml_ex(val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {174 let mut out = String::new();175 manifest_yaml_ex_buf(val, &mut out, &mut String::new(), options)?;176 Ok(out)177}178fn manifest_yaml_ex_buf(179 val: &Val,180 buf: &mut String,181 cur_padding: &mut String,182 options: &ManifestYamlOptions<'_>,183) -> Result<()> {184 use std::fmt::Write;185 match val {186 Val::Bool(v) => {187 if *v {188 buf.push_str("true")189 } else {190 buf.push_str("false")191 }192 }193 Val::Null => buf.push_str("null"),194 Val::Str(s) => {195 if s.is_empty() {196 buf.push_str("\"\"");197 } else if let Some(s) = s.strip_suffix('\n') {198 buf.push('|');199 for line in s.split('\n') {200 buf.push('\n');201 buf.push_str(options.padding);202 buf.push_str(line);203 }204 } else {205 escape_string_json_buf(s, buf)206 }207 }208 Val::Num(n) => write!(buf, "{}", *n).unwrap(),209 Val::Arr(a) => {210 if a.is_empty() {211 buf.push_str("[]");212 } else {213 for (i, item) in a.iter().enumerate() {214 if i != 0 {215 buf.push('\n');216 buf.push_str(cur_padding);217 }218 let item = item?;219 buf.push('-');220 match &item {221 Val::Arr(a) if !a.is_empty() => {222 buf.push('\n');223 buf.push_str(cur_padding);224 buf.push_str(options.padding);225 }226 _ => buf.push(' '),227 }228 let extra_padding = match &item {229 Val::Arr(a) => !a.is_empty(),230 Val::Obj(o) => !o.is_empty(),231 _ => false,232 };233 let prev_len = cur_padding.len();234 if extra_padding {235 cur_padding.push_str(options.padding);236 }237 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;238 cur_padding.truncate(prev_len);239 }240 }241 }242 Val::Obj(o) => {243 if o.is_empty() {244 buf.push_str("{}");245 } else {246 for (i, key) in o.fields().iter().enumerate() {247 if i != 0 {248 buf.push('\n');249 buf.push_str(cur_padding);250 }251 escape_string_json_buf(key, buf);252 buf.push(':');253 let prev_len = cur_padding.len();254 let item = o.get(key.clone())?.expect("field exists");255 match &item {256 Val::Arr(a) if !a.is_empty() => {257 buf.push('\n');258 buf.push_str(cur_padding);259 buf.push_str(options.arr_element_padding);260 cur_padding.push_str(options.arr_element_padding);261 }262 Val::Obj(o) if !o.is_empty() => {263 buf.push('\n');264 buf.push_str(cur_padding);265 buf.push_str(options.padding);266 cur_padding.push_str(options.padding);267 }268 _ => buf.push(' '),269 }270 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;271 cur_padding.truncate(prev_len);272 }273 }274 }275 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),276 }277 Ok(())278}1use crate::error::Error::*;2use crate::error::Result;3use crate::{throw, Val};45#[derive(PartialEq, Clone, Copy)]6pub enum ManifestType {7 // Applied in manifestification8 Manifest,9 /// Used for std.manifestJson10 /// Empty array/objects extends to "[\n\n]" instead of "[ ]" as in manifest11 Std,12 /// No line breaks, used in `obj+''`13 ToString,14 /// Minified json15 Minify,16}1718pub struct ManifestJsonOptions<'s> {19 pub padding: &'s str,20 pub mtype: ManifestType,21}2223pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {24 let mut out = String::new();25 manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?;26 Ok(out)27}28fn manifest_json_ex_buf(29 val: &Val,30 buf: &mut String,31 cur_padding: &mut String,32 options: &ManifestJsonOptions<'_>,33) -> Result<()> {34 use std::fmt::Write;35 let mtype = options.mtype;36 match val {37 Val::Bool(v) => {38 if *v {39 buf.push_str("true");40 } else {41 buf.push_str("false");42 }43 }44 Val::Null => buf.push_str("null"),45 Val::Str(s) => escape_string_json_buf(s, buf),46 Val::Num(n) => write!(buf, "{}", n).unwrap(),47 Val::Arr(items) => {48 buf.push('[');49 if !items.is_empty() {50 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {51 buf.push('\n');52 }5354 let old_len = cur_padding.len();55 cur_padding.push_str(options.padding);56 for (i, item) in items.iter().enumerate() {57 if i != 0 {58 buf.push(',');59 if mtype == ManifestType::ToString {60 buf.push(' ');61 } else if mtype != ManifestType::Minify {62 buf.push('\n');63 }64 }65 buf.push_str(cur_padding);66 manifest_json_ex_buf(&item?, buf, cur_padding, options)?;67 }68 cur_padding.truncate(old_len);6970 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {71 buf.push('\n');72 buf.push_str(cur_padding);73 }74 } else if mtype == ManifestType::Std {75 buf.push_str("\n\n");76 buf.push_str(cur_padding);77 } else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {78 buf.push(' ');79 }80 buf.push(']');81 }82 Val::Obj(obj) => {83 obj.run_assertions()?;84 buf.push('{');85 let fields = obj.fields();86 if !fields.is_empty() {87 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {88 buf.push('\n');89 }9091 let old_len = cur_padding.len();92 cur_padding.push_str(options.padding);93 for (i, field) in fields.into_iter().enumerate() {94 if i != 0 {95 buf.push(',');96 if mtype == ManifestType::ToString {97 buf.push(' ');98 } else if mtype != ManifestType::Minify {99 buf.push('\n');100 }101 }102 buf.push_str(cur_padding);103 escape_string_json_buf(&field, buf);104 buf.push_str(": ");105 crate::push(106 None,107 || format!("field <{}> manifestification", field.clone()),108 || {109 let value = obj.get(field.clone())?.unwrap();110 manifest_json_ex_buf(&value, buf, cur_padding, options)111 },112 )?;113 }114 cur_padding.truncate(old_len);115116 if mtype != ManifestType::ToString && mtype != ManifestType::Minify {117 buf.push('\n');118 buf.push_str(cur_padding);119 }120 } else if mtype == ManifestType::Std {121 buf.push_str("\n\n");122 buf.push_str(cur_padding);123 } else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {124 buf.push(' ');125 }126 buf.push('}');127 }128 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),129 };130 Ok(())131}132133pub fn escape_string_json(s: &str) -> String {134 let mut buf = String::new();135 escape_string_json_buf(s, &mut buf);136 buf137}138139fn escape_string_json_buf(s: &str, buf: &mut String) {140 use std::fmt::Write;141 buf.push('"');142 for c in s.chars() {143 match c {144 '"' => buf.push_str("\\\""),145 '\\' => buf.push_str("\\\\"),146 '\u{0008}' => buf.push_str("\\b"),147 '\u{000c}' => buf.push_str("\\f"),148 '\n' => buf.push_str("\\n"),149 '\r' => buf.push_str("\\r"),150 '\t' => buf.push_str("\\t"),151 c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {152 write!(buf, "\\u{:04x}", c as u32).unwrap()153 }154 c => buf.push(c),155 }156 }157 buf.push('"');158}159160pub struct ManifestYamlOptions<'s> {161 /// Padding before fields, i.e162 /// ```yaml163 /// a:164 /// b:165 /// ## <- this166 /// ```167 pub padding: &'s str,168 /// Padding before array elements in objects169 /// ```yaml170 /// a:171 /// - 1172 /// ## <- this173 /// ```174 pub arr_element_padding: &'s str,175}176177pub fn manifest_yaml_ex(val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {178 let mut out = String::new();179 manifest_yaml_ex_buf(val, &mut out, &mut String::new(), options)?;180 Ok(out)181}182fn manifest_yaml_ex_buf(183 val: &Val,184 buf: &mut String,185 cur_padding: &mut String,186 options: &ManifestYamlOptions<'_>,187) -> Result<()> {188 use std::fmt::Write;189 match val {190 Val::Bool(v) => {191 if *v {192 buf.push_str("true")193 } else {194 buf.push_str("false")195 }196 }197 Val::Null => buf.push_str("null"),198 Val::Str(s) => {199 if s.is_empty() {200 buf.push_str("\"\"");201 } else if let Some(s) = s.strip_suffix('\n') {202 buf.push('|');203 for line in s.split('\n') {204 buf.push('\n');205 buf.push_str(options.padding);206 buf.push_str(line);207 }208 } else {209 escape_string_json_buf(s, buf)210 }211 }212 Val::Num(n) => write!(buf, "{}", *n).unwrap(),213 Val::Arr(a) => {214 if a.is_empty() {215 buf.push_str("[]");216 } else {217 for (i, item) in a.iter().enumerate() {218 if i != 0 {219 buf.push('\n');220 buf.push_str(cur_padding);221 }222 let item = item?;223 buf.push('-');224 match &item {225 Val::Arr(a) if !a.is_empty() => {226 buf.push('\n');227 buf.push_str(cur_padding);228 buf.push_str(options.padding);229 }230 _ => buf.push(' '),231 }232 let extra_padding = match &item {233 Val::Arr(a) => !a.is_empty(),234 Val::Obj(o) => !o.is_empty(),235 _ => false,236 };237 let prev_len = cur_padding.len();238 if extra_padding {239 cur_padding.push_str(options.padding);240 }241 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;242 cur_padding.truncate(prev_len);243 }244 }245 }246 Val::Obj(o) => {247 if o.is_empty() {248 buf.push_str("{}");249 } else {250 for (i, key) in o.fields().iter().enumerate() {251 if i != 0 {252 buf.push('\n');253 buf.push_str(cur_padding);254 }255 escape_string_json_buf(key, buf);256 buf.push(':');257 let prev_len = cur_padding.len();258 let item = o.get(key.clone())?.expect("field exists");259 match &item {260 Val::Arr(a) if !a.is_empty() => {261 buf.push('\n');262 buf.push_str(cur_padding);263 buf.push_str(options.arr_element_padding);264 cur_padding.push_str(options.arr_element_padding);265 }266 Val::Obj(o) if !o.is_empty() => {267 buf.push('\n');268 buf.push_str(cur_padding);269 buf.push_str(options.padding);270 cur_padding.push_str(options.padding);271 }272 _ => buf.push(' '),273 }274 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;275 cur_padding.truncate(prev_len);276 }277 }278 }279 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),280 }281 Ok(())282}