Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions benches/display_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use expression_engine::Value;

fn bench_display_value(c: &mut Criterion) {
let mut list = Vec::new();
for i in 0..10 {
list.push(Value::from(i));
}

let mut map = Vec::new();
for i in 0..10 {
map.push((Value::from(format!("key{}", i)), Value::from(i)));
}

let val = Value::List(vec![
Value::from("hello"),
Value::from(42),
Value::from(true),
Value::List(list),
Value::Map(map),
]);

c.bench_function("display_value", |b| {
b.iter(|| format!("{}", black_box(&val)))
});
}

criterion_group!(benches, bench_display_value);
criterion_main!(benches);
Comment on lines +28 to +29
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Criterion benchmark target likely won't compile/run under cargo bench unless it is registered in Cargo.toml with harness = false. Without an explicit [[bench]] entry, Cargo uses the default benchmark harness, which conflicts with criterion_main! generating its own main (typically causing a duplicate/unknown main harness error). Add a [[bench]] name = "display_value" entry with harness = false so the new benchmark works consistently.

Copilot uses AI. Check for mistakes.
24 changes: 12 additions & 12 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,29 @@ pub enum Value {
None,
}

// Optimization: Write directly to `std::fmt::Formatter` instead of creating intermediate
// strings and calling `format!()` in a loop.
// Impact: Reduces heap allocations, avoiding O(N) allocations for Lists and Maps.
#[cfg(not(tarpaulin_include))]
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::String(val) => write!(f, "value string: {}", val.clone()),
Self::Number(val) => write!(f, "value number: {}", val.clone()),
Self::Bool(val) => write!(f, "value bool: {}", val.clone()),
Self::String(val) => write!(f, "value string: {}", val),
Self::Number(val) => write!(f, "value number: {}", val),
Self::Bool(val) => write!(f, "value bool: {}", val),
Self::List(values) => {
let mut s = String::from("[");
write!(f, "value list: [")?;
for value in values {
s.push_str(format!("{},", value.clone()).as_str());
write!(f, "{},", value)?;
}
Comment on lines 28 to 30
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation adds a trailing comma for every element in the list, resulting in output like [1,2,3,]. While this preserves the previous behavior, it is generally considered better practice to omit the trailing separator for the last element to improve readability.

Suggested change
for value in values {
s.push_str(format!("{},", value.clone()).as_str());
write!(f, "{},", value)?;
}
for (i, value) in values.iter().enumerate() {
if i > 0 {
write!(f, ",")?;
}
write!(f, "{}", value)?;
}

s.push_str("]");
write!(f, "value list: {}", s)
write!(f, "]")
}
Self::Map(m) => {
let mut s = String::from("{");
write!(f, "value map: {{")?;
for (k, v) in m {
s.push_str(format!("key: {},", k.clone()).as_str());
s.push_str(format!("value: {}; ", v.clone()).as_str());
write!(f, "key: {},value: {}; ", k, v)?;
}
Comment on lines 35 to 37
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation adds a trailing semicolon and space for every entry in the map, resulting in output like {key: k,value: v; key: k2,value: v2; }. It is generally preferred to omit the trailing separator for the last entry to improve the clarity of the output.

                for (i, (k, v)) in m.iter().enumerate() {
                    if i > 0 {
                        write!(f, "; ")?;
                    }
                    write!(f, "key: {},value: {}", k, v)?;
                }

s.push_str("}");
write!(f, "value map: {}", s)
write!(f, "}}")
}
Self::None => write!(f, "None"),
}
Expand Down
Loading