use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::Formatter;
#[derive(Clone)]
pub struct TemplateString {
pub string: String,
}
impl TemplateString {
pub fn execute(&self, values: Vec<(&str, &str)>) -> String {
let mut string = self.string.clone();
values
.iter()
.for_each(|(k, v)| string = string.replace(&format!("{{{k}}}"), v));
string
}
}
impl Serialize for TemplateString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.string)
}
}
struct TmplStrVisitor;
impl Visitor<'_> for TmplStrVisitor {
type Value = TemplateString;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("a valid template string")
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
{
Ok(TemplateString { string: v })
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(TemplateString { string: v.into() })
}
}
impl<'de> Deserialize<'de> for TemplateString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(TmplStrVisitor)
}
}
impl From<String> for TemplateString {
fn from(value: String) -> Self {
Self { string: value }
}
}
#[cfg(test)]
mod tests {
use crate::templating::TemplateString;
#[test]
fn deserializes_properly() {
let str = TemplateString {
string: "Hi {name}!".into(),
};
assert_eq!(
serde_json::to_string(&str).unwrap(),
"\"Hi {name}!\"".to_string()
);
}
#[test]
fn serializes_properly() {
let str: TemplateString = serde_json::from_str("\"Hi {name}!\"").unwrap();
assert_eq!(str.string, "Hi {name}!".to_string());
}
#[test]
fn executes_properly() {
let str = TemplateString::from("Hello, {name1} and {name2}!".to_string());
let result = str.execute(vec![("name1", "Alice"), ("name2", "Bob")]);
assert_eq!(result, "Hello, Alice and Bob!".to_string())
}
}