Skip to content

Commit

Permalink
fix(if): Improve accuracy of contains op
Browse files Browse the repository at this point in the history
- Centralize logic for `Object` logic.
- Rely on `Value` equality for `Array` logic.
- Possible performance improvement in `Object` logic.
  • Loading branch information
epage committed Nov 17, 2018
1 parent 385a62f commit 07452cd
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 10 deletions.
36 changes: 31 additions & 5 deletions liquid-value/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,16 +194,31 @@ impl Value {
}
}

/// Access a contained `Value`.
pub fn contains_key(&self, index: &Scalar) -> bool {
match *self {
Value::Array(ref x) => {
if let Some(index) = index.to_integer() {
let index = convert_index(index, x.len());
index < x.len()
} else {
match &*index.to_str() {
"first" | "last" => true,
_ => false,
}
}
}
Value::Object(ref x) => x.contains_key(index.to_str().as_ref()),
_ => false,
}
}

/// Access a contained `Value`.
pub fn get<'s>(&'s self, index: &Scalar) -> Option<&'s Self> {
match *self {
Value::Array(ref x) => {
if let Some(index) = index.to_integer() {
let index = if 0 <= index {
index as isize
} else {
(x.len() as isize) + (index as isize)
};
let index = convert_index(index, x.len());
x.get(index as usize)
} else {
match &*index.to_str() {
Expand All @@ -219,6 +234,17 @@ impl Value {
}
}

fn convert_index(index: i32, max_size: usize) -> usize {
let index = index as isize;
let max_size = max_size as isize;
let index = if 0 <= index {
index
} else {
max_size + index
};
index as usize
}

impl Default for Value {
fn default() -> Self {
Self::nil()
Expand Down
14 changes: 9 additions & 5 deletions src/tags/if_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,18 @@ struct Conditional {
}

fn contains_check(a: &Value, b: &Value) -> Result<bool> {
let b = b.to_str();

match *a {
Value::Scalar(ref val) => Ok(val.to_str().contains(b.as_ref())),
Value::Object(ref obj) => Ok(obj.contains_key(b.as_ref())),
Value::Scalar(ref val) => {
let b = b.to_str();
Ok(val.to_str().contains(b.as_ref()))
},
Value::Object(_) => {
let b = b.as_scalar();
let check = b.map(|b| a.contains_key(b)).unwrap_or(false);
Ok(check)
},
Value::Array(ref arr) => {
for elem in arr {
let elem = elem.to_str();
if elem == b {
return Ok(true);
}
Expand Down

0 comments on commit 07452cd

Please sign in to comment.