sato/
context.rs

1use std::collections::{HashMap, BTreeMap};
2use crate::renderer::RenderValue;
3use crate::template::Template;
4
5
6#[derive(Clone, Debug)]
7pub enum ContextValue {
8    Integer(i64),
9    Boolean(bool),
10    String(String),
11    Vec(Vec<ContextValue>),
12    Object(RenderContext),
13    Template(Template),
14}
15
16impl From<&str> for ContextValue {
17    fn from(other: &str) -> Self {
18        ContextValue::String(other.into())
19    }
20}
21
22impl From<String> for ContextValue {
23    fn from(other: String) -> Self {
24        ContextValue::String(other)
25    }
26}
27
28impl From<&String> for ContextValue {
29    fn from(other: &String) -> Self {
30        ContextValue::String(other.clone())
31    }
32}
33
34impl<T: Into<ContextValue>> From<Vec<T>> for ContextValue {
35    fn from(other: Vec<T>) -> Self {
36        ContextValue::Vec(other.into_iter().map(|k| k.into()).collect())
37    }
38}
39
40impl From<RenderContext> for ContextValue {
41    fn from(other: RenderContext) -> Self {
42        ContextValue::Object(other)
43    }
44}
45
46impl From<BTreeMap<String, ContextValue>> for ContextValue {
47    fn from(other: BTreeMap<String, ContextValue>) -> Self {
48        ContextValue::Object(RenderContext(other))
49    }
50}
51
52impl From<HashMap<String, ContextValue>> for ContextValue {
53    fn from(other: HashMap<String, ContextValue>) -> Self {
54        ContextValue::Object(RenderContext(other.into_iter().collect()))
55    }
56}
57
58impl From<Template> for ContextValue {
59    fn from(other: Template) -> Self {
60        ContextValue::Template(other)
61    }
62}
63
64impl From<bool> for ContextValue {
65    fn from(other: bool) -> Self {
66        ContextValue::Boolean(other)
67    }
68}
69
70// TODO: somehow make this generic over all numbers
71impl From<usize> for ContextValue {
72    fn from(other: usize) -> Self {
73        ContextValue::Integer(other as i64)
74    }
75}
76
77impl From<i32> for ContextValue {
78    fn from(other: i32) -> Self {
79        ContextValue::Integer(other as i64)
80    }
81}
82
83impl From<i64> for ContextValue {
84    fn from(other: i64) -> Self {
85        ContextValue::Integer(other)
86    }
87}
88
89impl From<u32> for ContextValue {
90    fn from(other: u32) -> Self {
91        ContextValue::Integer(other as i64)
92    }
93}
94
95impl PartialEq for ContextValue {
96    fn eq(&self, other: &ContextValue) -> bool {
97        match (self, other) {
98            (ContextValue::Integer(a), ContextValue::Integer(b)) => a == b,
99            (ContextValue::Boolean(a), ContextValue::Boolean(b)) => a == b,
100            (ContextValue::String(a), ContextValue::String(b)) => a == b,
101            (ContextValue::Vec(a), ContextValue::Vec(b)) => a == b,
102            _ => false,
103        }
104    }
105}
106
107impl PartialOrd for ContextValue {
108    fn partial_cmp(&self, other: &ContextValue) -> Option<std::cmp::Ordering> {
109        match (self, other) {
110            (ContextValue::Integer(a), ContextValue::Integer(b)) => a.partial_cmp(b),
111            (ContextValue::Boolean(a), ContextValue::Boolean(b)) => a.partial_cmp(b),
112            (ContextValue::String(a), ContextValue::String(b)) => a.partial_cmp(b),
113            (ContextValue::Vec(a), ContextValue::Vec(b)) => a.partial_cmp(b),
114            _ => None,
115        }
116    }
117}
118
119impl From<&RenderValue> for ContextValue {
120    fn from(other: &RenderValue) -> ContextValue {
121        match other {
122            RenderValue::String(s) => ContextValue::String(s.clone()),
123            RenderValue::Integer(i) => ContextValue::Integer(*i),
124            RenderValue::Boolean(b) => ContextValue::Boolean(*b),
125            RenderValue::Vec(v) => ContextValue::Vec(v.iter().map(|e| e.into()).collect()),
126            RenderValue::Object(o) => ContextValue::Object(RenderContext(o.iter().map(|(k, v)| (k.clone(), v.into())).collect())),
127            RenderValue::Template(t) => ContextValue::Template(t.clone()),
128            RenderValue::Empty => ContextValue::String("".into()),
129        }
130    }
131}
132
133impl From<RenderValue> for ContextValue {
134    fn from(other: RenderValue) -> ContextValue {
135        match other {
136            RenderValue::String(s) => ContextValue::String(s.clone()),
137            RenderValue::Integer(i) => ContextValue::Integer(i),
138            RenderValue::Boolean(b) => ContextValue::Boolean(b),
139            RenderValue::Vec(v) => ContextValue::Vec(v.iter().map(|e| e.into()).collect()),
140            RenderValue::Object(o) => ContextValue::Object(RenderContext(o.iter().map(|(k, v)| (k.clone(), v.into())).collect())),
141            RenderValue::Template(t) => ContextValue::Template(t),
142            RenderValue::Empty => ContextValue::String("".into()),
143        }
144    }
145}
146
147
148#[derive(Default, Clone, Debug)]
149pub struct RenderContext(pub(crate) BTreeMap<String, ContextValue>);
150
151
152impl RenderContext {
153    pub fn builder() -> RenderContextBuilder {
154        RenderContextBuilder::default()
155    }
156    
157    pub fn insert<K, V>(&mut self, key: K, value: V)
158    where
159        K: std::convert::Into<String>,
160        V: std::convert::Into<ContextValue>,
161    {
162        self.0.insert(key.into().trim_start_matches('$').into(), value.into());
163    }
164
165    pub fn get<K>(&self, key: K) -> Option<&ContextValue>
166    where
167        K: std::convert::Into<String>,
168    {
169        self.0.get(key.into().trim_start_matches('$'))
170    }
171}
172
173
174#[derive(Default, Clone)]
175pub struct RenderContextBuilder(pub(crate) BTreeMap<String, ContextValue>);
176
177impl RenderContextBuilder {
178    pub fn insert<K, V>(mut self, key: K, value: V) -> Self
179    where
180        K: std::convert::Into<String>,
181        V: std::convert::Into<ContextValue>,
182    {
183        self.0.insert(key.into(), value.into());
184        self
185    }
186
187    pub fn build(self) -> RenderContext {
188        RenderContext(self.0)
189    }
190}