(s: &str, out: &mut String, ensure_ascii: bool)
| 185 | } |
| 186 | |
| 187 | fn escape_string(s: &str, out: &mut String, ensure_ascii: bool) { |
| 188 | out.push('"'); |
| 189 | for c in s.chars() { |
| 190 | match c { |
| 191 | '"' => out.push_str("\\\""), |
| 192 | '\\' => out.push_str("\\\\"), |
| 193 | '\n' => out.push_str("\\n"), |
| 194 | '\r' => out.push_str("\\r"), |
| 195 | '\t' => out.push_str("\\t"), |
| 196 | '\u{08}' => out.push_str("\\b"), |
| 197 | '\u{0C}' => out.push_str("\\f"), |
| 198 | c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)), |
| 199 | c if ensure_ascii && (c as u32) >= 0x80 => { |
| 200 | let cp = c as u32; |
| 201 | if cp <= 0xFFFF { |
| 202 | out.push_str(&format!("\\u{:04x}", cp)); |
| 203 | } else { |
| 204 | // UTF-16 surrogate pair for code points beyond the BMP. |
| 205 | let v = cp - 0x10000; |
| 206 | let hi = 0xD800 + (v >> 10); |
| 207 | let lo = 0xDC00 + (v & 0x3FF); |
| 208 | out.push_str(&format!("\\u{:04x}\\u{:04x}", hi, lo)); |
| 209 | } |
| 210 | } |
| 211 | c => out.push(c), |
| 212 | } |
| 213 | } |
| 214 | out.push('"'); |
| 215 | } |
| 216 | |
| 217 | fn format_float(f: f64) -> String { |
| 218 | // Integer-valued floats keep a trailing ".0" to disambiguate from int (Python's `json.dumps(1.0)` -> `"1.0"`). |
no test coverage detected