Use StructObject For Dynamic Variables In Rust's MiniJinja
Code
use crate::page::Page;
use minijinja::value::{StructObject, Value};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "lowercase")]
pub struct Universe {
pub pages: Vec<Page>,
}
impl Universe {
pub fn home_page_links(&self) -> Vec<(String, String)> {
vec![("a".to_string(), "b".to_string())]
}
}
impl StructObject for Universe {
fn get_field(&self, field: &str) -> Option<Value> {
match field {
"home_page_links" => Some(Value::from_serializable(&self.clone().home_page_links())),
_ => None,
}
}
}
Code
use minijinja::value::{StructObject, Value};
use minijinja::{context, Environment};
use serde::{Deserialize, Serialize};
pub struct Widget;
pub struct Thing;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum Payload {
Tango { value: String },
}
impl Widget {
fn alfa_signal(&self) -> String {
"This is alfa in widget".to_string()
}
}
impl StructObject for Widget {
fn get_field(&self, field: &str) -> Option<Value> {
match field {
"alfa" => Some(Value::from(self.alfa_signal())),
_ => None,
}
}
}
impl Thing {
fn bravo_signal(&self) -> String {
"This is bravo in thing".to_string()
}
}
impl StructObject for Thing {
fn get_field(&self, field: &str) -> Option<Value> {
match field {
"bravo" => Some(Value::from(self.bravo_signal())),
_ => None,
}
}
}
fn main() {
let widget = Widget;
let thing = Thing;
let p = Payload::Tango {
value: "charlie".to_string(),
};
let env = Environment::new();
let tmpl = env
.template_from_str("{{ p.type}};{{ p.value }} - {{ w.alfa }} - {{ t.bravo }}")
.unwrap();
let w = Value::from_struct_object(widget);
let t = Value::from_struct_object(thing);
let output = tmpl.render(context!(w => w, t => t, p=> p)).unwrap();
dbg!(output);
}
Notes
-
needs `cargo add minijinja serde``
-
needs `derive`` added to `serde`` in _Cargo.toml__ like:
``` serde = {version = "1.0.177", features = ["derive"] } ```
-
If you try to just print the main object out in the template (e.g. with `{{ whatever }}`` and don't call a function on it nothing will show up. Makes sense, but it threw me the first couple of times
Reference
This is the key to being able to use functions from object inside templates