json_template/functions/
mod.rs

1//! Functions module.
2
3use std::{collections::HashMap, rc::Rc};
4
5use serde_json::Value;
6
7use crate::{Context, Deserializer, Placeholder, JSON};
8
9
10/// Functions registry.
11#[derive(Clone)]
12pub struct Functions {
13    registry: HashMap<String, Rc<dyn Fn(&Deserializer, &Context, &Placeholder) -> serde_json::Result<Value>>>
14}
15
16/// Transforms everything into a string.
17fn string(deserializer: &Deserializer, context: &Context, placeholder: &Placeholder) -> serde_json::Result<Value> {
18    context.find(deserializer, placeholder).map(|value| Value::String(value.to_string()))
19}
20
21/// Reads a file.
22fn file(deserializer: &Deserializer, context: &Context, placeholder: &Placeholder) -> serde_json::Result<Value> {
23    context
24        .directory()
25        .as_ref()
26        .map(|directory| directory.join(placeholder.path().str()))
27        .ok_or_else(|| serde::de::Error::custom("No directory set."))
28        .and_then(|path| deserializer.deserialize_with_context::<Value>(path, context))
29}
30
31/// Composes a value from multiple placeholders.
32fn compose(deserializer: &Deserializer, context: &Context, placeholder: &Placeholder) -> serde_json::Result<Value> {
33    let path = placeholder.path();
34    let parts = path.str().split(',').collect::<Vec<_>>();
35    let mut value = Value::Object(Default::default());
36    for part in parts {
37        let new_value = deserializer.resolve_string(part, context)?;
38        value.add_recursive(new_value);
39    }
40    Ok(value)
41}
42
43impl Default for Functions {
44    fn default() -> Self {
45        let registry = Default::default();
46        let mut functions = Functions { registry };
47        functions.register("string", string);
48        functions.register("file", file);
49        functions.register("compose", compose);
50        functions
51    }    
52}
53
54impl Functions {
55    /// Create a new functions.
56    pub fn register(&mut self, name: impl AsRef<str>, function: impl Fn(&Deserializer, &Context, &Placeholder) -> serde_json::Result<Value> + 'static) {
57        self.registry.insert(name.as_ref().to_string(), Rc::new(function));
58    }
59
60    /// Get a function.
61    pub fn get(&self, name: impl AsRef<str>) -> Option<Rc<dyn Fn(&Deserializer, &Context, &Placeholder) -> serde_json::Result<Value>>> {
62        self.registry.get(name.as_ref()).cloned()
63    }
64}