1use std::fmt::{Debug, Formatter};
2
3use chrono::NaiveDate;
4use serde::{Deserialize, Serialize};
5
6use crate::ast::AstNode;
7use derive_more::TryInto;
8
9macro_rules! impl_getters {
10 ($type:ty, [$($name:ident),+], [$($out:ty),+]) => {
11 $(impl $type {
12 pub fn $name(&self) -> $out {
13 self.$name
14 }
15 })*
16 }
17}
18
19#[derive(Clone, PartialEq, TryInto, Serialize, Deserialize)]
20#[serde(bound(deserialize = "'de: 'static"))]
21#[try_into(ref)]
22pub enum AstLiteral {
23 Null,
25 Integer(i128),
27 Date(Date),
29 DateAndTime(DateAndTime),
31 TimeOfDay(TimeOfDay),
33 Time(Time),
35 Real(String),
37 Bool(bool),
39 String(StringValue),
41 Array(Array),
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46pub struct Date {
47 year: i32,
48 month: u32,
49 day: u32,
50 is_long: bool,
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
54pub struct DateAndTime {
55 year: i32,
56 month: u32,
57 day: u32,
58 hour: u32,
59 min: u32,
60 sec: u32,
61 nano: u32,
62 is_long: bool,
63}
64
65#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
66pub struct TimeOfDay {
67 hour: u32,
68 min: u32,
69 sec: u32,
70 nano: u32,
71 is_long: bool,
72}
73
74#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
75pub struct Time {
76 pub day: f64,
77 pub hour: f64,
78 pub min: f64,
79 pub sec: f64,
80 pub milli: f64,
81 pub micro: f64,
82 pub nano: u32,
83 pub negative: bool,
84 pub is_long: bool,
85}
86
87#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
88pub struct StringValue {
89 pub value: String,
90 pub is_wide: bool,
91}
92
93#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
94#[serde(bound(deserialize = "'de: 'static"))]
95pub struct Array {
96 pub elements: Option<Box<AstNode>>, }
98
99fn calculate_date_time(
102 year: i32,
103 month: u32,
104 day: u32,
105 hour: u32,
106 min: u32,
107 sec: u32,
108 nano: u32,
109) -> Result<i64, String> {
110 NaiveDate::from_ymd_opt(year, month, day)
111 .and_then(|date| date.and_hms_nano_opt(hour, min, sec, nano))
112 .ok_or_else(|| format!("Invalid Date {year}-{month}-{day}-{hour}:{min}:{sec}.{nano}"))
113 .and_then(|date_time| {
114 date_time
115 .and_utc()
116 .timestamp_nanos_opt()
117 .ok_or_else(|| format!("Out of range Date {year}-{month}-{day}-{hour}:{min}:{sec}.{nano}"))
118 })
119}
120
121impl DateAndTime {
122 pub fn value(&self) -> Result<i64, String> {
124 calculate_date_time(self.year, self.month, self.day, self.hour, self.min, self.sec, self.nano)
125 }
126}
127
128impl Time {
129 pub fn value(&self) -> i64 {
131 let dhm_seconds = {
132 let hours = self.day * 24_f64 + self.hour;
133 let mins = hours * 60_f64 + self.min;
134 mins * 60_f64 + self.sec
135 };
136 let millis = dhm_seconds * 1000_f64 + self.milli;
137 let micro = millis * 1000_f64 + self.micro;
138 let nano = micro * 1000_f64 + self.nano as f64;
139 let nanos = nano.round() as i64;
141
142 if self.negative {
143 -nanos
144 } else {
145 nanos
146 }
147 }
148}
149
150impl TimeOfDay {
151 pub fn value(&self) -> Result<i64, String> {
153 calculate_date_time(1970, 1, 1, self.hour, self.min, self.sec, self.nano)
154 }
155}
156
157impl Date {
158 pub fn value(&self) -> Result<i64, String> {
161 calculate_date_time(self.year, self.month, self.day, 0, 0, 0, 0)
162 }
163}
164
165impl_getters! { Date, [year, month, day], [i32, u32, u32] }
166impl_getters! { DateAndTime, [year, month, day, hour, min, sec, nano], [i32, u32, u32, u32, u32, u32, u32]}
167impl_getters! { TimeOfDay, [hour, min, sec, nano], [u32, u32, u32, u32]}
168impl_getters! { Time, [day, hour, min, sec, milli, micro, nano], [f64, f64, f64, f64, f64, f64, u32]}
169
170impl StringValue {
171 pub fn is_wide(&self) -> bool {
172 self.is_wide
173 }
174
175 pub fn value(&self) -> &str {
176 self.value.as_str()
177 }
178}
179
180impl Time {
181 pub fn is_negative(&self) -> bool {
182 self.negative
183 }
184
185 pub fn is_long(&self) -> bool {
186 self.is_long
187 }
188}
189
190impl Date {
191 pub fn is_long(&self) -> bool {
192 self.is_long
193 }
194}
195
196impl DateAndTime {
197 pub fn is_long(&self) -> bool {
198 self.is_long
199 }
200}
201
202impl TimeOfDay {
203 pub fn is_long(&self) -> bool {
204 self.is_long
205 }
206}
207
208impl Array {
209 pub fn elements(&self) -> Option<&AstNode> {
210 self.elements.as_ref().map(|it| it.as_ref())
211 }
212}
213
214impl AstLiteral {
215 pub fn new_array(elements: Option<Box<AstNode>>) -> Self {
217 AstLiteral::Array(Array { elements })
218 }
219 pub fn new_integer(value: i128) -> Self {
221 AstLiteral::Integer(value)
222 }
223 pub fn new_real(value: String) -> Self {
225 AstLiteral::Real(value)
226 }
227 pub fn new_bool(value: bool) -> Self {
229 AstLiteral::Bool(value)
230 }
231 pub fn new_string(value: String, is_wide: bool) -> Self {
233 AstLiteral::String(StringValue { value, is_wide })
234 }
235
236 pub fn new_date(year: i32, month: u32, day: u32) -> Self {
238 AstLiteral::Date(Date { year, month, day, is_long: false })
239 }
240
241 pub fn new_date_with_long_flag(year: i32, month: u32, day: u32, is_long: bool) -> Self {
243 AstLiteral::Date(Date { year, month, day, is_long })
244 }
245
246 pub fn new_date_and_time(
248 year: i32,
249 month: u32,
250 day: u32,
251 hour: u32,
252 min: u32,
253 sec: u32,
254 nano: u32,
255 ) -> Self {
256 AstLiteral::DateAndTime(DateAndTime { year, month, day, hour, min, sec, nano, is_long: false })
257 }
258
259 pub fn new_long_date_and_time(
261 year: i32,
262 month: u32,
263 day: u32,
264 hour: u32,
265 min: u32,
266 sec: u32,
267 nano: u32,
268 ) -> Self {
269 AstLiteral::DateAndTime(DateAndTime { year, month, day, hour, min, sec, nano, is_long: true })
270 }
271
272 pub fn new_time_of_day(hour: u32, min: u32, sec: u32, nano: u32) -> Self {
274 AstLiteral::TimeOfDay(TimeOfDay { hour, min, sec, nano, is_long: false })
275 }
276
277 pub fn new_time_of_day_with_long_flag(hour: u32, min: u32, sec: u32, nano: u32, is_long: bool) -> Self {
279 AstLiteral::TimeOfDay(TimeOfDay { hour, min, sec, nano, is_long })
280 }
281
282 pub fn new_null() -> Self {
284 AstLiteral::Null
285 }
286
287 pub fn get_literal_value(&self) -> String {
288 match self {
289 AstLiteral::String(StringValue { value, is_wide: true, .. }) => format!(r#""{value}""#),
290 AstLiteral::String(StringValue { value, is_wide: false, .. }) => format!(r#"'{value}'"#),
291 AstLiteral::Bool(value) => {
292 format!("{value}")
293 }
294 AstLiteral::Integer(value) => {
295 format!("{value}")
296 }
297 AstLiteral::Real(value) => value.clone(),
298 _ => format!("{self:#?}"),
299 }
300 }
301
302 pub fn is_cast_prefix_eligible(&self) -> bool {
303 matches!(
305 self,
306 AstLiteral::Bool { .. }
307 | AstLiteral::Integer { .. }
308 | AstLiteral::Real { .. }
309 | AstLiteral::String { .. }
310 | AstLiteral::Time { .. }
311 | AstLiteral::Date { .. }
312 | AstLiteral::TimeOfDay { .. }
313 | AstLiteral::DateAndTime { .. }
314 )
315 }
316
317 pub fn is_numerical(&self) -> bool {
318 matches!(
319 self,
320 AstLiteral::Integer { .. }
321 | AstLiteral::Real { .. }
322 | AstLiteral::Time { .. }
323 | AstLiteral::Date { .. }
324 | AstLiteral::TimeOfDay { .. }
325 | AstLiteral::DateAndTime { .. }
326 )
327 }
328
329 pub fn is_zero(&self) -> bool {
330 match self {
331 AstLiteral::Integer(0) => true,
332 AstLiteral::Real(val) => val == "0" || val == "0.0",
333 _ => false,
334 }
335 }
336
337 pub fn get_literal_integer_value(&self) -> Option<i128> {
338 let Self::Integer(val) = self else { return None };
339 Some(*val)
340 }
341}
342
343impl Debug for AstLiteral {
344 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
345 match self {
346 AstLiteral::Null => f.debug_struct("LiteralNull").finish(),
347 AstLiteral::Integer(value) => f.debug_struct("LiteralInteger").field("value", value).finish(),
348 AstLiteral::Date(Date { year, month, day, .. }) => f
349 .debug_struct("LiteralDate")
350 .field("year", year)
351 .field("month", month)
352 .field("day", day)
353 .finish(),
354 AstLiteral::DateAndTime(DateAndTime { year, month, day, hour, min, sec, nano, .. }) => f
355 .debug_struct("LiteralDateAndTime")
356 .field("year", year)
357 .field("month", month)
358 .field("day", day)
359 .field("hour", hour)
360 .field("min", min)
361 .field("sec", sec)
362 .field("nano", nano)
363 .finish(),
364 AstLiteral::TimeOfDay(TimeOfDay { hour, min, sec, nano, .. }) => f
365 .debug_struct("LiteralTimeOfDay")
366 .field("hour", hour)
367 .field("min", min)
368 .field("sec", sec)
369 .field("nano", nano)
370 .finish(),
371 AstLiteral::Time(Time { day, hour, min, sec, milli, micro, nano, negative, .. }) => f
372 .debug_struct("LiteralTime")
373 .field("day", day)
374 .field("hour", hour)
375 .field("min", min)
376 .field("sec", sec)
377 .field("milli", milli)
378 .field("micro", micro)
379 .field("nano", nano)
380 .field("negative", negative)
381 .finish(),
382 AstLiteral::Real(value) => f.debug_struct("LiteralReal").field("value", value).finish(),
383 AstLiteral::Bool(value) => f.debug_struct("LiteralBool").field("value", value).finish(),
384 AstLiteral::String(StringValue { value, is_wide, .. }) => {
385 f.debug_struct("LiteralString").field("value", value).field("is_wide", is_wide).finish()
386 }
387 AstLiteral::Array(Array { elements, .. }) => {
388 f.debug_struct("LiteralArray").field("elements", elements).finish()
389 }
390 }
391 }
392}