mdbook_plotly/code_handler/
map.rs1use crate::preprocessor::config::MapNamespaceScope;
2use fasteval::EvalNamespace;
3use serde_json::{Map as JsonMap, Value};
4use std::collections::BTreeMap;
5
6pub type Map = JsonMap<String, Value>;
7pub(crate) type Vars = BTreeMap<String, f64>;
8
9pub(crate) fn lookup_path<'a>(map: &'a Map, name: &str) -> Option<&'a Value> {
10 let path = name.strip_prefix("map.").unwrap_or(name);
11 let mut parts = path.split('.');
12 let first = parts.next()?;
13 let mut value = map.get(first)?;
14
15 for part in parts {
16 match value {
17 Value::Object(obj) => value = obj.get(part)?,
18 Value::Array(arr) => {
19 let idx = part.parse::<usize>().ok()?;
20 value = arr.get(idx)?;
21 }
22 _ => return None,
23 }
24 }
25
26 Some(value)
27}
28
29pub(crate) fn map_value<'a>(map: &'a Map, index: &str) -> anyhow::Result<&'a Value> {
30 lookup_path(map, index).ok_or_else(|| anyhow::anyhow!("missing map value `{}`", index))
31}
32
33fn value_to_f64(value: &Value) -> Option<f64> {
34 match value {
35 Value::Number(n) => n.as_f64(),
36 Value::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
37 Value::String(s) => s.parse::<f64>().ok(),
38 _ => None,
39 }
40}
41
42pub(crate) struct MapNamespace<'a> {
43 map: &'a Map,
44 vars: &'a Vars,
45 scope: &'a MapNamespaceScope,
46}
47
48impl<'a> MapNamespace<'a> {
49 pub(crate) fn new(map: &'a Map, vars: &'a Vars, scope: &'a MapNamespaceScope) -> Self {
50 Self { map, vars, scope }
51 }
52
53 fn lookup_map_value(&self, name: &str) -> Option<f64> {
54 match self.scope {
55 MapNamespaceScope::FullMap => lookup_path(self.map, name).and_then(value_to_f64),
56 MapNamespaceScope::ExportsOnly => {
57 let path = if name.starts_with("map.exports.") {
58 name.to_owned()
59 } else {
60 format!("exports.{name}")
61 };
62 lookup_path(self.map, &path).and_then(value_to_f64)
63 }
64 }
65 }
66}
67
68impl EvalNamespace for MapNamespace<'_> {
69 fn lookup(&mut self, name: &str, _args: Vec<f64>, _keybuf: &mut String) -> Option<f64> {
70 self.vars
71 .get(name)
72 .copied()
73 .or_else(|| self.lookup_map_value(name))
74 }
75}