1use crate::Value;23pub fn write_identifier(k: &str, out: &mut String) {4 if k.contains(['.', '\'', '\"', '\\', '\n', '\t', '\r', '$']) {5 write_nix_str_singleline(k, out);6 } else {7 out.push_str(k);8 }9}1011fn write_nix_obj_key_buf(k: &str, v: &Value, out: &mut String, padding: &mut usize) {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, padding);19 }20 v => {21 out.push_str(" = ");22 write_nix_buf(v, out, padding);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}3940fn write_padding(out: &mut String, padding: &usize) {41 for _ in 0..*padding {42 out.push_str(" ");43 }44}4546pub fn write_nix_str_singleline(str: &str, out: &mut String) {47 out.push_str(&escape_string(str))48}49pub fn write_nix_str(str: &str, out: &mut String, padding: &mut usize) {50 if str.ends_with('\n') {51 out.push_str("''");52 *padding += 1;53 for ele in str[0..str.len() - 1].split('\n') {54 out.push('\n');55 write_padding(out, padding);56 out.push_str(57 &ele58 59 .replace("''", "'''")60 61 .replace("${", "''${")62 63 64 65 66 .replace('\t', "''\\t"),67 );68 }69 out.push('\n');70 *padding -= 1;71 write_padding(out, padding);72 73 out.push_str("''");74 } else {75 write_nix_str_singleline(str, out);76 }77}7879fn write_nix_buf(value: &Value, out: &mut String, padding: &mut usize) {80 match value {81 Value::Null => out.push_str("null"),82 Value::Boolean(v) => out.push_str(if *v { "true" } else { "false" }),83 Value::Number(n) => out.push_str(&format!("{n}")),84 Value::String(s) => write_nix_str(s, out, padding),85 Value::Array(a) => {86 if a.is_empty() {87 out.push_str("[ ]");88 } else {89 out.push_str("[\n");90 *padding += 1;91 for item in a {92 write_padding(out, padding);93 write_nix_buf(item, out, padding);94 out.push('\n');95 }96 *padding -= 1;97 write_padding(out, padding);98 out.push(']');99 }100 }101 Value::Object(obj) => {102 if obj.is_empty() {103 out.push_str("{ }")104 } else {105 out.push_str("{\n");106 *padding += 1;107 for (k, v) in obj {108 write_padding(out, padding);109 write_nix_obj_key_buf(k, v, out, padding);110 out.push('\n');111 }112 *padding -= 1;113 write_padding(out, padding);114 out.push('}');115 }116 }117 };118}119120pub fn write_nix(value: &Value) -> String {121 let mut out = String::new();122 write_nix_buf(value, &mut out, &mut 0);123 out124}