diff --git a/src/bin.rs b/src/bin.rs index ec05dd1..43690e1 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -50,7 +50,7 @@ fn main() { .first() .expect("There should be more than 1 template") .name; - let breadcrumbs = vec![&context as &dyn IntoContextElement]; + // let breadcrumbs = vec![&context as &dyn IntoContextElement]; // println!( // "{}", // dust_renderer @@ -161,288 +161,288 @@ fn encode_uri_component(inp: &str) -> String { output } -fn apply_filter( - json_value: &serde_json::Value, - filter: &Filter, -) -> Result { - match (json_value, filter) { - // Html escape filter - (serde_json::Value::String(string), Filter::HtmlEncode) => { - Ok(serde_json::Value::String(html_escape(string))) - } - (_, Filter::HtmlEncode) => Ok(serde_json::Value::String(html_escape( - &json_value.render(&Vec::new())?, - ))), - // Disable html escape filter - (_, Filter::DisableHtmlEncode) => panic!("The |s filter is automatically removed by the renderer since it is a no-op during rendering."), - // Parse JSON filter - (serde_json::Value::String(string), Filter::JsonParse) => { - serde_json::from_str(&string).or(Err(RenderError::InvalidJson(string.to_owned()))) - } - (_, Filter::JsonParse) => { - let rendered_value = json_value.render(&Vec::new())?; - serde_json::from_str(&rendered_value).or(Err(RenderError::InvalidJson(rendered_value))) - } - // Json Stringify filter - (_, Filter::JsonStringify) => { - Ok(serde_json::Value::String(json_value.to_string())) - } - // Javascript escape filter - (serde_json::Value::String(string), Filter::JavascriptStringEncode) => { - Ok(serde_json::Value::String(javascript_escape(string))) - } - (serde_json::Value::Bool(boolean), Filter::JavascriptStringEncode) => { - Ok(serde_json::Value::Bool(*boolean)) - } - (serde_json::Value::Number(number), Filter::JavascriptStringEncode) => { - Ok(serde_json::Value::Number(number.clone())) - } - (serde_json::Value::Array(arr), Filter::JavascriptStringEncode) => { - Ok(serde_json::Value::Array(arr.clone())) - } - (serde_json::Value::Object(obj), Filter::JavascriptStringEncode) => { - Ok(serde_json::Value::Object(obj.clone())) - } - (_, Filter::JavascriptStringEncode) => Ok(serde_json::Value::String(javascript_escape( - &json_value.render(&Vec::new())?, - ))), - // EncodeURI filter - (serde_json::Value::String(string), Filter::EncodeUri) => { - Ok(serde_json::Value::String(encode_uri(string))) - } - (_, Filter::EncodeUri) => Ok(serde_json::Value::String(encode_uri( - &json_value.render(&Vec::new())?, - ))), - // EncodeURIComponent filter - (serde_json::Value::String(string), Filter::EncodeUriComponent) => { - Ok(serde_json::Value::String(encode_uri_component(string))) - } - (_, Filter::EncodeUriComponent) => Ok(serde_json::Value::String(encode_uri_component( - &json_value.render(&Vec::new())?, - ))), - } -} +// fn apply_filter( +// json_value: &serde_json::Value, +// filter: &Filter, +// ) -> Result { +// match (json_value, filter) { +// // Html escape filter +// (serde_json::Value::String(string), Filter::HtmlEncode) => { +// Ok(serde_json::Value::String(html_escape(string))) +// } +// (_, Filter::HtmlEncode) => Ok(serde_json::Value::String(html_escape( +// &json_value.render(&Vec::new())?, +// ))), +// // Disable html escape filter +// (_, Filter::DisableHtmlEncode) => panic!("The |s filter is automatically removed by the renderer since it is a no-op during rendering."), +// // Parse JSON filter +// (serde_json::Value::String(string), Filter::JsonParse) => { +// serde_json::from_str(&string).or(Err(RenderError::InvalidJson(string.to_owned()))) +// } +// (_, Filter::JsonParse) => { +// let rendered_value = json_value.render(&Vec::new())?; +// serde_json::from_str(&rendered_value).or(Err(RenderError::InvalidJson(rendered_value))) +// } +// // Json Stringify filter +// (_, Filter::JsonStringify) => { +// Ok(serde_json::Value::String(json_value.to_string())) +// } +// // Javascript escape filter +// (serde_json::Value::String(string), Filter::JavascriptStringEncode) => { +// Ok(serde_json::Value::String(javascript_escape(string))) +// } +// (serde_json::Value::Bool(boolean), Filter::JavascriptStringEncode) => { +// Ok(serde_json::Value::Bool(*boolean)) +// } +// (serde_json::Value::Number(number), Filter::JavascriptStringEncode) => { +// Ok(serde_json::Value::Number(number.clone())) +// } +// (serde_json::Value::Array(arr), Filter::JavascriptStringEncode) => { +// Ok(serde_json::Value::Array(arr.clone())) +// } +// (serde_json::Value::Object(obj), Filter::JavascriptStringEncode) => { +// Ok(serde_json::Value::Object(obj.clone())) +// } +// (_, Filter::JavascriptStringEncode) => Ok(serde_json::Value::String(javascript_escape( +// &json_value.render(&Vec::new())?, +// ))), +// // EncodeURI filter +// (serde_json::Value::String(string), Filter::EncodeUri) => { +// Ok(serde_json::Value::String(encode_uri(string))) +// } +// (_, Filter::EncodeUri) => Ok(serde_json::Value::String(encode_uri( +// &json_value.render(&Vec::new())?, +// ))), +// // EncodeURIComponent filter +// (serde_json::Value::String(string), Filter::EncodeUriComponent) => { +// Ok(serde_json::Value::String(encode_uri_component(string))) +// } +// (_, Filter::EncodeUriComponent) => Ok(serde_json::Value::String(encode_uri_component( +// &json_value.render(&Vec::new())?, +// ))), +// } +// } -fn apply_filters( - json_value: &serde_json::Value, - filters: &[Filter], -) -> Result { - let mut final_value: serde_json::Value = apply_filter(json_value, &filters[0])?; +// fn apply_filters( +// json_value: &serde_json::Value, +// filters: &[Filter], +// ) -> Result { +// let mut final_value: serde_json::Value = apply_filter(json_value, &filters[0])?; - for filter in &filters[1..] { - final_value = apply_filter(&final_value, filter)?; - } +// for filter in &filters[1..] { +// final_value = apply_filter(&final_value, filter)?; +// } - Ok(final_value) -} +// Ok(final_value) +// } -impl ContextElement for serde_json::Value {} +// impl ContextElement for serde_json::Value {} -impl Truthiness for serde_json::Value { - fn is_truthy(&self) -> bool { - match self { - serde_json::Value::Null => false, - serde_json::Value::Bool(boolean) => *boolean, - serde_json::Value::Number(_num) => true, - serde_json::Value::String(string_value) => !string_value.is_empty(), - serde_json::Value::Array(array_value) => !array_value.is_empty(), - serde_json::Value::Object(_obj) => true, - } - } -} +// impl Truthiness for serde_json::Value { +// fn is_truthy(&self) -> bool { +// match self { +// serde_json::Value::Null => false, +// serde_json::Value::Bool(boolean) => *boolean, +// serde_json::Value::Number(_num) => true, +// serde_json::Value::String(string_value) => !string_value.is_empty(), +// serde_json::Value::Array(array_value) => !array_value.is_empty(), +// serde_json::Value::Object(_obj) => true, +// } +// } +// } -impl Renderable for serde_json::Value { - fn render(&self, _filters: &Vec) -> Result { - let after_apply = if _filters.is_empty() { - None - } else { - Some(apply_filters(self, _filters)?) - }; +// impl Renderable for serde_json::Value { +// fn render(&self, _filters: &Vec) -> Result { +// let after_apply = if _filters.is_empty() { +// None +// } else { +// Some(apply_filters(self, _filters)?) +// }; - match after_apply.as_ref().unwrap_or(self) { - serde_json::Value::Null => Ok("".to_owned()), - serde_json::Value::Bool(boolean) => Ok(boolean.to_string()), - serde_json::Value::Number(num) => Ok(num.to_string()), - serde_json::Value::String(string) => Ok(string.to_string()), - serde_json::Value::Array(arr) => { - // TODO: Handle the filters instead of passing a Vec::new() - let rendered: Result, RenderError> = - arr.iter().map(|val| val.render(&Vec::new())).collect(); - let rendered_slice: &[String] = &rendered?; - Ok(rendered_slice.join(",")) - } - serde_json::Value::Object(_obj) => Ok("[object Object]".to_owned()), - } - } -} +// match after_apply.as_ref().unwrap_or(self) { +// serde_json::Value::Null => Ok("".to_owned()), +// serde_json::Value::Bool(boolean) => Ok(boolean.to_string()), +// serde_json::Value::Number(num) => Ok(num.to_string()), +// serde_json::Value::String(string) => Ok(string.to_string()), +// serde_json::Value::Array(arr) => { +// // TODO: Handle the filters instead of passing a Vec::new() +// let rendered: Result, RenderError> = +// arr.iter().map(|val| val.render(&Vec::new())).collect(); +// let rendered_slice: &[String] = &rendered?; +// Ok(rendered_slice.join(",")) +// } +// serde_json::Value::Object(_obj) => Ok("[object Object]".to_owned()), +// } +// } +// } -impl Walkable for serde_json::Value { - fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> { - match self { - serde_json::Value::Null => Err(WalkError::CantWalk), - serde_json::Value::Bool(_boolean) => Err(WalkError::CantWalk), - serde_json::Value::Number(_num) => Err(WalkError::CantWalk), - serde_json::Value::String(_string) => Err(WalkError::CantWalk), - serde_json::Value::Array(_arr) => Err(WalkError::CantWalk), - serde_json::Value::Object(obj) => obj - .get(segment) - .map(|val| val as _) - .ok_or(WalkError::CantWalk), - } - } -} +// impl Walkable for serde_json::Value { +// fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> { +// match self { +// serde_json::Value::Null => Err(WalkError::CantWalk), +// serde_json::Value::Bool(_boolean) => Err(WalkError::CantWalk), +// serde_json::Value::Number(_num) => Err(WalkError::CantWalk), +// serde_json::Value::String(_string) => Err(WalkError::CantWalk), +// serde_json::Value::Array(_arr) => Err(WalkError::CantWalk), +// serde_json::Value::Object(obj) => obj +// .get(segment) +// .map(|val| val as _) +// .ok_or(WalkError::CantWalk), +// } +// } +// } -impl Loopable for serde_json::Value { - fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { - match self { - serde_json::Value::Array(array_value) => array_value.iter().map(|x| x as _).collect(), - _ => Vec::new(), - } - } -} +// impl Loopable for serde_json::Value { +// fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { +// match self { +// serde_json::Value::Array(array_value) => array_value.iter().map(|x| x as _).collect(), +// _ => Vec::new(), +// } +// } +// } -impl CompareContextElement for serde_json::Value { - fn equals(&self, other: &dyn ContextElement) -> bool { - // println!("equals json {:?} | {:?}", self, other); - // Handle other serde_json::Value - match other.to_any().downcast_ref::() { - None => (), - Some(other_json_value) => match (self, other_json_value) { - // Non-scalar values not caught in the renderer by the - // identical-path shortcut are always not equal. - (serde_json::Value::Array(_), _) - | (_, serde_json::Value::Array(_)) - | (serde_json::Value::Object(_), _) - | (_, serde_json::Value::Object(_)) => return false, - _ => return self == other_json_value, - }, - } - // Handle literals - match other.to_any().downcast_ref::() { - None => (), - Some(OwnedLiteral::LString(other_string)) => { - return self.as_str().map_or(false, |s| s == other_string) - } - Some(OwnedLiteral::LPositiveInteger(other_num)) => { - return self.as_u64().map_or(false, |n| n == *other_num) - } - } - false - } +// impl CompareContextElement for serde_json::Value { +// fn equals(&self, other: &dyn ContextElement) -> bool { +// // println!("equals json {:?} | {:?}", self, other); +// // Handle other serde_json::Value +// match other.to_any().downcast_ref::() { +// None => (), +// Some(other_json_value) => match (self, other_json_value) { +// // Non-scalar values not caught in the renderer by the +// // identical-path shortcut are always not equal. +// (serde_json::Value::Array(_), _) +// | (_, serde_json::Value::Array(_)) +// | (serde_json::Value::Object(_), _) +// | (_, serde_json::Value::Object(_)) => return false, +// _ => return self == other_json_value, +// }, +// } +// // Handle literals +// match other.to_any().downcast_ref::() { +// None => (), +// Some(OwnedLiteral::LString(other_string)) => { +// return self.as_str().map_or(false, |s| s == other_string) +// } +// Some(OwnedLiteral::LPositiveInteger(other_num)) => { +// return self.as_u64().map_or(false, |n| n == *other_num) +// } +// } +// false +// } - fn partial_compare(&self, other: &dyn ContextElement) -> Option { - // println!("partial_compare json {:?} | {:?}", self, other); - // Handle type coerced objects +// fn partial_compare(&self, other: &dyn ContextElement) -> Option { +// // println!("partial_compare json {:?} | {:?}", self, other); +// // Handle type coerced objects - // When doing a greater than or less than comparison, - // javascript coerces objects into "[object Object]". - if let serde_json::Value::Object(_) = self { - return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned())) - .partial_compare(other); - } +// // When doing a greater than or less than comparison, +// // javascript coerces objects into "[object Object]". +// if let serde_json::Value::Object(_) = self { +// return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned())) +// .partial_compare(other); +// } - // When doing a greater than or less than comparison - // javascript turns arrays into strings. - if let serde_json::Value::Array(_) = self { - return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned())) - .partial_compare(other); - } +// // When doing a greater than or less than comparison +// // javascript turns arrays into strings. +// if let serde_json::Value::Array(_) = self { +// return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned())) +// .partial_compare(other); +// } - // Handle other serde_json::Value - match other.to_any().downcast_ref::() { - None => (), - Some(other_json_value) => { - return match (self, other_json_value) { - ( - serde_json::Value::Bool(self_boolean), - serde_json::Value::Bool(other_boolean), - ) => self_boolean.partial_cmp(other_boolean), - ( - serde_json::Value::Number(self_number), - serde_json::Value::Number(other_number), - ) => return compare_json_numbers(self_number, other_number), - ( - serde_json::Value::String(self_string), - serde_json::Value::Number(other_number), - ) => return compare_json_numbers(self_string, other_number), - ( - serde_json::Value::Number(self_number), - serde_json::Value::String(other_string), - ) => return compare_json_numbers(self_number, other_string), - ( - serde_json::Value::String(self_string), - serde_json::Value::String(other_string), - ) => self_string.partial_cmp(other_string), - ( - serde_json::Value::Array(self_array), - serde_json::Value::Array(other_array), - ) => { - return self - .render(&Vec::new()) - .unwrap_or("".to_owned()) - .partial_cmp( - &other_json_value - .render(&Vec::new()) - .unwrap_or("".to_owned()), - ) - } - _ => None, - }; - } - } - // Handle literals - match other.to_any().downcast_ref::() { - None => (), - Some(other_literal) => match (self, other_literal) { - (serde_json::Value::String(self_string), OwnedLiteral::LString(other_string)) => { - return self_string.partial_cmp(other_string) - } - ( - serde_json::Value::String(self_string), - OwnedLiteral::LPositiveInteger(other_num), - ) => return compare_json_numbers(self_string, other_literal), - (serde_json::Value::Number(self_num), OwnedLiteral::LString(other_string)) => { - return compare_json_numbers(self_num, other_string) - } - ( - serde_json::Value::Number(self_num), - OwnedLiteral::LPositiveInteger(other_num), - ) => return compare_json_numbers(self_num, other_literal), - (serde_json::Value::Array(_), _) => { - // TODO - todo!() - } - (serde_json::Value::Object(_), _) => { - // TODO - todo!() - } - (serde_json::Value::Bool(_), _) => { - // TODO - todo!() - } - (serde_json::Value::Null, _) => { - // TODO - todo!() - } - }, - } - None - } -} +// // Handle other serde_json::Value +// match other.to_any().downcast_ref::() { +// None => (), +// Some(other_json_value) => { +// return match (self, other_json_value) { +// ( +// serde_json::Value::Bool(self_boolean), +// serde_json::Value::Bool(other_boolean), +// ) => self_boolean.partial_cmp(other_boolean), +// ( +// serde_json::Value::Number(self_number), +// serde_json::Value::Number(other_number), +// ) => return compare_json_numbers(self_number, other_number), +// ( +// serde_json::Value::String(self_string), +// serde_json::Value::Number(other_number), +// ) => return compare_json_numbers(self_string, other_number), +// ( +// serde_json::Value::Number(self_number), +// serde_json::Value::String(other_string), +// ) => return compare_json_numbers(self_number, other_string), +// ( +// serde_json::Value::String(self_string), +// serde_json::Value::String(other_string), +// ) => self_string.partial_cmp(other_string), +// ( +// serde_json::Value::Array(self_array), +// serde_json::Value::Array(other_array), +// ) => { +// return self +// .render(&Vec::new()) +// .unwrap_or("".to_owned()) +// .partial_cmp( +// &other_json_value +// .render(&Vec::new()) +// .unwrap_or("".to_owned()), +// ) +// } +// _ => None, +// }; +// } +// } +// // Handle literals +// match other.to_any().downcast_ref::() { +// None => (), +// Some(other_literal) => match (self, other_literal) { +// (serde_json::Value::String(self_string), OwnedLiteral::LString(other_string)) => { +// return self_string.partial_cmp(other_string) +// } +// ( +// serde_json::Value::String(self_string), +// OwnedLiteral::LPositiveInteger(other_num), +// ) => return compare_json_numbers(self_string, other_literal), +// (serde_json::Value::Number(self_num), OwnedLiteral::LString(other_string)) => { +// return compare_json_numbers(self_num, other_string) +// } +// ( +// serde_json::Value::Number(self_num), +// OwnedLiteral::LPositiveInteger(other_num), +// ) => return compare_json_numbers(self_num, other_literal), +// (serde_json::Value::Array(_), _) => { +// // TODO +// todo!() +// } +// (serde_json::Value::Object(_), _) => { +// // TODO +// todo!() +// } +// (serde_json::Value::Bool(_), _) => { +// // TODO +// todo!() +// } +// (serde_json::Value::Null, _) => { +// // TODO +// todo!() +// } +// }, +// } +// None +// } +// } -/// Create a new vec by of references to the serde_json::Values as -/// ContextElement trait objects so we can use its implementation of -/// PartialOrd. -/// -/// You cannot implement a trait you do not define for a type you do -/// not define, so I cannot implement PartialOrd for -/// serde_json::value. Instead, I just re-use the PartialOrd -/// implementation for ContextElement which unfortunately has extra -/// overhead of downcasting. This would be a good spot for -/// optimization. -fn convert_vec_to_context_element(array: &Vec) -> Vec<&dyn ContextElement> { - array.iter().map(|v| v as _).collect() -} +// /// Create a new vec by of references to the serde_json::Values as +// /// ContextElement trait objects so we can use its implementation of +// /// PartialOrd. +// /// +// /// You cannot implement a trait you do not define for a type you do +// /// not define, so I cannot implement PartialOrd for +// /// serde_json::value. Instead, I just re-use the PartialOrd +// /// implementation for ContextElement which unfortunately has extra +// /// overhead of downcasting. This would be a good spot for +// /// optimization. +// fn convert_vec_to_context_element(array: &Vec) -> Vec<&dyn ContextElement> { +// array.iter().map(|v| v as _).collect() +// } #[derive(Debug)] enum JsonNumber { diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index c31ecc9..68008e0 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -1,4 +1,5 @@ use crate::parser::Filter; +use crate::renderer::breadcrumb_tree::BreadcrumbTree; use crate::renderer::errors::RenderError; use crate::renderer::errors::WalkError; use crate::renderer::DustRenderer; @@ -103,7 +104,7 @@ pub trait IntoContextElement: Debug + Walkable + CloneIntoBoxedContextElement { fn into_context_element( &self, renderer: &DustRenderer, - breadcrumbs: &Vec<&dyn IntoContextElement>, + breadcrumbs: Option<&BreadcrumbTree>, ) -> &dyn ContextElement; } @@ -111,7 +112,7 @@ impl IntoContextElement for C { fn into_context_element( &self, renderer: &DustRenderer, - breadcrumbs: &Vec<&dyn IntoContextElement>, + breadcrumbs: Option<&BreadcrumbTree>, ) -> &dyn ContextElement { self } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 7eecacb..a168830 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -4,8 +4,8 @@ mod breadcrumb_tree; mod context_element; mod errors; mod inline_partial_tree; -mod iteration_context; -mod parameters_context; +// mod iteration_context; +// mod parameters_context; mod renderer; mod tree_walking; mod walking; diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 455dfd9..75d45b2 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -80,17 +80,17 @@ impl<'a> DustRenderer<'a> { Some(_) => None, None => maybe_breadcrumbs, }; - let mut new_nodes = Vec::new(); + let mut new_nodes: Vec = Vec::new(); - // explicit_context.as_ref().map(|path| { - // let x = walk_path(maybe_breadcrumbs, &path.keys); - // x.map(|ice| ice.into_context_element(self, breadcrumbs)) - // .map(|val| { - // if val.is_truthy() { - // new_nodes.push(val.from_context_element()) - // } - // }); - // }); + explicit_context.as_ref().map(|path| { + let x = walk_path(maybe_breadcrumbs, &path.keys); + x.map(|ice| ice.into_context_element(self, maybe_breadcrumbs)) + .map(|val| { + if val.is_truthy() { + new_nodes.push(BreadcrumbTreeElement::Borrowed(val.from_context_element())) + } + }); + }); injected_context.map(|ctx| new_nodes.push(BreadcrumbTreeElement::Borrowed(ctx))); new_context_element .map(|ctx| new_nodes.push(BreadcrumbTreeElement::Borrowed(ctx.from_context_element())));