1use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime};
16use core::fmt::{self, Debug, Display};
17use drasi_query_ast::ast::Expression as AstExpression;
18use duration::Duration;
19use float::Float;
20use index::Index;
21use integer::Integer;
22use serde_json::Value;
23use std::{
24 collections::BTreeMap,
25 hash::{Hash, Hasher},
26 sync::Arc,
27};
28use zoned_datetime::ZonedDateTime;
29use zoned_time::ZonedTime;
30
31use crate::models::{Element, ElementMetadata, ElementReference};
32
33#[allow(clippy::derived_hash_with_manual_eq)]
34#[derive(Clone, Hash, Eq, Default)]
35pub enum VariableValue {
36 #[default]
37 Null,
38 Bool(bool),
39 Float(Float),
40 Integer(Integer),
41 String(String),
42 List(Vec<VariableValue>),
43 Object(BTreeMap<String, VariableValue>), Date(NaiveDate), LocalTime(NaiveTime),
47 ZonedTime(ZonedTime),
48 LocalDateTime(NaiveDateTime), ZonedDateTime(ZonedDateTime),
50 Duration(Duration),
51 Expression(AstExpression),
52 ListRange(ListRange),
53 Element(Arc<Element>),
54 ElementMetadata(ElementMetadata),
55 ElementReference(ElementReference),
56 Awaiting,
57}
58
59impl From<VariableValue> for Value {
60 fn from(val: VariableValue) -> Self {
61 match val {
62 VariableValue::Null => Value::Null,
63 VariableValue::Bool(b) => Value::Bool(b),
64 VariableValue::Float(f) => Value::Number(f.into()),
65 VariableValue::Integer(i) => Value::Number(i.into()),
66 VariableValue::String(s) => Value::String(s),
67 VariableValue::List(l) => Value::Array(l.into_iter().map(|x| x.into()).collect()),
68 VariableValue::Object(o) => {
69 Value::Object(o.into_iter().map(|(k, v)| (k, v.into())).collect())
70 }
71 VariableValue::Date(d) => Value::String(d.to_string()),
72 VariableValue::LocalTime(t) => Value::String(t.to_string()),
73 VariableValue::ZonedTime(t) => Value::String(t.to_string()),
74 VariableValue::LocalDateTime(t) => Value::String(t.to_string()),
75 VariableValue::ZonedDateTime(t) => Value::String(t.to_string()),
76 VariableValue::Duration(d) => Value::String(d.to_string()),
77 VariableValue::Expression(e) => Value::String(format!("{e:?}")),
78 VariableValue::ListRange(r) => Value::String(r.to_string()),
79 VariableValue::Element(e) => e.as_ref().into(),
80 VariableValue::ElementMetadata(m) => Value::String(m.to_string()),
81 VariableValue::ElementReference(r) => Value::String(r.to_string()),
82 VariableValue::Awaiting => Value::String("Awaiting".to_string()),
83 }
84 }
85}
86
87#[derive(Clone, Debug, Hash, PartialEq, Eq)]
88pub struct ListRange {
89 pub start: RangeBound,
90 pub end: RangeBound,
91}
92
93impl Display for ListRange {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 write!(f, "{}..{}", self.start, self.end)
96 }
97}
98
99#[derive(Clone, Debug, Hash, PartialEq, Eq)]
100pub enum RangeBound {
101 Index(i64),
102 Unbounded,
103}
104
105impl Display for RangeBound {
106 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107 match self {
108 RangeBound::Index(i) => write!(f, "{i}"),
109 RangeBound::Unbounded => write!(f, "..."),
110 }
111 }
112}
113
114impl VariableValue {
115 pub fn get<I: Index>(&self, index: I) -> Option<&VariableValue> {
116 index.index_into(self)
117 }
118
119 pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut VariableValue> {
120 index.index_into_mut(self)
121 }
122
123 pub fn as_object(&self) -> Option<&BTreeMap<String, VariableValue>> {
124 match self {
125 VariableValue::Object(map) => Some(map),
126 _ => None,
127 }
128 }
129
130 pub fn as_object_mut(&mut self) -> Option<&mut BTreeMap<String, VariableValue>> {
131 match self {
132 VariableValue::Object(map) => Some(map),
133 _ => None,
134 }
135 }
136
137 pub fn is_object(&self) -> bool {
138 self.as_object().is_some()
139 }
140
141 pub fn as_array(&self) -> Option<&Vec<VariableValue>> {
142 match self {
143 VariableValue::List(list) => Some(list),
144 _ => None,
145 }
146 }
147
148 pub fn as_array_mut(&mut self) -> Option<&mut Vec<VariableValue>> {
149 match self {
150 VariableValue::List(list) => Some(list),
151 _ => None,
152 }
153 }
154
155 pub fn is_array(&self) -> bool {
156 self.as_array().is_some()
157 }
158
159 pub fn as_str(&self) -> Option<&str> {
160 match self {
161 VariableValue::String(s) => Some(s),
162 _ => None,
163 }
164 }
165
166 pub fn is_string(&self) -> bool {
167 self.as_str().is_some()
168 }
169
170 pub fn is_number(&self) -> bool {
171 matches!(*self, VariableValue::Integer(_) | VariableValue::Float(_))
172 }
173
174 pub fn is_i64(&self) -> bool {
175 match self {
176 VariableValue::Integer(n) => n.is_i64(),
177 _ => false,
178 }
179 }
180
181 pub fn is_f64(&self) -> bool {
182 match self {
183 VariableValue::Float(n) => n.is_f64(),
184 _ => false,
185 }
186 }
187
188 pub fn is_u64(&self) -> bool {
189 match self {
190 VariableValue::Integer(n) => n.is_u64(),
191 _ => false,
192 }
193 }
194
195 pub fn as_i64(&self) -> Option<i64> {
196 match self {
197 VariableValue::Integer(n) => n.as_i64(),
198 _ => None,
199 }
200 }
201
202 pub fn as_f64(&self) -> Option<f64> {
203 match self {
204 VariableValue::Float(n) => n.as_f64(),
205 VariableValue::Integer(n) => n.as_i64().map(|n| n as f64),
206 _ => None,
207 }
208 }
209
210 pub fn as_u64(&self) -> Option<u64> {
211 match self {
212 VariableValue::Integer(n) => n.as_u64(),
213 _ => None,
214 }
215 }
216
217 pub fn as_bool(&self) -> Option<bool> {
218 match *self {
219 VariableValue::Bool(b) => Some(b),
220 _ => None,
221 }
222 }
223
224 pub fn is_boolean(&self) -> bool {
225 self.as_bool().is_some()
226 }
227
228 pub fn as_null(&self) -> Option<()> {
229 match *self {
230 VariableValue::Null => Some(()),
231 _ => None,
232 }
233 }
234
235 pub fn is_null(&self) -> bool {
236 self.as_null().is_some()
237 }
238
239 pub fn as_date(&self) -> Option<NaiveDate> {
240 match *self {
241 VariableValue::Date(d) => Some(d),
242 _ => None,
243 }
244 }
245
246 pub fn is_date(&self) -> bool {
247 self.as_date().is_some()
248 }
249
250 pub fn as_local_time(&self) -> Option<NaiveTime> {
251 match *self {
252 VariableValue::LocalTime(t) => Some(t),
253 _ => None,
254 }
255 }
256
257 pub fn is_local_time(&self) -> bool {
258 self.as_local_time().is_some()
259 }
260
261 pub fn as_time(&self) -> Option<ZonedTime> {
262 match self {
263 VariableValue::ZonedTime(t) => Some(*t),
264 _ => None,
265 }
266 }
267
268 pub fn is_time(&self) -> bool {
269 self.as_time().is_some()
270 }
271
272 pub fn as_local_date_time(&self) -> Option<NaiveDateTime> {
273 match *self {
274 VariableValue::LocalDateTime(t) => Some(t),
275 _ => None,
276 }
277 }
278
279 pub fn is_local_date_time(&self) -> bool {
280 self.as_local_date_time().is_some()
281 }
282
283 pub fn as_zoned_date_time(&self) -> Option<ZonedDateTime> {
284 match self {
285 VariableValue::ZonedDateTime(t) => Some(t.clone()),
286 _ => None,
287 }
288 }
289
290 pub fn get_date_property(&self, property: String) -> Option<String> {
291 if self.is_date() {
292 match property.as_str() {
293 "year" => Some(match self.as_date() {
294 Some(date) => date.year().to_string(),
295 None => return None,
296 }),
297 "month" => Some(match self.as_date() {
298 Some(date) => date.month().to_string(),
299 None => return None,
300 }),
301 "day" => Some(match self.as_date() {
302 Some(date) => date.day().to_string(),
303 None => return None,
304 }),
305 _ => None,
306 }
307 } else {
308 None
309 }
310 }
311
312 pub fn is_zoned_date_time(&self) -> bool {
313 self.as_zoned_date_time().is_some()
314 }
315
316 pub fn as_duration(&self) -> Option<Duration> {
317 match self {
318 VariableValue::Duration(d) => Some(d.clone()),
319 _ => None,
320 }
321 }
322
323 pub fn is_duration(&self) -> bool {
324 self.as_duration().is_some()
325 }
326
327 pub fn as_expression(&self) -> Option<AstExpression> {
328 match self {
329 VariableValue::Expression(e) => Some(e.clone()),
330 _ => None,
331 }
332 }
333
334 pub fn is_expression(&self) -> bool {
335 self.as_expression().is_some()
336 }
337
338 pub fn as_list_range(&self) -> Option<ListRange> {
339 match self {
340 VariableValue::ListRange(r) => Some(r.clone()),
341 _ => None,
342 }
343 }
344
345 pub fn is_list_range(&self) -> bool {
346 self.as_list_range().is_some()
347 }
348
349 pub fn pointer(&self, pointer: &str) -> Option<&VariableValue> {
350 if pointer.is_empty() {
351 return Some(self);
352 }
353 if !pointer.starts_with('/') {
354 return None;
355 }
356 pointer
357 .split('/')
358 .skip(1)
359 .map(|x| x.replace("~1", "/").replace("~0", "~"))
360 .try_fold(self, |target, token| match target {
361 VariableValue::Object(map) => map.get(&token),
362 VariableValue::List(list) => parse_index(&token).and_then(|x| list.get(x)),
363 _ => None,
364 })
365 }
366
367 pub fn hash_for_groupby<H: Hasher>(&self, state: &mut H) {
368 match self {
369 VariableValue::Element(element) => element.get_reference().hash(state),
370 _ => self.hash(state),
371 }
372 }
373}
374
375fn parse_index(s: &str) -> Option<usize> {
376 if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
377 return None;
378 }
379 s.parse().ok()
380}
381
382impl Debug for VariableValue {
383 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
384 match self {
385 VariableValue::Null => formatter.write_str("Null"),
386 VariableValue::Bool(boolean) => write!(formatter, "Bool({boolean})"),
387 VariableValue::Integer(integer) => write!(formatter, "Integer({integer})"),
388 VariableValue::Float(float) => write!(formatter, "Float({float})"),
389 VariableValue::String(string) => write!(formatter, "String({string:?})"),
390 VariableValue::List(vec) => {
391 let _ = formatter.write_str("List ");
392 Debug::fmt(vec, formatter)
393 }
394 VariableValue::Object(map) => {
395 let _ = formatter.write_str("Object ");
396 Debug::fmt(map, formatter)
397 }
398 VariableValue::Date(date) => write!(formatter, "Date({date})"),
399 VariableValue::LocalTime(time) => write!(formatter, "LocalTime({time})"),
400 VariableValue::ZonedTime(time) => write!(formatter, "Time({time})"),
401 VariableValue::LocalDateTime(time) => write!(formatter, "LocalDateTime({time})"),
402 VariableValue::ZonedDateTime(time) => write!(formatter, "ZonedDateTime({time})"),
403 VariableValue::Duration(duration) => write!(formatter, "Duration({duration})"),
404 VariableValue::Expression(expression) => {
405 write!(formatter, "Expression({expression:?})")
406 }
407 VariableValue::ListRange(range) => write!(formatter, "ListRange({range:?})"),
408 VariableValue::Element(element) => write!(formatter, "Element({element:?})"),
409 VariableValue::ElementMetadata(metadata) => {
410 write!(formatter, "ElementMetadata({metadata:?})")
411 }
412 VariableValue::ElementReference(reference) => {
413 write!(formatter, "ElementReference({reference:?})")
414 }
415 VariableValue::Awaiting => write!(formatter, "Awaiting"),
416 }
417 }
418}
419
420impl Display for VariableValue {
421 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
422 match &self {
423 VariableValue::Null => write!(f, "null"),
424 VariableValue::Bool(b) => write!(f, "{b}"),
425 VariableValue::Integer(i) => write!(f, "{i}"),
426 VariableValue::Float(fl) => write!(f, "{fl}"),
427 VariableValue::String(s) => write!(f, "{s}"),
428 VariableValue::List(l) => {
429 let mut first = true;
430 write!(f, "[")?;
431 for item in l {
432 if first {
433 first = false;
434 } else {
435 write!(f, ", ")?;
436 }
437 write!(f, "{item}")?;
438 }
439 write!(f, "]")
440 }
441 VariableValue::Object(o) => {
442 let mut first = true;
443 write!(f, "{{")?;
444 for (key, value) in o {
445 if first {
446 first = false;
447 } else {
448 write!(f, ", ")?;
449 }
450 write!(f, "{key}: {value}")?;
451 }
452 write!(f, "}}")
453 }
454 VariableValue::Date(d) => write!(f, "{d}"),
455 VariableValue::LocalTime(t) => write!(f, "{t}"),
456 VariableValue::ZonedTime(t) => write!(f, "{t}"),
457 VariableValue::LocalDateTime(t) => write!(f, "{t}"),
458 VariableValue::ZonedDateTime(t) => write!(f, "{t}"),
459 VariableValue::Duration(d) => write!(f, "{d}"),
460 VariableValue::Expression(e) => write!(f, "{e:?}"),
461 VariableValue::ListRange(r) => write!(f, "{r}"),
462 VariableValue::Element(e) => write!(f, "{e:?}"),
463 VariableValue::ElementMetadata(m) => write!(f, "{m}"),
464 VariableValue::ElementReference(r) => write!(f, "{r}"),
465 VariableValue::Awaiting => write!(f, "Awaiting"),
466 }
467 }
468}
469
470pub mod de;
471pub mod duration;
472pub mod float;
473mod from;
474mod index;
475pub mod integer;
476mod partial_eq;
477pub mod ser;
478#[cfg(test)]
479mod tests;
480pub mod zoned_datetime;
481pub mod zoned_time;