home ~ projects ~ socials

Use StructObject For Dynamic Variables In Rust's MiniJinja

use crate::page::Page;
use minijinja::value::{StructObject, Value};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(content = "content", rename_all = "lowercase", tag = "type")]
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,
        }
    }
}
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(content = "content", rename_all = "lowercase", tag = "type")]
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"] }

Notes

  • 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
  • The old notes had #[serde(content = "content", rename_all = "lowercase", tag = "type")] but I think that causes a problem with enums with a single value (i.e. not struct enums, but I forget what the other ones are called)

TODO

    Combine these two examples with .from and .from_seriliazble

    Combine with 2vauitbb

    Show regular object which allows method calls and is the way to go with neopoligin

-- end of line --

References