1use crate::Value;23pub fn write_identifier(k: &str, out: &mut String) {4 if k.contains(['.', '\'', '\"', '\\', '\n', '\t', '\r', '$']) {5 write_nix_str(k, out);6 } else {7 out.push_str(k);8 }9}1011fn write_nix_obj_key_buf(k: &str, v: &Value, out: &mut String) {12 write_identifier(k, out);13 match v {14 Value::Object(o) if o.len() == 1 => {15 let (k, v) = o.iter().next().unwrap();1617 out.push('.');18 write_nix_obj_key_buf(k, v, out);19 }20 v => {21 out.push_str(" = ");22 write_nix_buf(v, out);23 out.push(';');24 }25 }26}2728pub fn escape_string(str: &str) -> String {29 format!(30 "\"{}\"",31 str.replace('\\', "\\\\")32 .replace('"', "\\\"")33 .replace('\n', "\\n")34 .replace('\t', "\\t")35 .replace('\r', "\\r")36 .replace('$', "\\$")37 )38}3940pub fn write_nix_str(str: &str, out: &mut String) {41 if str.ends_with('\n') {42 out.push_str("''");43 for ele in str.split('\n') {44 out.push('\n');45 out.push_str(46 &ele47 48 .replace("''", "'''")49 50 .replace("${", "''${")51 52 53 54 55 .replace('\t', "''\\t"),56 );57 }58 59 out.push_str("''");60 } else {61 out.push_str(&escape_string(str))62 }63}6465fn write_nix_buf(value: &Value, out: &mut String) {66 match value {67 Value::Null => out.push_str("null"),68 Value::Boolean(v) => out.push_str(if *v { "true" } else { "false" }),69 Value::Number(n) => out.push_str(&format!("{}", n)),70 Value::String(s) => write_nix_str(s, out),71 Value::Array(a) => {72 if a.is_empty() {73 out.push_str("[ ]");74 } else {75 out.push('[');76 for item in a {77 write_nix_buf(item, out);78 out.push('\n');79 }80 out.push(']');81 }82 }83 Value::Object(obj) => {84 if obj.is_empty() {85 out.push_str("{ }")86 } else {87 out.push('{');88 for (k, v) in obj {89 write_nix_obj_key_buf(k, v, out);90 out.push('\n');91 }92 out.push('}');93 }94 }95 };96}9798pub fn write_nix(value: &Value) -> String {99 let mut out = String::new();100 write_nix_buf(value, &mut out);101 out102}