home
NOTE: Under Construction - I'm in the middle of upgrading my site and lots of stuff is kinda broken. Please forgive the mess.

Use A Mutex Value To Save A Cache State In A MiniJinja Struct Object

February 2024
Code
```cargo
[dependencies]
minijinja = "1.0.12"
```

use minijinja::value::{Object, Value};
use minijinja::{context, Environment, Error};
use std::fmt::Display;
use std::sync::Mutex;
use std::collections::BTreeMap;

fn main() {
    let cache = Mutex::new(BTreeMap::new());
    let mut env = Environment::new();
    env.add_template("cache_test", "{{ widget.ping() }} {{ widget.ping() }}")
        .unwrap();
    let tmpl = env.get_template("cache_test").unwrap();
    let widget = Widget { cache };
    println!(
        "{}",
        tmpl.render(context!(widget => Value::from_object(widget)))
            .unwrap()
    );
}

#[derive(Debug)]
pub struct Widget {
    pub cache : Mutex<BTreeMap<String, u8>>,
}

impl Widget {
    pub fn new(cache: Mutex<BTreeMap<String, u8>>) -> Widget {
        Widget { cache }
    }
    pub fn ping(&self) -> u8 {
        let mut cache = self.cache.lock().unwrap();
        match cache.get("counter") {
            Some(value) => *value,
            None => {
                cache.insert("counter".to_string(), 1);
                0
            }
        }
    }
}

impl Object for Widget {
    fn call_method(
        &self,
        _state: &minijinja::State,
        name: &str,
        _args: &[Value],
    ) -> Result<Value, Error> {
        match name {
            "ping" => Ok(Value::from(self.ping())),
            _ => Ok(Value::from("")),
        }
    }
}

impl Display for Widget {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "this is required from minijinja but rarely used")
    }
}
Results
0 1

This is anoter sample to add in that shows how to do two level

Code
    pub fn page_title(&self, id: &str) -> Option<String> {
        let mut cache = self.cache.lock().unwrap();
        let page_titles = cache.get_mut("page_title").unwrap();
        match page_titles.get(id) {
            Some(title) => title.clone(),
            None => {
                let title = match self.pages.get(id) {
                    Some(page) => get_title_section_title(&page.ast),
                    None => None,
                };
                page_titles.insert(id.to_string(), title.clone());
                title
            }
        }
    }

This still needs a write up. Here's the code in the mean time

═══ § ═══