fend_core/
json.rs

1/// The method is not meant to be used by other crates! It may change
2/// or be removed in the future, with no regard for backwards compatibility.
3#[allow(clippy::missing_panics_doc)]
4pub fn escape_string(input: &str, out: &mut String) {
5	for ch in input.chars() {
6		match ch {
7			'\\' => out.push_str("\\\\"),
8			'"' => out.push_str("\\\""),
9			'\n' => out.push_str("\\n"),
10			'\r' => out.push_str("\\r"),
11			'\t' => out.push_str("\\t"),
12			'\x20'..='\x7e' => out.push(ch),
13			_ => {
14				let mut buf = [0; 2];
15				for &mut code_unit in ch.encode_utf16(&mut buf) {
16					out.push_str("\\u");
17					out.push(char::from_digit(u32::from(code_unit) / 0x1000, 16).unwrap());
18					out.push(char::from_digit(u32::from(code_unit) % 0x1000 / 0x100, 16).unwrap());
19					out.push(char::from_digit(u32::from(code_unit) % 0x100 / 0x10, 16).unwrap());
20					out.push(char::from_digit(u32::from(code_unit) % 0x10, 16).unwrap());
21				}
22			}
23		}
24	}
25}
26
27#[cfg(test)]
28mod tests {
29	use super::*;
30
31	#[track_caller]
32	fn test_json_str(input: &str, expected: &str) {
33		let mut out = String::new();
34		escape_string(input, &mut out);
35		assert_eq!(out, expected);
36	}
37
38	#[test]
39	fn json_string_encoding() {
40		test_json_str("abc", "abc");
41		test_json_str("fancy string\n", "fancy string\\n");
42		test_json_str("\n\t\r\0\\\'\"", "\\n\\t\\r\\u0000\\\\'\\\"");
43		test_json_str("\u{1d54a}", "\\ud835\\udd4a");
44	}
45}