duster/src/renderer/parameters_context.rs

151 lines
4.6 KiB
Rust
Raw Normal View History

use crate::parser::KVPair;
2020-05-09 02:34:58 +00:00
use crate::parser::{Filter, RValue};
use crate::renderer::context_element::ContextElement;
2020-05-09 18:53:53 +00:00
use crate::renderer::walking::walk_path;
2020-05-09 02:34:58 +00:00
use crate::renderer::Loopable;
use crate::renderer::RenderError;
use crate::renderer::Renderable;
2020-05-09 18:10:38 +00:00
use crate::renderer::WalkError;
2020-05-09 02:34:58 +00:00
use crate::renderer::Walkable;
use std::collections::HashMap;
2020-05-10 22:10:17 +00:00
/// Copy the data from an RValue to an Owned struct
///
/// In order to get comparisons to work for our `ContextElement` trait
/// objects, we need to be able to use `std::any::Any`. Unfortunately,
/// `Any` requires that the structs do not have a lifetime (so they
/// will have a `'static` lifetime. This means that we cannot have a
/// `<'a>` appended to the struct type, so the struct cannot contain
/// any borrows. Rather than impose the copy cost in the parser, we
/// are imposing the cost of copying the data in the renderer because
/// the parser has no reason to not be able to reference data from the
/// input string.
pub enum OwnedRValue {
RVPath(OwnedPath),
RVString(String),
}
pub struct OwnedPath {
pub keys: Vec<String>,
}
2020-05-10 22:19:06 +00:00
impl From<&RValue<'_>> for OwnedRValue {
fn from(original: &RValue<'_>) -> Self {
2020-05-10 22:10:17 +00:00
match original {
RValue::RVString(text) => OwnedRValue::RVString(text.to_owned()),
RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath {
keys: path.keys.iter().map(|k| k.to_string()).collect(),
}),
}
}
}
pub struct NewParametersContext {
params: HashMap<String, OwnedRValue>,
2020-05-10 22:19:06 +00:00
breadcrumbs: Vec<Box<dyn ContextElement>>,
}
impl NewParametersContext {
pub fn new(
breadcrumbs: &Vec<&dyn ContextElement>,
params: &Vec<KVPair>,
) -> NewParametersContext {
let owned_params: HashMap<String, OwnedRValue> = params
.iter()
.map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value)))
.collect();
2020-05-10 22:35:24 +00:00
let x: String = "foo".to_owned();
let y: &dyn ContextElement = &x as _;
2020-05-10 22:45:54 +00:00
// let owned_y: Box<dyn ContextElement> = Box::new(*y.clone());
// unsafe {
// let ce = &mut *y.clone() as *mut dyn ContextElement;
// Box::from_raw(ce);
// }
2020-05-10 22:35:24 +00:00
// let owned_breadcrumbs: Vec<Box<dyn ContextElement>> =
// breadcrumbs.iter().map(|ce| Box::new(*ce.clone())).collect();
2020-05-10 22:19:06 +00:00
NewParametersContext {
params: owned_params,
breadcrumbs: Vec::new(),
}
}
2020-05-10 22:10:17 +00:00
}
#[derive(Clone, Debug)]
pub struct ParametersContext<'a> {
params: HashMap<&'a str, &'a RValue<'a>>,
breadcrumbs: &'a Vec<&'a dyn ContextElement>,
}
impl<'a> ParametersContext<'a> {
pub fn new(
breadcrumbs: &'a Vec<&'a dyn ContextElement>,
params: &'a Vec<KVPair<'a>>,
) -> ParametersContext<'a> {
let param_map = params
.iter()
.map(|pair: &KVPair<'a>| (pair.key, &pair.value))
.collect();
ParametersContext {
params: param_map,
breadcrumbs: breadcrumbs,
}
}
}
2020-05-09 02:34:58 +00:00
impl<'a> ContextElement for ParametersContext<'a> {}
impl<'a> Renderable for ParametersContext<'a> {
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
2020-05-09 18:53:53 +00:00
// TODO: Would this even ever be called? Won't matter, but I'd
// like to know. Since it is injected 1 above the current
// context, we wouldn't be able to access it with `{.}`.
2020-05-09 02:34:58 +00:00
Ok("[object Object]".to_owned())
}
}
impl<'a> Loopable for ParametersContext<'a> {
2020-05-09 18:18:45 +00:00
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
2020-05-09 18:53:53 +00:00
// TODO: Would this even ever be called? Won't matter, but I'd
// like to know. Since it is injected 1 above the current
// context, we wouldn't be able to access it with `{.}`.
2020-05-09 18:18:45 +00:00
vec![self]
2020-05-09 02:34:58 +00:00
}
}
impl<'a> Walkable for ParametersContext<'a> {
2020-05-09 18:10:38 +00:00
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
2020-05-09 18:53:53 +00:00
let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?;
match rval {
RValue::RVPath(path) => walk_path(self.breadcrumbs, &path.keys),
RValue::RVString(text) => Ok(text),
}
}
}
impl ContextElement for String {}
impl Renderable for String {
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
Ok(self.clone())
}
}
impl Loopable for String {
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
if self.is_empty() {
Vec::new()
} else {
vec![self]
}
}
}
impl Walkable for String {
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
2020-05-09 18:10:38 +00:00
Err(WalkError::CantWalk)
2020-05-09 02:34:58 +00:00
}
}