use crate::MetaValue;
pub fn format_meta_value(value: &MetaValue, config: &super::FormatConfig) -> String {
match value {
MetaValue::String(s) => format!("\"{}\"", escape_string(s)),
MetaValue::Account(a) => a.to_string(),
MetaValue::Currency(c) => c.to_string(),
MetaValue::Tag(t) => format!("#{t}"),
MetaValue::Link(l) => format!("^{l}"),
MetaValue::Date(d) => d.to_string(),
MetaValue::Number(n) => n.to_string(),
MetaValue::Amount(a) => super::format_amount_with(a, config),
MetaValue::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
MetaValue::None => String::new(),
MetaValue::Int(i) => i.to_string(),
}
}
#[must_use]
pub fn escape_csv(s: &str) -> String {
if s.contains(',') || s.contains('"') || s.contains('\n') {
format!("\"{}\"", s.replace('"', "\"\""))
} else {
s.to_string()
}
}
#[must_use]
pub fn escape_json(s: &str) -> String {
use std::fmt::Write;
let mut out = String::with_capacity(s.len());
for c in s.chars() {
match c {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\t' => out.push_str("\\t"),
'\r' => out.push_str("\\r"),
'\u{08}' => out.push_str("\\b"),
'\u{0c}' => out.push_str("\\f"),
c if (c as u32) < 0x20 => {
let _ = write!(out, "\\u{:04x}", c as u32);
}
c => out.push(c),
}
}
out
}
pub fn escape_string(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for c in s.chars() {
match c {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\t' => out.push_str("\\t"),
'\r' => out.push_str("\\r"),
_ => out.push(c),
}
}
out
}
#[cfg(test)]
mod tests {
use super::{escape_json, escape_string};
#[test]
fn escape_json_produces_valid_json_for_control_chars() {
assert_eq!(escape_json("a\"\\b"), "a\\\"\\\\b");
assert_eq!(escape_json("x\ny\tz\r"), "x\\ny\\tz\\r");
assert_eq!(escape_json("\u{08}\u{0c}"), "\\b\\f");
assert_eq!(escape_json("A\u{1b}B"), "A\\u001bB");
assert_eq!(escape_json("\u{00}"), "\\u0000");
assert_eq!(escape_json("投資 123"), "投資 123");
}
#[test]
fn escapes_quote_backslash_and_controls() {
assert_eq!(escape_string("a\"b"), "a\\\"b");
assert_eq!(escape_string("a\\b"), "a\\\\b");
assert_eq!(escape_string("a\nb"), "a\\nb");
assert_eq!(escape_string("a\tb"), "a\\tb");
assert_eq!(escape_string("a\rb"), "a\\rb");
}
#[test]
fn leaves_plain_text_untouched() {
assert_eq!(escape_string("plain text 123"), "plain text 123");
}
}