sim_codec/implementation/
strings.rs1use sim_kernel::{CodecId, Error, Result};
7
8pub fn encode_string_literal(value: &str) -> String {
25 let mut out = String::from("\"");
26 for ch in value.chars() {
27 match ch {
28 '\\' => out.push_str("\\\\"),
29 '"' => out.push_str("\\\""),
30 '\n' => out.push_str("\\n"),
31 '\r' => out.push_str("\\r"),
32 '\t' => out.push_str("\\t"),
33 ch if ch.is_control() => {
34 use std::fmt::Write;
35 write!(&mut out, "\\u{{{:x}}}", ch as u32).expect("string writes do not fail");
36 }
37 ch => out.push(ch),
38 }
39 }
40 out.push('"');
41 out
42}
43
44pub fn decode_string_literal(codec: CodecId, raw: &str) -> Result<String> {
50 let inner = raw
51 .strip_prefix('"')
52 .and_then(|rest| rest.strip_suffix('"'))
53 .ok_or_else(|| Error::CodecError {
54 codec,
55 message: format!("invalid string literal {raw}"),
56 })?;
57 let chars = inner.chars().collect::<Vec<_>>();
58 let mut index = 0;
59 let mut out = String::new();
60 while index < chars.len() {
61 let ch = chars[index];
62 if ch != '\\' {
63 out.push(ch);
64 index += 1;
65 continue;
66 }
67
68 index += 1;
69 let escaped = *chars.get(index).ok_or_else(|| Error::CodecError {
70 codec,
71 message: format!("unterminated string escape in {raw}"),
72 })?;
73 match escaped {
74 '\\' => out.push('\\'),
75 '"' => out.push('"'),
76 'n' => out.push('\n'),
77 'r' => out.push('\r'),
78 't' => out.push('\t'),
79 'u' => {
80 index += 1;
81 if chars.get(index) != Some(&'{') {
82 return Err(Error::CodecError {
83 codec,
84 message: format!("invalid unicode escape in {raw}"),
85 });
86 }
87 let mut hex = String::new();
88 index += 1;
89 while let Some(ch) = chars.get(index) {
90 if *ch == '}' {
91 break;
92 }
93 hex.push(*ch);
94 index += 1;
95 }
96 if chars.get(index) != Some(&'}') || hex.is_empty() {
97 return Err(Error::CodecError {
98 codec,
99 message: format!("invalid unicode escape in {raw}"),
100 });
101 }
102 let scalar = u32::from_str_radix(&hex, 16).map_err(|_| Error::CodecError {
103 codec,
104 message: format!("invalid unicode escape in {raw}"),
105 })?;
106 let decoded = char::from_u32(scalar).ok_or_else(|| Error::CodecError {
107 codec,
108 message: format!("invalid unicode scalar in {raw}"),
109 })?;
110 out.push(decoded);
111 }
112 other => {
113 return Err(Error::CodecError {
114 codec,
115 message: format!("unsupported string escape \\{other} in {raw}"),
116 });
117 }
118 }
119 index += 1;
120 }
121 Ok(out)
122}