use std::collections::HashMap;
use tera::{Error as TeraError, Result as TeraResult, Value as TeraValue};
pub fn register_replicate_function(tera: &mut tera::Tera) {
tera.register_function("replicate", replicate_function);
}
pub fn register_reverse_function(tera: &mut tera::Tera) {
tera.register_function("reverse", reverse_function);
}
pub fn register_take_function(tera: &mut tera::Tera) {
tera.register_function("take", take_function);
}
pub fn register_strlen_function(tera: &mut tera::Tera) {
tera.register_function("strlen", strlen_function);
}
pub fn register_mask_partial_function(tera: &mut tera::Tera) {
tera.register_function("mask_partial", mask_partial_function);
}
pub fn register_all_standard_functions(tera: &mut tera::Tera) {
register_replicate_function(tera);
register_reverse_function(tera);
register_take_function(tera);
register_strlen_function(tera);
register_mask_partial_function(tera);
}
fn replicate_function(args: &HashMap<String, TeraValue>) -> TeraResult<TeraValue> {
let s = args
.get("s")
.and_then(|v| v.as_str())
.ok_or_else(|| TeraError::msg("replicate function requires 's' parameter"))?;
let n = args
.get("n")
.and_then(|v| v.as_i64())
.ok_or_else(|| TeraError::msg("replicate function requires 'n' parameter"))?;
if n < 0 {
return Ok(TeraValue::String("".to_string()));
}
let result = s.repeat(n as usize);
Ok(TeraValue::String(result))
}
fn reverse_function(args: &HashMap<String, TeraValue>) -> TeraResult<TeraValue> {
let input = if let Some(value) = args.get("0") {
value
.as_str()
.ok_or_else(|| TeraError::msg("reverse function argument must be a string"))?
} else if let Some(value) = args.get("s") {
value
.as_str()
.ok_or_else(|| TeraError::msg("reverse function 's' parameter must be a string"))?
} else {
return Err(TeraError::msg(
"reverse function requires a string argument",
));
};
let reversed: String = input.chars().rev().collect();
Ok(TeraValue::String(reversed))
}
fn take_function(args: &HashMap<String, TeraValue>) -> TeraResult<TeraValue> {
let n = if let Some(value) = args.get("0") {
value
.as_i64()
.ok_or_else(|| TeraError::msg("take function first argument must be a number"))?
} else if let Some(value) = args.get("n") {
value
.as_i64()
.ok_or_else(|| TeraError::msg("take function 'n' parameter must be a number"))?
} else {
return Err(TeraError::msg(
"take function requires first argument to be a number",
));
};
let s = if let Some(value) = args.get("1") {
value
.as_str()
.ok_or_else(|| TeraError::msg("take function second argument must be a string"))?
} else if let Some(value) = args.get("s") {
value
.as_str()
.ok_or_else(|| TeraError::msg("take function 's' parameter must be a string"))?
} else {
return Err(TeraError::msg(
"take function requires second argument to be a string",
));
};
if n < 0 {
return Ok(TeraValue::String("".to_string()));
}
let chars: Vec<char> = s.chars().collect();
let taken: String = chars.into_iter().take(n as usize).collect();
Ok(TeraValue::String(taken))
}
fn strlen_function(args: &HashMap<String, TeraValue>) -> TeraResult<TeraValue> {
let input = if let Some(value) = args.get("0") {
value
.as_str()
.ok_or_else(|| TeraError::msg("strlen function argument must be a string"))?
} else if let Some(value) = args.get("s") {
value
.as_str()
.ok_or_else(|| TeraError::msg("strlen function 's' parameter must be a string"))?
} else {
return Err(TeraError::msg("strlen function requires a string argument"));
};
let length = input.chars().count();
Ok(TeraValue::from(length))
}
fn mask_partial_function(args: &HashMap<String, TeraValue>) -> TeraResult<TeraValue> {
let l = args.get("l").and_then(|v| v.as_i64()).unwrap_or(0);
let r = args.get("r").and_then(|v| v.as_i64()).unwrap_or(0);
let c = args.get("c").and_then(|v| v.as_str()).unwrap_or("*");
let s = args
.get("s")
.and_then(|v| v.as_str())
.ok_or_else(|| TeraError::msg("mask_partial function requires 's' parameter"))?;
if l < 0 || r < 0 {
return Err(TeraError::msg(
"mask_partial function requires non-negative l and r parameters",
));
}
let chars: Vec<char> = s.chars().collect();
let total_len = chars.len();
let l_usize = l as usize;
let r_usize = r as usize;
if l_usize + r_usize >= total_len {
return Ok(TeraValue::String(s.to_string()));
}
let middle_len = total_len - l_usize - r_usize;
let left_part: String = chars.iter().take(l_usize).collect();
let right_part: String = chars.iter().skip(total_len - r_usize).collect();
let middle_part = c.repeat(middle_len);
let result = format!("{}{}{}", left_part, middle_part, right_part);
Ok(TeraValue::String(result))
}
#[cfg(test)]
mod tests {
use super::*;
use tera::Tera;
#[test]
fn test_replicate_function_direct() {
let mut args = HashMap::new();
args.insert("s".to_string(), TeraValue::String("*".to_string()));
args.insert("n".to_string(), TeraValue::Number(5.into()));
let result = replicate_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "*****");
let mut args = HashMap::new();
args.insert("s".to_string(), TeraValue::String("**".to_string()));
args.insert("n".to_string(), TeraValue::Number(4.into()));
let result = replicate_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "********");
}
#[test]
fn test_reverse_function_direct() {
let mut args = HashMap::new();
args.insert("s".to_string(), TeraValue::String("hello".to_string()));
let result = reverse_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "olleh");
}
#[test]
fn test_take_function_direct() {
let mut args = HashMap::new();
args.insert("n".to_string(), TeraValue::Number(3.into()));
args.insert("s".to_string(), TeraValue::String("hello".to_string()));
let result = take_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "hel");
}
#[test]
fn test_strlen_function_direct() {
let mut args = HashMap::new();
args.insert("s".to_string(), TeraValue::String("hello".to_string()));
let result = strlen_function(&args).unwrap();
assert_eq!(result.as_i64().unwrap(), 5);
let mut args = HashMap::new();
args.insert("s".to_string(), TeraValue::String("🚀🎉🌟".to_string()));
let result = strlen_function(&args).unwrap();
assert_eq!(result.as_i64().unwrap(), 3);
}
#[test]
fn test_function_registration() {
let mut tera = Tera::default();
register_all_standard_functions(&mut tera);
tera.add_raw_template("test", "{{strlen(s='test')}}")
.unwrap();
let context = tera::Context::new();
let result = tera.render("test", &context).unwrap();
assert_eq!(result, "4");
}
#[test]
fn test_mask_partial_function_direct() {
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(2.into()));
args.insert("r".to_string(), TeraValue::Number(2.into()));
args.insert("s".to_string(), TeraValue::String("abcdefgh".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "ab****gh");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(2.into()));
args.insert("r".to_string(), TeraValue::Number(2.into()));
args.insert("c".to_string(), TeraValue::String("*".to_string()));
args.insert("s".to_string(), TeraValue::String("abcdefgh".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "ab****gh");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(1.into()));
args.insert("r".to_string(), TeraValue::Number(3.into()));
args.insert("c".to_string(), TeraValue::String("*".to_string()));
args.insert(
"s".to_string(),
TeraValue::String("password123".to_string()),
);
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "p*******123");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(3.into()));
args.insert("r".to_string(), TeraValue::Number(3.into()));
args.insert("c".to_string(), TeraValue::String("*".to_string()));
args.insert("s".to_string(), TeraValue::String("hello".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "hello");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(0.into()));
args.insert("r".to_string(), TeraValue::Number(2.into()));
args.insert("c".to_string(), TeraValue::String("*".to_string()));
args.insert("s".to_string(), TeraValue::String("secret".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "****et");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(2.into()));
args.insert("r".to_string(), TeraValue::Number(0.into()));
args.insert("c".to_string(), TeraValue::String("*".to_string()));
args.insert("s".to_string(), TeraValue::String("secret".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "se****");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(1.into()));
args.insert("r".to_string(), TeraValue::Number(1.into()));
args.insert("c".to_string(), TeraValue::String("*".to_string()));
args.insert("s".to_string(), TeraValue::String("🚀🎉🌟🔥⭐".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "🚀***⭐");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(2.into()));
args.insert("r".to_string(), TeraValue::Number(2.into()));
args.insert("c".to_string(), TeraValue::String("#".to_string()));
args.insert("s".to_string(), TeraValue::String("password".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "pa####rd");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(1.into()));
args.insert("r".to_string(), TeraValue::Number(1.into()));
args.insert("c".to_string(), TeraValue::String("-X-".to_string()));
args.insert("s".to_string(), TeraValue::String("test123".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "t-X--X--X--X--X-3");
}
#[test]
fn test_mask_partial_function_defaults() {
let mut args = HashMap::new();
args.insert("s".to_string(), TeraValue::String("test".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "****");
let mut args = HashMap::new();
args.insert("r".to_string(), TeraValue::Number(2.into()));
args.insert("s".to_string(), TeraValue::String("test".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "**st");
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(2.into()));
args.insert("s".to_string(), TeraValue::String("test".to_string()));
let result = mask_partial_function(&args).unwrap();
assert_eq!(result.as_str().unwrap(), "te**");
}
#[test]
fn test_mask_partial_function_errors() {
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(2.into()));
args.insert("r".to_string(), TeraValue::Number(2.into()));
let result = mask_partial_function(&args);
assert!(result.is_err());
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number((-1).into()));
args.insert("r".to_string(), TeraValue::Number(2.into()));
args.insert("s".to_string(), TeraValue::String("test".to_string()));
let result = mask_partial_function(&args);
assert!(result.is_err());
let mut args = HashMap::new();
args.insert("l".to_string(), TeraValue::Number(2.into()));
args.insert("r".to_string(), TeraValue::Number((-1).into()));
args.insert("s".to_string(), TeraValue::String("test".to_string()));
let result = mask_partial_function(&args);
assert!(result.is_err());
}
#[test]
fn test_mask_partial_function_registration() {
let mut tera = Tera::default();
register_mask_partial_function(&mut tera);
tera.add_raw_template("test1", "{{mask_partial(l=2, r=2, s='abcdefgh')}}")
.unwrap();
let context = tera::Context::new();
let result = tera.render("test1", &context).unwrap();
assert_eq!(result, "ab****gh");
tera.add_raw_template("test2", "{{mask_partial(l=2, r=2, c='*', s='abcdefgh')}}")
.unwrap();
let result = tera.render("test2", &context).unwrap();
assert_eq!(result, "ab****gh");
tera.add_raw_template("test3", "{{mask_partial(l=1, r=1, c='#', s='secret')}}")
.unwrap();
let result = tera.render("test3", &context).unwrap();
assert_eq!(result, "s####t");
tera.add_raw_template("test4", "{{mask_partial(s='test')}}")
.unwrap();
let result = tera.render("test4", &context).unwrap();
assert_eq!(result, "****");
tera.add_raw_template("test5", "{{mask_partial(l=2, s='hello')}}")
.unwrap();
let result = tera.render("test5", &context).unwrap();
assert_eq!(result, "he***");
tera.add_raw_template("test6", "{{mask_partial(r=2, s='world')}}")
.unwrap();
let result = tera.render("test6", &context).unwrap();
assert_eq!(result, "***ld");
}
}