1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::fmt;
use itertools;
use liquid_error::{Error, Result};
use liquid_value::Object;
use liquid_value::PathRef;
use liquid_value::ScalarCow;
use liquid_value::Value;
pub trait ValueStore: fmt::Debug {
fn contains_root(&self, name: &str) -> bool;
fn roots(&self) -> Vec<&str>;
fn contains_variable(&self, path: PathRef) -> bool;
fn try_get_variable<'a>(&'a self, path: PathRef) -> Option<&'a Value>;
fn get_variable<'a>(&'a self, path: PathRef) -> Result<&'a Value>;
}
impl ValueStore for Object {
fn contains_root(&self, name: &str) -> bool {
self.contains_key(name)
}
fn roots(&self) -> Vec<&str> {
self.keys().map(|s| s.as_ref()).collect()
}
fn contains_variable(&self, path: PathRef) -> bool {
get_variable_option(self, path).is_some()
}
fn try_get_variable<'a>(&'a self, path: PathRef) -> Option<&'a Value> {
get_variable_option(self, path)
}
fn get_variable<'a>(&'a self, path: PathRef) -> Result<&'a Value> {
if let Some(res) = self.try_get_variable(path) {
return Ok(res);
} else {
for cur_idx in 1..path.len() {
let subpath_end = path.len() - cur_idx;
let subpath = &path[0..subpath_end];
if let Some(parent) = self.try_get_variable(subpath) {
let subpath = itertools::join(subpath.iter().map(ScalarCow::render), ".");
let requested = &path[subpath_end];
let available: Vec<_> = parent.keys().collect();
let available = itertools::join(available.iter().map(ScalarCow::render), ", ");
return Error::with_msg("Unknown index")
.context("variable", subpath)
.context("requested index", format!("{}", requested.render()))
.context("available indexes", available)
.into_err();
}
}
let requested = path
.get(0)
.expect("`Path` guarantees at least one element")
.to_str()
.into_owned();
let available = itertools::join(self.keys(), ", ");
return Error::with_msg("Unknown variable")
.context("requested variable", requested)
.context("available variables", available)
.into_err();
}
}
}
fn get_variable_option<'o>(obj: &'o Object, path: PathRef) -> Option<&'o Value> {
let mut indexes = path.iter();
let key = indexes.next()?;
let key = key.to_str();
let value = obj.get(key.as_ref())?;
indexes.fold(Some(value), |value, index| {
let value = value?;
value.get(index)
})
}