Skip to content

Commit 7fd1e62

Browse files
committed
perf(value): Reduce allocations with Cow
Change `value::Object`'s key to a `Cow` to avoid allocations when a `&'static str` is used. BREAKING CHANGE: When inserting items into a `value::Object`, the value needs to be turned into a `Cow<str>`, usually with `.into()`. This carries forward to inserting values into a `Context`.
1 parent f52f89e commit 7fd1e62

File tree

13 files changed

+43
-36
lines changed

13 files changed

+43
-36
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ let template = liquid::ParserBuilder::with_liquid()
2929
.parse("Liquid! {{num | minus: 2}}").unwrap();
3030

3131
let mut globals = liquid::Object::new();
32-
globals.insert("num".to_owned(), liquid::Value::scalar(4f64));
32+
globals.insert("num".into(), liquid::Value::scalar(4f64));
3333

3434
let output = template.render(&globals).unwrap();
3535
assert_eq!(output, "Liquid! 2".to_string());

src/interpreter/context.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::HashMap;
22

33
use error::{Error, Result};
44
use value::{Index, Object, Value};
5+
use std::borrow;
56

67
use super::Argument;
78
use super::{BoxedValueFilter, FilterValue};
@@ -167,8 +168,11 @@ impl Context {
167168
}
168169

169170
/// Sets a value in the global context.
170-
pub fn set_global_val(&mut self, name: &str, val: Value) -> Option<Value> {
171-
self.globals.insert(name.to_owned(), val)
171+
pub fn set_global_val<S>(&mut self, name: S, val: Value) -> Option<Value>
172+
where
173+
S: Into<borrow::Cow<'static, str>>,
174+
{
175+
self.globals.insert(name.into(), val)
172176
}
173177

174178
/// Sets a value to the rendering context.
@@ -179,9 +183,12 @@ impl Context {
179183
/// Panics if there is no frame on the local values stack. Context
180184
/// instances are created with a top-level stack frame in place, so
181185
/// this should never happen in a well-formed program.
182-
pub fn set_val(&mut self, name: &str, val: Value) -> Option<Value> {
186+
pub fn set_val<S>(&mut self, name: S, val: Value) -> Option<Value>
187+
where
188+
S: Into<borrow::Cow<'static, str>>,
189+
{
183190
match self.stack.last_mut() {
184-
Some(frame) => frame.insert(name.to_owned(), val),
191+
Some(frame) => frame.insert(name.into(), val),
185192
None => panic!("Cannot insert into an empty stack"),
186193
}
187194
}
@@ -202,7 +209,7 @@ mod test {
202209
fn get_val_failure() {
203210
let mut ctx = Context::new();
204211
let mut post = Object::new();
205-
post.insert("number".to_owned(), Value::scalar(42f64));
212+
post.insert("number".into(), Value::scalar(42f64));
206213
ctx.set_global_val("post", Value::Object(post));
207214
assert!(ctx.get_val("post.number").is_none());
208215
}
@@ -211,7 +218,7 @@ mod test {
211218
fn get_val_by_index() {
212219
let mut ctx = Context::new();
213220
let mut post = Object::new();
214-
post.insert("number".to_owned(), Value::scalar(42f64));
221+
post.insert("number".into(), Value::scalar(42f64));
215222
ctx.set_global_val("post", Value::Object(post));
216223
let indexes = vec![Index::with_key("post"), Index::with_key("number")];
217224
assert_eq!(

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//! .parse("Liquid! {{num | minus: 2}}").unwrap();
1515
//!
1616
//! let mut globals = liquid::Object::new();
17-
//! globals.insert("num".to_owned(), liquid::Value::scalar(4f64));
17+
//! globals.insert("num".into(), liquid::Value::scalar(4f64));
1818
//!
1919
//! let output = template.render(&globals).unwrap();
2020
//! assert_eq!(output, "Liquid! 2".to_string());

src/parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ impl Parser {
259259
/// .parse_file("path/to/template.txt").unwrap();
260260
///
261261
/// let mut globals = liquid::Object::new();
262-
/// globals.insert("data".to_owned(), liquid::Value::scalar(4f64));
262+
/// globals.insert("data".into(), liquid::Value::scalar(4f64));
263263
/// let output = template.render(&globals).unwrap();
264264
/// assert_eq!(output, "Liquid! 4\n".to_string());
265265
/// ```

src/tags/assign_tag.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl Renderable for Assign {
2525
let value = self.src
2626
.apply_filters(context)
2727
.trace_with(|| self.trace().into())?;
28-
context.set_global_val(&self.dst, value);
28+
context.set_global_val(self.dst.to_owned(), value);
2929
Ok(None)
3030
}
3131
}

src/tags/capture_block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl Renderable for Capture {
2828
.trace_with(|| self.trace().into())?
2929
.unwrap_or_else(|| "".to_owned());
3030

31-
context.set_global_val(&self.id, Value::scalar(output));
31+
context.set_global_val(self.id.to_owned(), Value::scalar(output));
3232
Ok(None)
3333
}
3434
}

src/tags/for_block.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,22 +131,22 @@ impl Renderable for For {
131131
let mut ret = String::default();
132132
context.run_in_scope(|mut scope| {
133133
let mut helper_vars = Object::new();
134-
helper_vars.insert("length".to_owned(), Value::scalar(range_len as i32));
134+
helper_vars.insert("length".into(), Value::scalar(range_len as i32));
135135

136136
for (i, v) in range.iter().enumerate() {
137-
helper_vars.insert("index0".to_owned(), Value::scalar(i as i32));
138-
helper_vars.insert("index".to_owned(), Value::scalar((i + 1) as i32));
137+
helper_vars.insert("index0".into(), Value::scalar(i as i32));
138+
helper_vars.insert("index".into(), Value::scalar((i + 1) as i32));
139139
helper_vars.insert(
140-
"rindex0".to_owned(),
140+
"rindex0".into(),
141141
Value::scalar((range_len - i - 1) as i32),
142142
);
143143
helper_vars
144-
.insert("rindex".to_owned(), Value::scalar((range_len - i) as i32));
145-
helper_vars.insert("first".to_owned(), Value::scalar(i == 0));
146-
helper_vars.insert("last".to_owned(), Value::scalar(i == (range_len - 1)));
144+
.insert("rindex".into(), Value::scalar((range_len - i) as i32));
145+
helper_vars.insert("first".into(), Value::scalar(i == 0));
146+
helper_vars.insert("last".into(), Value::scalar(i == (range_len - 1)));
147147

148148
scope.set_val("forloop", Value::Object(helper_vars.clone()));
149-
scope.set_val(&self.var_name, v.clone());
149+
scope.set_val(self.var_name.to_owned(), v.clone());
150150
let inner = self.item_template
151151
.render(&mut scope)
152152
.trace_with(|| self.trace().into())

src/tags/if_block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ mod test {
502502

503503
let mut context = Context::new();
504504
let mut obj = Object::new();
505-
obj.insert("Star Wars".to_owned(), Value::scalar("1977"));
505+
obj.insert("Star Wars".into(), Value::scalar("1977"));
506506
context.set_global_val("movies", Value::Object(obj));
507507
let output = template.render(&mut context).unwrap();
508508
assert_eq!(output, Some("if true".to_owned()));

src/value/values.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub enum Value {
3232
pub type Array = Vec<Value>;
3333

3434
/// Type representing a Liquid object, payload of the `Value::Object` variant
35-
pub type Object = MapImpl<String, Value>;
35+
pub type Object = MapImpl<borrow::Cow<'static, str>, Value>;
3636

3737
impl Value {
3838
pub fn scalar<T: Into<Scalar>>(value: T) -> Self {
@@ -57,7 +57,7 @@ impl Value {
5757
}
5858
Value::Object(ref x) => {
5959
let arr: Vec<String> = x.iter()
60-
.map(|(k, v)| k.clone() + ": " + &v.to_string())
60+
.map(|(k, v)| format!("{}: {}", k, v))
6161
.collect();
6262
borrow::Cow::Owned(arr.join(", "))
6363
}
@@ -297,17 +297,17 @@ mod test {
297297
#[test]
298298
fn object_equality() {
299299
let a: Object = [
300-
("alpha".to_owned(), Value::scalar("1")),
301-
("beta".to_owned(), Value::scalar(2f64)),
300+
("alpha".into(), Value::scalar("1")),
301+
("beta".into(), Value::scalar(2f64)),
302302
].into_iter()
303303
.cloned()
304304
.collect();
305305
let a = Value::Object(a);
306306

307307
let b: Object = [
308-
("alpha".to_owned(), Value::scalar("1")),
309-
("beta".to_owned(), Value::scalar(2f64)),
310-
("gamma".to_owned(), Value::Array(vec![])),
308+
("alpha".into(), Value::scalar("1")),
309+
("beta".into(), Value::scalar(2f64)),
310+
("gamma".into(), Value::Array(vec![])),
311311
].into_iter()
312312
.cloned()
313313
.collect();

tests/filters.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ pub fn escape() {
464464
];
465465
for t in &samples {
466466
let mut globals = liquid::Object::new();
467-
globals.insert("var".to_owned(), liquid::Value::scalar(t.0));
467+
globals.insert("var".into(), liquid::Value::scalar(t.0));
468468
let template = liquid::ParserBuilder::with_liquid()
469469
.build()
470470
.parse(text)
@@ -487,7 +487,7 @@ pub fn escape_once() {
487487
];
488488
for t in &samples {
489489
let mut globals = liquid::Object::new();
490-
globals.insert("var".to_owned(), liquid::Value::scalar(t.0));
490+
globals.insert("var".into(), liquid::Value::scalar(t.0));
491491
let template = liquid::ParserBuilder::with_liquid()
492492
.build()
493493
.parse(text)

tests/fixtures.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ numTwo: 6
5353
#[test]
5454
pub fn include() {
5555
let mut globals: liquid::Object = Default::default();
56-
globals.insert("num".to_owned(), Value::scalar(5f64));
57-
globals.insert("numTwo".to_owned(), Value::scalar(10f64));
56+
globals.insert("num".into(), Value::scalar(5f64));
57+
globals.insert("numTwo".into(), Value::scalar(10f64));
5858
compare_by_file("include", &globals);
5959
}
6060

tests/parse_file.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ numTwo: 6
6666
#[test]
6767
pub fn include_by_file() {
6868
let mut globals: Object = Default::default();
69-
globals.insert("num".to_owned(), Value::scalar(5f64));
70-
globals.insert("numTwo".to_owned(), Value::scalar(10f64));
69+
globals.insert("num".into(), Value::scalar(5f64));
70+
globals.insert("numTwo".into(), Value::scalar(10f64));
7171
compare_by_file("include", &globals);
7272
}
7373

tests/value.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ pub fn deserialize_object() {
143143
let actual: liquid::Value =
144144
serde_yaml::from_str("---\nNum: 1\nBool: true\nStr: \"true\"").unwrap();
145145
let expected: liquid::Object = [
146-
("Num".to_owned(), liquid::Value::scalar(1f64)),
147-
("Bool".to_owned(), liquid::Value::scalar(true)),
148-
("Str".to_owned(), liquid::Value::scalar("true")),
146+
("Num".into(), liquid::Value::scalar(1f64)),
147+
("Bool".into(), liquid::Value::scalar(true)),
148+
("Str".into(), liquid::Value::scalar("true")),
149149
].iter()
150150
.cloned()
151151
.collect();

0 commit comments

Comments
 (0)