1use std::borrow::Cow;
5
6pub fn quoted(s: &str) -> String {
8 let mut out = String::with_capacity(s.len() + 2);
9 asc_arsc::quote(s, &mut out);
10 out
11}
12
13pub fn value(s: &str) -> Cow<'_, str> {
17 let plain = !s.is_empty() && !s.chars().any(|c| c.is_whitespace() || c.is_control() || matches!(c, '"' | '\\' | '='));
18 if plain { Cow::Borrowed(s) } else { Cow::Owned(quoted(s)) }
19}
20
21#[cfg(test)]
22mod tests {
23 use super::*;
24
25 #[test]
26 fn quoted_strings_stay_on_one_line_and_parse_as_json() {
27 let raw = "a\"b\\c\nd\te\r\u{1b}\u{7f}\u{85}é😀";
28 let q = quoted(raw);
29 assert_eq!(q, r#""a\"b\\c\nd\te\r\u001b\u007f\u0085é😀""#);
30 assert_eq!(serde_json::from_str::<String>(&q).unwrap(), raw);
31 }
32
33 #[test]
34 fn values_are_quoted_only_when_ambiguous() {
35 assert_eq!(value("com.demo.Main"), "com.demo.Main");
36 assert_eq!(value("signature|privileged"), "signature|privileged");
37 assert_eq!(value("1.0 beta"), r#""1.0 beta""#);
38 assert_eq!(value("a=b"), r#""a=b""#);
39 assert_eq!(value(""), r#""""#);
40 }
41}