Add an is_castable() function to stop casting to number for booleans in the @size helper.

master
Tom Alexander 4 years ago
parent e54e20d254
commit a622a7e1bc
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

@ -317,6 +317,17 @@ impl Loopable for serde_json::Value {
} }
impl Sizable 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<IceResult<'a>> { fn get_size<'a>(&'a self) -> Option<IceResult<'a>> {
match self { match self {
serde_json::Value::Null => { serde_json::Value::Null => {
@ -368,7 +379,7 @@ impl Castable for serde_json::Value {
(serde_json::Value::Array(_), "number") => None, (serde_json::Value::Array(_), "number") => None,
(serde_json::Value::Object(_), "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::Number(num), "string") => Some(IceResult::from_owned(
serde_json::Value::String(num.to_string()), serde_json::Value::String(num.to_string()),
)), )),

@ -65,6 +65,18 @@ pub trait Castable {
} }
pub trait Sizable { 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<IceResult<'a>>; fn get_size<'a>(&'a self) -> Option<IceResult<'a>>;
} }

@ -196,6 +196,16 @@ impl Walkable for OwnedLiteral {
} }
impl Sizable 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<IceResult<'a>> { fn get_size<'a>(&'a self) -> Option<IceResult<'a>> {
match self { match self {
OwnedLiteral::LBoolean(_) => { OwnedLiteral::LBoolean(_) => {

@ -730,7 +730,6 @@ impl<'a> DustRenderer<'a> {
maybe_ice maybe_ice
.as_ref() .as_ref()
.map(|ice| ice.get_context_element_reference()) .map(|ice| ice.get_context_element_reference())
// .map(|ce| ce.get_size())
}); });
match value_ce { match value_ce {
// If "key" is not on the @size tag at all, render 0. // 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 // numbers, and if that succeeds it uses the
// number, otherwise we'll get the size of the // number, otherwise we'll get the size of the
// original type. // original type.
match ce.cast_to_type("number") { match (ce.cast_to_type("number"), ce.is_castable()) {
Some(ice) => { (Some(ice), true) => {
return ice return ice
.get_context_element_reference() .get_context_element_reference()
.get_size() .get_size()
@ -752,7 +751,15 @@ impl<'a> DustRenderer<'a> {
}) })
.unwrap_or(Ok("".to_owned())) .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 return ce
.get_size() .get_size()
.map(|ce_size| { .map(|ce_size| {

Loading…
Cancel
Save