From a622a7e1bc40571c369133e2830cc6a078668c39 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 14 Jun 2020 18:27:28 -0400 Subject: [PATCH] Add an is_castable() function to stop casting to number for booleans in the @size helper. --- src/bin.rs | 13 ++++++++++++- src/renderer/context_element.rs | 12 ++++++++++++ src/renderer/parameters_context.rs | 10 ++++++++++ src/renderer/renderer.rs | 15 +++++++++++---- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index 3a7eade..a614f88 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -317,6 +317,17 @@ impl Loopable for serde_json::Value { } impl Sizable for serde_json::Value { + fn is_castable(&self) -> bool { + match self { + serde_json::Value::Null => true, + serde_json::Value::Bool(_) => false, + serde_json::Value::Number(_) => true, + serde_json::Value::String(_) => true, + serde_json::Value::Array(_) => true, + serde_json::Value::Object(_) => true, + } + } + fn get_size<'a>(&'a self) -> Option> { match self { serde_json::Value::Null => { @@ -368,7 +379,7 @@ impl Castable for serde_json::Value { (serde_json::Value::Array(_), "number") => None, (serde_json::Value::Object(_), "number") => None, - (serde_json::Value::String(text), "string") => Some(IceResult::from_borrowed(self)), + (serde_json::Value::String(_), "string") => Some(IceResult::from_borrowed(self)), (serde_json::Value::Number(num), "string") => Some(IceResult::from_owned( serde_json::Value::String(num.to_string()), )), diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 01281d3..0e4779c 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -65,6 +65,18 @@ pub trait Castable { } pub trait Sizable { + /// Special case: In DustJS the @size helper usually attempts to + /// cast to a number before calculating the size. The exception to + /// this is booleans. `Number(true) == 1` but `@size` on any + /// boolean is always 0. Make this function return false for any + /// type that casting to a number shouldn't be attempted. + /// + /// Note: Its fine for objects that cannot be cast to a number to + /// return true here. False is only needed for cases where casting + /// to a number would cause a deviation in the final value for + /// `@size`. + fn is_castable(&self) -> bool; + fn get_size<'a>(&'a self) -> Option>; } diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 8c8255d..a03535c 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -196,6 +196,16 @@ impl Walkable for OwnedLiteral { } impl Sizable for OwnedLiteral { + fn is_castable(&self) -> bool { + match self { + OwnedLiteral::LBoolean(_) => false, + OwnedLiteral::LFloat(_) => true, + OwnedLiteral::LPositiveInteger(_) => true, + OwnedLiteral::LNegativeInteger(_) => true, + OwnedLiteral::LString(_) => true, + } + } + fn get_size<'a>(&'a self) -> Option> { match self { OwnedLiteral::LBoolean(_) => { diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index eef9a3f..023cd38 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -730,7 +730,6 @@ impl<'a> DustRenderer<'a> { maybe_ice .as_ref() .map(|ice| ice.get_context_element_reference()) - // .map(|ce| ce.get_size()) }); match value_ce { // If "key" is not on the @size tag at all, render 0. @@ -742,8 +741,8 @@ impl<'a> DustRenderer<'a> { // numbers, and if that succeeds it uses the // number, otherwise we'll get the size of the // original type. - match ce.cast_to_type("number") { - Some(ice) => { + match (ce.cast_to_type("number"), ce.is_castable()) { + (Some(ice), true) => { return ice .get_context_element_reference() .get_size() @@ -752,7 +751,15 @@ impl<'a> DustRenderer<'a> { }) .unwrap_or(Ok("".to_owned())) } - None => { + (Some(_), false) => { + return ce + .get_size() + .map(|ce_size| { + ce_size.get_context_element_reference().render(&Vec::new()) + }) + .unwrap_or(Ok("".to_owned())) + } + (None, _) => { return ce .get_size() .map(|ce_size| {