1use alloc::string::String;
4
5use crate::{compat::HashMap, value::Value};
6
7#[derive(Debug, Clone, Default)]
25pub struct Context {
26 pub(crate) values: HashMap<String, Value>,
27}
28
29impl Context {
30 #[must_use]
32 pub fn new() -> Self {
33 Self::default()
34 }
35
36 #[must_use]
38 pub fn with_capacity(capacity: usize) -> Self {
39 Self {
40 values: HashMap::with_capacity(capacity),
41 }
42 }
43
44 #[must_use]
46 pub fn len(&self) -> usize {
47 self.values.len()
48 }
49
50 #[must_use]
52 pub fn is_empty(&self) -> bool {
53 self.values.is_empty()
54 }
55
56 #[must_use]
58 pub fn contains_key(&self, key: &str) -> bool {
59 self.values.contains_key(key)
60 }
61
62 pub fn set(&mut self, key: impl Into<String>, value: impl Into<Value>) {
73 self.values.insert(key.into(), value.into());
74 }
75
76 #[must_use]
78 pub fn var(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
79 self.set(key, value);
80 self
81 }
82
83 #[must_use]
85 pub fn get(&self, key: &str) -> Option<&Value> {
86 self.values.get(key)
87 }
88
89 #[must_use]
93 pub fn into_inner(self) -> HashMap<String, Value> {
94 self.values
95 }
96}
97
98impl<K: Into<String>, V: Into<Value>> FromIterator<(K, V)> for Context {
100 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
101 let iter = iter.into_iter();
102 let (lower, _) = iter.size_hint();
103 let mut ctx = Self::with_capacity(lower);
104 for (k, v) in iter {
105 ctx.set(k, v);
106 }
107 ctx
108 }
109}
110
111#[cfg(feature = "serde")]
112impl Context {
113 pub fn from_value(val: Value) -> Result<Self, crate::error::TemplateError> {
119 match val {
120 Value::Struct(arc_map) => {
121 let values =
124 alloc::sync::Arc::try_unwrap(arc_map).unwrap_or_else(|arc| (*arc).clone());
125 Ok(Self { values })
126 }
127 other => Err(crate::error::TemplateError::syntax(format!(
128 "expected struct/map, got {}",
129 other.type_name()
130 ))),
131 }
132 }
133
134 pub fn from_serialize<T: serde::Serialize>(
140 value: &T,
141 ) -> Result<Self, crate::error::TemplateError> {
142 let val = crate::serde_support::to_value(value).map_err(|e| {
143 crate::error::TemplateError::syntax(format!("serde conversion failed: {e}"))
144 })?;
145 Self::from_value(val)
146 }
147
148 pub fn from_cbor(data: &[u8]) -> Result<Self, crate::error::TemplateError> {
157 let val: Value = ciborium::from_reader(data).map_err(|e| {
158 crate::error::TemplateError::syntax(format!("cbor deserialization failed: {e}"))
159 })?;
160 Self::from_value(val)
161 }
162}
163
164#[cfg(feature = "std")]
167#[cfg(feature = "serde")]
168impl Context {
169 pub fn from_flexbuffers(data: &[u8]) -> Result<Self, crate::error::TemplateError> {
175 let r = flexbuffers::Reader::get_root(data).map_err(|e| {
176 crate::error::TemplateError::syntax(format!("flexbuffers root error: {e}"))
177 })?;
178 let val: Value = serde::Deserialize::deserialize(r).map_err(|e| {
179 crate::error::TemplateError::syntax(format!("flexbuffers deserialization failed: {e}"))
180 })?;
181 Self::from_value(val)
182 }
183}
184
185#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn new_context_is_empty() {
195 let ctx = Context::new();
196 assert!(ctx.get("anything").is_none());
197 }
198
199 #[test]
200 fn set_and_get_str() {
201 let mut ctx = Context::new();
202 ctx.set("greeting", "hello");
203 assert_eq!(ctx.get("greeting"), Some(&Value::Str("hello".into())));
204 }
205
206 #[test]
207 fn set_and_get_bool() {
208 let mut ctx = Context::new();
209 ctx.set("flag", true);
210 assert_eq!(ctx.get("flag"), Some(&Value::Bool(true)));
211 }
212
213 #[test]
214 fn set_and_get_int() {
215 let mut ctx = Context::new();
216 ctx.set("count", 42_i64);
217 assert_eq!(ctx.get("count"), Some(&Value::Int(42)));
218 }
219
220 #[test]
221 fn overwrite_value() {
222 let mut ctx = Context::new();
223 ctx.set("k", "first");
224 ctx.set("k", "second");
225 assert_eq!(ctx.get("k"), Some(&Value::Str("second".into())));
226 }
227
228 #[test]
229 fn get_missing_returns_none() {
230 let ctx = Context::new();
231 assert_eq!(ctx.get("nonexistent"), None);
232 }
233
234 #[test]
235 fn default_is_same_as_new() {
236 let a = Context::new();
237 let b = Context::default();
238 assert!(a.values.is_empty());
239 assert!(b.values.is_empty());
240 }
241}