1use std::rc::Rc;
12
13use bstr::BString;
14use thiserror::Error;
15
16use crate::types;
17use crate::types::{Array, TypeValue};
18
19pub struct Variable(TypeValue);
24
25#[derive(Error, Debug, Eq, PartialEq)]
27pub enum VariableError {
28 #[error("variable `{0}` not defined")]
32 Undefined(String),
33
34 #[error("variable `{0}` already exists")]
36 AlreadyExists(String),
37
38 #[error("invalid variable identifier `{0}`")]
41 InvalidIdentifier(String),
42
43 #[error("null values are not accepted")]
46 UnexpectedNull,
47
48 #[error("arrays can't be empty and all items must be non-null and the same type")]
51 InvalidArray,
52
53 #[error("integer value is out of range")]
55 IntegerOutOfRange,
56
57 #[error(
61 "invalid type for `{variable}`, expecting `{expected_type}`, got `{actual_type}"
62 )]
63 InvalidType {
64 variable: String,
66 expected_type: String,
68 actual_type: String,
70 },
71}
72
73impl TryFrom<bool> for Variable {
74 type Error = VariableError;
75 fn try_from(value: bool) -> Result<Self, Self::Error> {
76 Ok(Variable(TypeValue::var_bool_from(value)))
77 }
78}
79
80impl TryFrom<i64> for Variable {
81 type Error = VariableError;
82 fn try_from(value: i64) -> Result<Self, Self::Error> {
83 Ok(Variable(TypeValue::var_integer_from(value)))
84 }
85}
86
87impl TryFrom<i32> for Variable {
88 type Error = VariableError;
89 fn try_from(value: i32) -> Result<Self, Self::Error> {
90 Ok(Variable(TypeValue::var_integer_from(value)))
91 }
92}
93
94impl TryFrom<i16> for Variable {
95 type Error = VariableError;
96 fn try_from(value: i16) -> Result<Self, Self::Error> {
97 Ok(Variable(TypeValue::var_integer_from(value)))
98 }
99}
100
101impl TryFrom<i8> for Variable {
102 type Error = VariableError;
103 fn try_from(value: i8) -> Result<Self, Self::Error> {
104 Ok(Variable(TypeValue::var_integer_from(value)))
105 }
106}
107
108impl TryFrom<u32> for Variable {
109 type Error = VariableError;
110 fn try_from(value: u32) -> Result<Self, Self::Error> {
111 Ok(Variable(TypeValue::var_integer_from(value)))
112 }
113}
114
115impl TryFrom<u16> for Variable {
116 type Error = VariableError;
117 fn try_from(value: u16) -> Result<Self, Self::Error> {
118 Ok(Variable(TypeValue::var_integer_from(value)))
119 }
120}
121
122impl TryFrom<u8> for Variable {
123 type Error = VariableError;
124 fn try_from(value: u8) -> Result<Self, Self::Error> {
125 Ok(Variable(TypeValue::var_integer_from(value)))
126 }
127}
128
129impl TryFrom<f64> for Variable {
130 type Error = VariableError;
131 fn try_from(value: f64) -> Result<Self, Self::Error> {
132 Ok(Variable(TypeValue::var_float_from(value)))
133 }
134}
135
136impl TryFrom<f32> for Variable {
137 type Error = VariableError;
138 fn try_from(value: f32) -> Result<Self, Self::Error> {
139 Ok(Variable(TypeValue::var_float_from(value)))
140 }
141}
142
143impl TryFrom<&str> for Variable {
144 type Error = VariableError;
145 fn try_from(value: &str) -> Result<Self, Self::Error> {
146 Ok(Variable(TypeValue::var_string_from(value)))
147 }
148}
149
150impl TryFrom<&[u8]> for Variable {
151 type Error = VariableError;
152 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
153 Ok(Variable(TypeValue::var_string_from(value)))
154 }
155}
156
157impl TryFrom<String> for Variable {
158 type Error = VariableError;
159 fn try_from(value: String) -> Result<Self, Self::Error> {
160 Ok(Variable(TypeValue::var_string_from(value)))
161 }
162}
163
164impl TryFrom<serde_json::Value> for Variable {
165 type Error = VariableError;
166 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
167 Variable::try_from(&value)
168 }
169}
170
171impl TryFrom<&serde_json::Value> for Variable {
172 type Error = VariableError;
173 fn try_from(value: &serde_json::Value) -> Result<Self, Self::Error> {
174 match value {
175 serde_json::Value::Null => Err(VariableError::UnexpectedNull),
176 serde_json::Value::Bool(b) => {
177 Ok(Variable(TypeValue::var_bool_from(*b)))
178 }
179 serde_json::Value::Number(n) => {
180 if let Some(n) = n.as_u64() {
181 let n: i64 = n
182 .try_into()
183 .map_err(|_| VariableError::IntegerOutOfRange)?;
184 Ok(Variable(TypeValue::var_integer_from(n)))
185 } else if let Some(n) = n.as_i64() {
186 Ok(Variable(TypeValue::var_integer_from(n)))
187 } else if let Some(n) = n.as_f64() {
188 Ok(Variable(TypeValue::var_float_from(n)))
189 } else {
190 unreachable!()
191 }
192 }
193 serde_json::Value::String(s) => {
194 Ok(Variable(TypeValue::var_string_from(s)))
195 }
196 serde_json::Value::Array(values) => {
197 let mut array = None;
198 for v in values {
201 if v.is_boolean() {
202 array = Some(Array::Bools(Vec::new()));
203 break;
204 } else if v.is_i64() {
205 array = Some(Array::Integers(Vec::new()));
206 break;
207 } else if v.is_f64() {
208 array = Some(Array::Floats(Vec::new()));
209 break;
210 } else if v.is_string() {
211 array = Some(Array::Strings(Vec::new()));
212 break;
213 } else if v.is_object() {
214 array = Some(Array::Structs(Vec::new()));
215 break;
216 } else if v.is_array() {
217 return Err(VariableError::InvalidArray);
219 }
220 }
221
222 if array.is_none() {
225 return Err(VariableError::InvalidArray);
226 }
227
228 let mut array = array.unwrap();
229
230 match array {
231 Array::Integers(ref mut integers) => {
232 for v in values {
233 match v.as_i64() {
234 Some(v) => {
235 integers.push(v);
236 }
237 None => {
238 return Err(VariableError::InvalidArray);
239 }
240 };
241 }
242 }
243 Array::Floats(ref mut floats) => {
244 for v in values {
245 match v.as_f64() {
246 Some(v) => {
247 floats.push(v);
248 }
249 None => {
250 return Err(VariableError::InvalidArray);
251 }
252 };
253 }
254 }
255 Array::Bools(ref mut bools) => {
256 for v in values {
257 match v.as_bool() {
258 Some(v) => {
259 bools.push(v);
260 }
261 None => {
262 return Err(VariableError::InvalidArray);
263 }
264 };
265 }
266 }
267 Array::Strings(ref mut strings) => {
268 for v in values {
269 match v.as_str() {
270 Some(v) => {
271 strings.push(BString::from(v).into());
272 }
273 None => {
274 return Err(VariableError::InvalidArray);
275 }
276 };
277 }
278 }
279 Array::Structs(ref mut structs) => {
280 for v in values {
281 match v.as_object() {
282 Some(v) => {
283 let mut s = types::Struct::new();
284 for (key, value) in v {
285 s.add_field(
286 key,
287 TypeValue::from(
288 Variable::try_from(value)?,
289 ),
290 );
291 }
292 structs.push(Rc::new(s));
293 }
294 None => {
295 return Err(VariableError::InvalidArray);
296 }
297 };
298 }
299 }
300 }
301 Ok(Variable(TypeValue::Array(Rc::new(array))))
302 }
303 serde_json::Value::Object(obj) => {
304 let mut s = types::Struct::new();
305 for (key, value) in obj {
306 s.add_field(
307 key,
308 TypeValue::from(Variable::try_from(value)?),
309 );
310 }
311 Ok(Variable(TypeValue::Struct(Rc::new(s))))
312 }
313 }
314 }
315}
316
317impl From<Variable> for TypeValue {
318 fn from(value: Variable) -> Self {
319 value.0
320 }
321}
322
323pub(crate) fn is_valid_identifier(ident: &str) -> bool {
328 let mut chars = ident.chars();
329
330 if let Some(first) = chars.next() {
331 if !first.is_alphabetic() && first != '_' {
333 return false;
334 }
335 } else {
336 return false;
338 }
339
340 chars.all(|c| c.is_alphanumeric() || c == '_')
342}
343
344#[cfg(test)]
345mod test {
346 #[test]
347 fn is_valid_identifier() {
348 assert!(super::is_valid_identifier("a"));
350 assert!(super::is_valid_identifier("_"));
351 assert!(super::is_valid_identifier("foo"));
352 assert!(super::is_valid_identifier("_foo"));
353
354 assert!(!super::is_valid_identifier("123"));
356 assert!(!super::is_valid_identifier("1foo"));
357 assert!(!super::is_valid_identifier("foo|"));
358 assert!(!super::is_valid_identifier("foo.bar"));
359 }
360}