Skip to content

Commit 5b8d3e3

Browse files
committed
Avoid quadratic string concatenations for gron
1 parent edb9d2b commit 5b8d3e3

1 file changed

Lines changed: 15 additions & 10 deletions

File tree

src/gron.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ use std::fmt::Write;
2828
/// Convert a JSON value to gron format
2929
pub fn json_to_gron(value: &JsonValue) -> String {
3030
let mut output = String::new();
31-
gron_recursive(value, "json", &mut output);
31+
let mut path = String::from("json");
32+
gron_recursive(value, &mut path, &mut output);
3233
output
3334
}
3435

35-
fn gron_recursive(value: &JsonValue, path: &str, output: &mut String) {
36+
fn gron_recursive(value: &JsonValue, path: &mut String, output: &mut String) {
3637
match value {
3738
JsonValue::Null => {
3839
writeln!(output, "{} = null;", path).unwrap();
@@ -49,15 +50,19 @@ fn gron_recursive(value: &JsonValue, path: &str, output: &mut String) {
4950
JsonValue::Array(arr) => {
5051
writeln!(output, "{} = [];", path).unwrap();
5152
for (i, item) in arr.iter().enumerate() {
52-
let new_path = format!("{}[{}]", path, i);
53-
gron_recursive(item, &new_path, output);
53+
let prefix_len = path.len();
54+
write!(path, "[{}]", i).unwrap();
55+
gron_recursive(item, path, output);
56+
path.truncate(prefix_len);
5457
}
5558
}
5659
JsonValue::Object(obj) => {
5760
writeln!(output, "{} = {{}};", path).unwrap();
5861
for (key, val) in obj.iter() {
59-
let new_path = format_path_segment(path, key);
60-
gron_recursive(val, &new_path, output);
62+
let prefix_len = path.len();
63+
append_path_segment(path, key);
64+
gron_recursive(val, path, output);
65+
path.truncate(prefix_len);
6166
}
6267
}
6368
}
@@ -88,13 +93,13 @@ fn is_valid_identifier(s: &str) -> bool {
8893
false
8994
}
9095

91-
/// Format a path segment, using dot notation for valid identifiers,
96+
/// Append a path segment to the existing path buffer, using dot notation for valid identifiers,
9297
/// bracket notation with quotes for everything else
93-
fn format_path_segment(current_path: &str, key: &str) -> String {
98+
fn append_path_segment(path: &mut String, key: &str) {
9499
if is_valid_identifier(key) {
95-
format!("{}.{}", current_path, key)
100+
write!(path, ".{}", key).unwrap();
96101
} else {
97-
format!("{}[{}]", current_path, escape_string(key))
102+
write!(path, "[{}]", escape_string(key)).unwrap();
98103
}
99104
}
100105

0 commit comments

Comments
 (0)