handlebars/block.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use std::collections::BTreeMap;
use serde_json::value::Value as Json;
use crate::error::RenderError;
use crate::local_vars::LocalVars;
#[derive(Clone, Debug)]
pub enum BlockParamHolder {
// a reference to certain context value
Path(Vec<String>),
// an actual value holder
Value(Json),
}
impl BlockParamHolder {
pub fn value(v: Json) -> BlockParamHolder {
BlockParamHolder::Value(v)
}
pub fn path(r: Vec<String>) -> BlockParamHolder {
BlockParamHolder::Path(r)
}
}
/// A map holds block parameters. The parameter can be either a value or a reference
#[derive(Clone, Debug, Default)]
pub struct BlockParams<'reg> {
data: BTreeMap<&'reg str, BlockParamHolder>,
}
impl<'reg> BlockParams<'reg> {
/// Create a empty block parameter map.
pub fn new() -> BlockParams<'reg> {
BlockParams::default()
}
/// Add a path reference as the parameter. The `path` is a vector of path
/// segments the relative to current block's base path.
pub fn add_path(&mut self, k: &'reg str, path: Vec<String>) -> Result<(), RenderError> {
self.data.insert(k, BlockParamHolder::path(path));
Ok(())
}
/// Add a value as parameter.
pub fn add_value(&mut self, k: &'reg str, v: Json) -> Result<(), RenderError> {
self.data.insert(k, BlockParamHolder::value(v));
Ok(())
}
/// Get a block parameter by its name.
pub fn get(&self, k: &str) -> Option<&BlockParamHolder> {
self.data.get(k)
}
}
/// A data structure holds contextual data for current block scope.
#[derive(Debug, Clone, Default)]
pub struct BlockContext<'rc> {
/// the `base_path` of current block scope
base_path: Vec<String>,
/// the `base_value` of current block scope, when the block is using a
/// constant or derived value as block base
base_value: Option<Json>,
/// current block context variables
block_params: BlockParams<'rc>,
/// local variables in current context
local_variables: LocalVars,
}
impl<'rc> BlockContext<'rc> {
/// create a new `BlockContext` with default data
pub fn new() -> BlockContext<'rc> {
BlockContext::default()
}
/// set a local variable into current scope
pub fn set_local_var(&mut self, name: &str, value: Json) {
self.local_variables.put(name, value);
}
/// Get mutable access to the local variables
pub fn local_variables_mut(&mut self) -> &mut LocalVars {
&mut self.local_variables
}
/// get a local variable from current scope
pub fn get_local_var(&self, name: &str) -> Option<&Json> {
self.local_variables.get(name)
}
/// borrow a reference to current scope's base path
/// all paths inside this block will be relative to this path
pub fn base_path(&self) -> &Vec<String> {
&self.base_path
}
/// borrow a mutable reference to the base path
pub fn base_path_mut(&mut self) -> &mut Vec<String> {
&mut self.base_path
}
/// borrow the base value
pub fn base_value(&self) -> Option<&Json> {
self.base_value.as_ref()
}
/// set the base value
pub fn set_base_value(&mut self, value: Json) {
self.base_value = Some(value);
}
/// Get a block parameter from this block.
/// Block parameters needed to be supported by the block helper.
/// The typical syntax for block parameter is:
///
/// ```skip
/// {{#myblock param1 as |block_param1|}}
/// ...
/// {{/myblock}}
/// ```
///
pub fn get_block_param(&self, block_param_name: &str) -> Option<&BlockParamHolder> {
self.block_params.get(block_param_name)
}
/// Reassign the block parameters for this block.
pub fn set_block_params(&mut self, block_params: BlockParams<'rc>) {
self.block_params = block_params;
}
/// Set a block parameter into this block.
pub fn set_block_param(&mut self, key: &'rc str, value: BlockParamHolder) {
self.block_params.data.insert(key, value);
}
}