rustledger_core/format/
helpers.rs1use crate::MetaValue;
4
5pub fn format_meta_value(value: &MetaValue, config: &super::FormatConfig) -> String {
7 match value {
8 MetaValue::String(s) => format!("\"{}\"", escape_string(s)),
9 MetaValue::Account(a) => a.to_string(),
10 MetaValue::Currency(c) => c.to_string(),
11 MetaValue::Tag(t) => format!("#{t}"),
12 MetaValue::Link(l) => format!("^{l}"),
13 MetaValue::Date(d) => d.to_string(),
14 MetaValue::Number(n) => n.to_string(),
18 MetaValue::Amount(a) => super::format_amount_with(a, config),
19 MetaValue::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
20 MetaValue::None => String::new(),
21 MetaValue::Int(i) => i.to_string(),
22 }
23}
24
25#[must_use]
36pub fn escape_csv(s: &str) -> String {
37 if s.contains(',') || s.contains('"') || s.contains('\n') {
38 format!("\"{}\"", s.replace('"', "\"\""))
39 } else {
40 s.to_string()
41 }
42}
43
44#[must_use]
54pub fn escape_json(s: &str) -> String {
55 use std::fmt::Write;
56 let mut out = String::with_capacity(s.len());
57 for c in s.chars() {
58 match c {
59 '"' => out.push_str("\\\""),
60 '\\' => out.push_str("\\\\"),
61 '\n' => out.push_str("\\n"),
62 '\t' => out.push_str("\\t"),
63 '\r' => out.push_str("\\r"),
64 '\u{08}' => out.push_str("\\b"),
65 '\u{0c}' => out.push_str("\\f"),
66 c if (c as u32) < 0x20 => {
67 let _ = write!(out, "\\u{:04x}", c as u32);
68 }
69 c => out.push(c),
70 }
71 }
72 out
73}
74
75pub fn escape_string(s: &str) -> String {
77 let mut out = String::with_capacity(s.len());
78 for c in s.chars() {
79 match c {
80 '"' => out.push_str("\\\""),
81 '\\' => out.push_str("\\\\"),
82 '\n' => out.push_str("\\n"),
83 '\t' => out.push_str("\\t"),
87 '\r' => out.push_str("\\r"),
88 _ => out.push(c),
89 }
90 }
91 out
92}
93
94#[cfg(test)]
95mod tests {
96 use super::{escape_json, escape_string};
97
98 #[test]
99 fn escape_json_produces_valid_json_for_control_chars() {
100 assert_eq!(escape_json("a\"\\b"), "a\\\"\\\\b");
102 assert_eq!(escape_json("x\ny\tz\r"), "x\\ny\\tz\\r");
103 assert_eq!(escape_json("\u{08}\u{0c}"), "\\b\\f");
104 assert_eq!(escape_json("A\u{1b}B"), "A\\u001bB");
107 assert_eq!(escape_json("\u{00}"), "\\u0000");
108 assert_eq!(escape_json("投資 123"), "投資 123");
110 }
111
112 #[test]
113 fn escapes_quote_backslash_and_controls() {
114 assert_eq!(escape_string("a\"b"), "a\\\"b");
115 assert_eq!(escape_string("a\\b"), "a\\\\b");
116 assert_eq!(escape_string("a\nb"), "a\\nb");
117 assert_eq!(escape_string("a\tb"), "a\\tb");
120 assert_eq!(escape_string("a\rb"), "a\\rb");
121 }
122
123 #[test]
124 fn leaves_plain_text_untouched() {
125 assert_eq!(escape_string("plain text 123"), "plain text 123");
126 }
127}