Skip to content

Commit 174982c

Browse files
committed
refactor: template optimizations
- use simd_json instead of serde_json for performance - preallocate bigger write buffers
1 parent 2eac583 commit 174982c

File tree

1 file changed

+21
-17
lines changed

1 file changed

+21
-17
lines changed

src/cmd/template.rs

+21-17
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ use std::{
5454

5555
use minijinja::Environment;
5656
use serde::Deserialize;
57-
use serde_json::Value;
5857

5958
use crate::{
60-
config::{Config, Delimiter},
59+
config::{Config, Delimiter, DEFAULT_WTR_BUFFER_CAPACITY},
6160
util, CliError, CliResult,
6261
};
6362

@@ -143,14 +142,6 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
143142
.collect();
144143
csv::StringRecord::from(sanitized_headers)
145144
};
146-
let context_capacity = if args.flag_no_headers {
147-
rdr.headers()?.len()
148-
} else {
149-
headers.len()
150-
};
151-
152-
// Reuse context and pre-allocate
153-
let mut context = serde_json::Map::with_capacity(context_capacity);
154145

155146
// Set up output handling
156147
let output_to_dir = args.arg_outdir.is_some();
@@ -177,8 +168,14 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
177168
None
178169
} else {
179170
Some(match args.flag_output {
180-
Some(file) => Box::new(BufWriter::new(fs::File::create(file)?)) as Box<dyn Write>,
181-
None => Box::new(BufWriter::new(std::io::stdout())) as Box<dyn Write>,
171+
Some(file) => Box::new(BufWriter::with_capacity(
172+
DEFAULT_WTR_BUFFER_CAPACITY,
173+
fs::File::create(file)?,
174+
)) as Box<dyn Write>,
175+
None => Box::new(BufWriter::with_capacity(
176+
DEFAULT_WTR_BUFFER_CAPACITY,
177+
std::io::stdout(),
178+
)) as Box<dyn Write>,
182179
})
183180
};
184181

@@ -188,28 +185,34 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
188185
let mut rendered = String::new();
189186
#[allow(unused_assignments)]
190187
let mut outfilename = String::new();
188+
let mut context = simd_json::owned::Object::default();
191189

192190
// Process each record
193191
for record in rdr.records() {
194192
row_number += 1;
195193
curr_record.clone_from(&record?);
196-
context.clear();
197194

198195
if args.flag_no_headers {
199196
// Use numeric, column 1-based indices (e.g. _c1, _c2, etc.)
200197
for (i, field) in curr_record.iter().enumerate() {
201-
context.insert(format!("_c{}", i + 1), Value::String(field.to_string()));
198+
context.insert(
199+
format!("_c{}", i + 1),
200+
simd_json::OwnedValue::String(field.to_owned()),
201+
);
202202
}
203203
} else {
204204
// Use header names
205205
for (header, field) in headers.iter().zip(curr_record.iter()) {
206-
context.insert(header.to_string(), Value::String(field.to_string()));
206+
context.insert(
207+
header.to_string(),
208+
simd_json::OwnedValue::String(field.to_owned()),
209+
);
207210
}
208211
}
209212
// Always add row number to context
210213
context.insert(
211214
QSV_ROWNO.to_string(),
212-
Value::Number(serde_json::Number::from(row_number)),
215+
simd_json::OwnedValue::from(row_number),
213216
);
214217

215218
// Render template with record data
@@ -231,8 +234,9 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
231234
write!(writer, "{rendered}")?;
232235
writer.flush()?;
233236
} else if let Some(ref mut w) = wtr {
234-
write!(w, "{rendered}")?;
237+
w.write_all(rendered.as_bytes())?;
235238
}
239+
context.clear();
236240
}
237241

238242
if let Some(mut w) = wtr {

0 commit comments

Comments
 (0)