diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index cd83681..dc190dc 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -77,6 +77,18 @@ impl<'a> DustRenderer<'a> { self.render_body(&main_template.contents, breadcrumbs, &new_blocks) } + fn render_maybe_body( + &'a self, + body: &'a Option, + breadcrumbs: &Vec<&'a dyn ContextElement>, + blocks: &'a InlinePartialTreeElement<'a>, + ) -> Result { + match body { + None => Ok("".to_owned()), + Some(body) => Ok(self.render_body(body, breadcrumbs, blocks)?), + } + } + fn render_body( &'a self, body: &'a Body, @@ -130,16 +142,13 @@ impl<'a> DustRenderer<'a> { } DustTag::DTSection(container) => { let val = walk_path(breadcrumbs, &container.path.keys); - let loop_elements: Vec<&dyn ContextElement> = self.get_loop_elements(val); + let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); if loop_elements.is_empty() { // Oddly enough if the value is falsey (like // an empty array or null), Dust uses the // original context before walking the path as // the context for rendering the else block - return match &container.else_contents { - Some(body) => self.render_body(&body, breadcrumbs, blocks), - None => Ok("".to_owned()), - }; + return self.render_maybe_body(&container.else_contents, breadcrumbs, blocks); } else { match &container.contents { None => return Ok("".to_owned()), @@ -160,33 +169,21 @@ impl<'a> DustRenderer<'a> { } DustTag::DTExists(container) => { let val = walk_path(breadcrumbs, &container.path.keys); - let loop_elements: Vec<&dyn ContextElement> = self.get_loop_elements(val); - if loop_elements.is_empty() { - return match &container.else_contents { - Some(body) => self.render_body(&body, breadcrumbs, blocks), - None => Ok("".to_owned()), - }; + let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); + return if loop_elements.is_empty() { + self.render_maybe_body(&container.else_contents, breadcrumbs, blocks) } else { - return match &container.contents { - None => Ok("".to_owned()), - Some(body) => self.render_body(&body, breadcrumbs, blocks), - }; - } + self.render_maybe_body(&container.contents, breadcrumbs, blocks) + }; } DustTag::DTNotExists(container) => { let val = walk_path(breadcrumbs, &container.path.keys); - let loop_elements: Vec<&dyn ContextElement> = self.get_loop_elements(val); - if !loop_elements.is_empty() { - return match &container.else_contents { - Some(body) => self.render_body(&body, breadcrumbs, blocks), - None => Ok("".to_owned()), - }; + let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); + return if !loop_elements.is_empty() { + self.render_maybe_body(&container.else_contents, breadcrumbs, blocks) } else { - return match &container.contents { - None => Ok("".to_owned()), - Some(body) => self.render_body(&body, breadcrumbs, blocks), - }; - } + self.render_maybe_body(&container.contents, breadcrumbs, blocks) + }; } DustTag::DTPartial(partial) => { if partial.params.is_empty() { @@ -202,34 +199,19 @@ impl<'a> DustRenderer<'a> { return Ok(rendered_content); } } - DustTag::DTInlinePartial(named_block) => { + DustTag::DTInlinePartial(_named_block) => { // Inline partials are blank during rendering (they get injected into blocks) return Ok("".to_owned()); } DustTag::DTBlock(named_block) => { - match blocks.get_block(named_block.name) { - None => match &named_block.contents { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - }, - Some(interior) => match interior { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - }, + return match blocks.get_block(named_block.name) { + None => self.render_maybe_body(&named_block.contents, breadcrumbs, blocks), + Some(interior) => self.render_maybe_body(interior, breadcrumbs, blocks), }; } DustTag::DTHelperEquals(parameterized_block) => { - let param_map: HashMap<&str, &RValue<'a>> = parameterized_block - .params - .iter() - .map(|pair: &KVPair<'a>| (pair.key, &pair.value)) - .collect(); + let param_map: HashMap<&str, &RValue<'a>> = + Self::get_rval_map(¶meterized_block.params); // Special case: when comparing two RVPaths, if the // path is equal then dust assumes the values are // equal (otherwise, non-scalar values are @@ -244,47 +226,31 @@ impl<'a> DustRenderer<'a> { }; } - let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") { - None => return Ok("".to_owned()), - Some(rval) => match rval { - RValue::RVString(text) => Ok(text), - RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), - RValue::RVPositiveInteger(num) => Ok(num), - }, - }; - let right_side: Result<&dyn ContextElement, WalkError> = - match param_map.get("value") { - None => Err(WalkError::CantWalk), - Some(rval) => match rval { - RValue::RVString(text) => Ok(text), - RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), - RValue::RVPositiveInteger(num) => Ok(num), - }, + let left_side: Result<&dyn ContextElement, WalkError> = + match Self::get_rval(breadcrumbs, ¶m_map, "key") { + None => return Ok("".to_owned()), + Some(res) => res, }; + let right_side: Result<&dyn ContextElement, WalkError> = + Self::get_rval(breadcrumbs, ¶m_map, "value") + .unwrap_or(Err(WalkError::CantWalk)); if left_side == right_side { - match ¶meterized_block.contents { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - } + return self.render_maybe_body( + ¶meterized_block.contents, + breadcrumbs, + blocks, + ); } else { - match ¶meterized_block.else_contents { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - } + return self.render_maybe_body( + ¶meterized_block.else_contents, + breadcrumbs, + blocks, + ); } } DustTag::DTHelperNotEquals(parameterized_block) => { - let param_map: HashMap<&str, &RValue<'a>> = parameterized_block - .params - .iter() - .map(|pair: &KVPair<'a>| (pair.key, &pair.value)) - .collect(); + let param_map: HashMap<&str, &RValue<'a>> = + Self::get_rval_map(¶meterized_block.params); // Special case: when comparing two RVPaths, if the // path is equal then dust assumes the values are // equal (otherwise, non-scalar values are @@ -299,64 +265,39 @@ impl<'a> DustRenderer<'a> { }; } - let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") { - None => return Ok("".to_owned()), - Some(rval) => match rval { - RValue::RVString(text) => Ok(text), - RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), - RValue::RVPositiveInteger(num) => Ok(num), - }, - }; - let right_side: Result<&dyn ContextElement, WalkError> = - match param_map.get("value") { - None => Err(WalkError::CantWalk), - Some(rval) => match rval { - RValue::RVString(text) => Ok(text), - RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), - RValue::RVPositiveInteger(num) => Ok(num), - }, + let left_side: Result<&dyn ContextElement, WalkError> = + match Self::get_rval(breadcrumbs, ¶m_map, "key") { + None => return Ok("".to_owned()), + Some(res) => res, }; + let right_side: Result<&dyn ContextElement, WalkError> = + Self::get_rval(breadcrumbs, ¶m_map, "value") + .unwrap_or(Err(WalkError::CantWalk)); if left_side != right_side { - match ¶meterized_block.contents { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - } + return self.render_maybe_body( + ¶meterized_block.contents, + breadcrumbs, + blocks, + ); } else { - match ¶meterized_block.else_contents { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - } + return self.render_maybe_body( + ¶meterized_block.else_contents, + breadcrumbs, + blocks, + ); } } DustTag::DTHelperGreaterThan(parameterized_block) => { - let param_map: HashMap<&str, &RValue<'a>> = parameterized_block - .params - .iter() - .map(|pair: &KVPair<'a>| (pair.key, &pair.value)) - .collect(); - let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") { - None => return Ok("".to_owned()), - Some(rval) => match rval { - RValue::RVString(text) => Ok(text), - RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), - RValue::RVPositiveInteger(num) => Ok(num), - }, - }; - let right_side: Result<&dyn ContextElement, WalkError> = - match param_map.get("value") { - None => Err(WalkError::CantWalk), - Some(rval) => match rval { - RValue::RVString(text) => Ok(text), - RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), - RValue::RVPositiveInteger(num) => Ok(num), - }, + let param_map: HashMap<&str, &RValue<'a>> = + Self::get_rval_map(¶meterized_block.params); + let left_side: Result<&dyn ContextElement, WalkError> = + match Self::get_rval(breadcrumbs, ¶m_map, "key") { + None => return Ok("".to_owned()), + Some(res) => res, }; + let right_side: Result<&dyn ContextElement, WalkError> = + Self::get_rval(breadcrumbs, ¶m_map, "value") + .unwrap_or(Err(WalkError::CantWalk)); match (left_side, right_side) { (Err(_), _) | (_, Err(_)) => match ¶meterized_block.else_contents { None => return Ok("".to_owned()), @@ -367,23 +308,17 @@ impl<'a> DustRenderer<'a> { }, (Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => { if left_side_unwrapped > right_side_unwrapped { - match ¶meterized_block.contents { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = - self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - } + return self.render_maybe_body( + ¶meterized_block.contents, + breadcrumbs, + blocks, + ); } else { - match ¶meterized_block.else_contents { - None => return Ok("".to_owned()), - Some(body) => { - let rendered_content = - self.render_body(body, breadcrumbs, blocks)?; - return Ok(rendered_content); - } - } + return self.render_maybe_body( + ¶meterized_block.else_contents, + breadcrumbs, + blocks, + ); } } } @@ -398,7 +333,6 @@ impl<'a> DustRenderer<'a> { /// If the value is falsey, and therefore should render the else /// block, this will return an empty vector. fn get_loop_elements<'b>( - &'a self, walk_result: Result<&'b dyn ContextElement, WalkError>, ) -> Vec<&'b dyn ContextElement> { match walk_result { @@ -419,6 +353,28 @@ impl<'a> DustRenderer<'a> { }, } } + + fn get_rval_map<'b>(params: &'b Vec>) -> HashMap<&'b str, &'b RValue<'b>> { + params + .iter() + .map(|pair: &KVPair<'b>| (pair.key, &pair.value)) + .collect() + } + + fn get_rval<'b>( + breadcrumbs: &Vec<&'b dyn ContextElement>, + param_map: &HashMap<&str, &'b RValue<'b>>, + key: &str, + ) -> Option> { + match param_map.get(key) { + None => None, + Some(rval) => match rval { + RValue::RVString(text) => Some(Ok(text)), + RValue::RVPath(path) => Some(walk_path(breadcrumbs, &path.keys)), + RValue::RVPositiveInteger(num) => Some(Ok(num)), + }, + } + } } #[cfg(test)]