//! JSON minification by whitespace removal only. The input must parse as strict JSON first; //! then every byte outside insignificant whitespace is kept, so duplicate keys, number spelling //! and string escapes reach the game exactly as written. /// The minified bytes, or `None` when `bytes` is not strict JSON (comments, a BOM, trailing /// commas): such files ship as they are. pub fn minify(bytes: &[u8]) -> Option> { serde_json::from_slice::(bytes).ok()?; let mut out = Vec::with_capacity(bytes.len()); let mut in_string = false; let mut escaped = false; for &b in bytes { if in_string { out.push(b); if escaped { escaped = false; } else if b == b'\\' { escaped = true; } else if b == b'"' { in_string = false; } } else if b == b'"' { in_string = true; out.push(b); } else if !matches!(b, b' ' | b'\t' | b'\n' | b'\r') { out.push(b); } } Some(out) } #[cfg(test)] mod tests { use super::*; #[test] fn strips_only_insignificant_whitespace() { let input = br#"{ "a b" : [ 1.50 , 2e3 ], "esc\" x" : "\\ y", "a b": null }"#; assert_eq!(minify(input).unwrap(), br#"{"a b":[1.50,2e3],"esc\" x":"\\ y","a b":null}"#); } #[test] fn lenient_json_ships_unchanged() { assert_eq!(minify(b"{ // c\n }"), None); assert_eq!(minify(b"\xef\xbb\xbf{}"), None); assert_eq!(minify(b"[1,]"), None); } }