archetect_core/vendor/tera/
context.rs1use std::collections::BTreeMap;
2use std::io::Write;
3
4use serde::ser::Serialize;
5use serde_json::value::{to_value, Map, Value};
6
7use crate::vendor::tera::errors::{Error, Result as TeraResult};
8
9#[derive(Debug, Clone, PartialEq)]
14pub struct Context {
15 data: BTreeMap<String, Value>,
16}
17
18impl Context {
19 pub fn new() -> Self {
21 Context { data: BTreeMap::new() }
22 }
23
24 pub fn insert<T: Serialize + ?Sized, S: Into<String>>(&mut self, key: S, val: &T) {
34 self.data.insert(key.into(), to_value(val).unwrap());
35 }
36
37 pub fn try_insert<T: Serialize + ?Sized, S: Into<String>>(
57 &mut self,
58 key: S,
59 val: &T,
60 ) -> TeraResult<()> {
61 self.data.insert(key.into(), to_value(val)?);
62
63 Ok(())
64 }
65
66 pub fn extend(&mut self, mut source: Context) {
80 self.data.append(&mut source.data);
81 }
82
83 pub fn into_json(self) -> Value {
85 let mut m = Map::new();
86 for (key, value) in self.data {
87 m.insert(key, value);
88 }
89 Value::Object(m)
90 }
91
92 pub fn from_value(obj: Value) -> TeraResult<Self> {
94 match obj {
95 Value::Object(m) => {
96 let mut data = BTreeMap::new();
97 for (key, value) in m {
98 data.insert(key, value);
99 }
100 Ok(Context { data })
101 }
102 _ => Err(Error::msg(
103 "Creating a Context from a Value/Serialize requires it being a JSON object",
104 )),
105 }
106 }
107
108 pub fn from_serialize(value: impl Serialize) -> TeraResult<Self> {
112 let obj = to_value(value).map_err(Error::json)?;
113 Context::from_value(obj)
114 }
115
116 pub fn get(&self, index: &str) -> Option<&Value> {
118 self.data.get(index)
119 }
120
121 pub fn contains_key(&self, index: &str) -> bool {
123 self.data.contains_key(index)
124 }
125}
126
127impl Default for Context {
128 fn default() -> Context {
129 Context::new()
130 }
131}
132
133pub trait ValueRender {
134 fn render(&self, write: &mut impl Write) -> std::io::Result<()>;
135}
136
137impl ValueRender for Value {
139 fn render(&self, write: &mut impl Write) -> std::io::Result<()> {
140 match *self {
141 Value::String(ref s) => write!(write, "{}", s),
142 Value::Number(ref i) => write!(write, "{}", i),
143 Value::Bool(i) => write!(write, "{}", i),
144 Value::Null => Ok(()),
145 Value::Array(ref a) => {
146 let mut first = true;
147 write!(write, "[")?;
148 for i in a.iter() {
149 if !first {
150 write!(write, ", ")?;
151 }
152 first = false;
153 i.render(write)?;
154 }
155 write!(write, "]")?;
156 Ok(())
157 }
158 Value::Object(_) => write!(write, "[object]"),
159 }
160 }
161}
162
163pub trait ValueNumber {
164 fn to_number(&self) -> Result<f64, ()>;
165}
166impl ValueNumber for Value {
169 fn to_number(&self) -> Result<f64, ()> {
170 match *self {
171 Value::Number(ref i) => Ok(i.as_f64().unwrap()),
172 _ => Err(()),
173 }
174 }
175}
176
177pub trait ValueTruthy {
179 fn is_truthy(&self) -> bool;
180}
181
182impl ValueTruthy for Value {
183 fn is_truthy(&self) -> bool {
184 match *self {
185 Value::Number(ref i) => {
186 if i.is_i64() {
187 return i.as_i64().unwrap() != 0;
188 }
189 if i.is_u64() {
190 return i.as_u64().unwrap() != 0;
191 }
192 let f = i.as_f64().unwrap();
193 f != 0.0 && !f.is_nan()
194 }
195 Value::Bool(ref i) => *i,
196 Value::Null => false,
197 Value::String(ref i) => !i.is_empty(),
198 Value::Array(ref i) => !i.is_empty(),
199 Value::Object(ref i) => !i.is_empty(),
200 }
201 }
202}
203
204#[inline]
206pub fn get_json_pointer(key: &str) -> String {
207 lazy_static::lazy_static! {
208 static ref JSON_POINTER_REGEX: regex::Regex = regex::Regex::new("\"[^\"]*\"|[^.]+").unwrap();
211 }
212
213 let mut segments = vec![""];
214 segments.extend(JSON_POINTER_REGEX.find_iter(key).map(|mat| mat.as_str().trim_matches('"')));
215 segments.join("/")
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 use serde_json::json;
223 use std::collections::HashMap;
224
225 #[test]
226 fn can_extend_context() {
227 let mut target = Context::new();
228 target.insert("a", &1);
229 target.insert("b", &2);
230 let mut source = Context::new();
231 source.insert("b", &3);
232 source.insert("c", &4);
233 target.extend(source);
234 assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
235 assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
236 assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
237 }
238
239 #[test]
240 fn can_create_context_from_value() {
241 let obj = json!({
242 "name": "bob",
243 "age": 25
244 });
245 let context_from_value = Context::from_value(obj).unwrap();
246 let mut context = Context::new();
247 context.insert("name", "bob");
248 context.insert("age", &25);
249 assert_eq!(context_from_value, context);
250 }
251
252 #[test]
253 fn can_create_context_from_impl_serialize() {
254 let mut map = HashMap::new();
255 map.insert("name", "bob");
256 map.insert("last_name", "something");
257 let context_from_serialize = Context::from_serialize(&map).unwrap();
258 let mut context = Context::new();
259 context.insert("name", "bob");
260 context.insert("last_name", "something");
261 assert_eq!(context_from_serialize, context);
262 }
263}