tank_core/
value.rs

1use crate::interval::Interval;
2use proc_macro2::TokenStream;
3use quote::{ToTokens, quote};
4use rust_decimal::Decimal;
5use std::{collections::HashMap, hash::Hash, mem::discriminant};
6use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
7use uuid::Uuid;
8
9#[derive(Default, Debug, Clone)]
10pub enum Value {
11    #[default]
12    Null,
13    Boolean(Option<bool>),
14    Int8(Option<i8>),
15    Int16(Option<i16>),
16    Int32(Option<i32>),
17    Int64(Option<i64>),
18    Int128(Option<i128>),
19    UInt8(Option<u8>),
20    UInt16(Option<u16>),
21    UInt32(Option<u32>),
22    UInt64(Option<u64>),
23    UInt128(Option<u128>),
24    Float32(Option<f32>),
25    Float64(Option<f64>),
26    Decimal(Option<Decimal>, /* width: */ u8, /* scale: */ u8),
27    Char(Option<char>),
28    Varchar(Option<String>),
29    Blob(Option<Box<[u8]>>),
30    Date(Option<Date>),
31    Time(Option<Time>),
32    Timestamp(Option<PrimitiveDateTime>),
33    TimestampWithTimezone(Option<OffsetDateTime>),
34    Interval(Option<Interval>),
35    Uuid(Option<Uuid>),
36    Array(
37        Option<Box<[Value]>>,
38        /* type: */ Box<Value>,
39        /* len: */ u32,
40    ),
41    List(Option<Vec<Value>>, /* type: */ Box<Value>),
42    Map(
43        Option<HashMap<Value, Value>>,
44        /* key: */ Box<Value>,
45        /* value: */ Box<Value>,
46    ),
47    Struct(
48        Option<Vec<(String, Value)>>,
49        /* type: */ Vec<(String, Value)>,
50    ),
51}
52
53impl Value {
54    pub fn same_type(&self, other: &Self) -> bool {
55        match (self, other) {
56            (Self::Decimal(.., l_width, l_scale), Self::Decimal(.., r_width, r_scale)) => {
57                (*l_width == 0 || *r_width == 0 || l_width == r_width)
58                    && (*l_scale == 0 || *r_scale == 0 || l_scale == r_scale)
59            }
60            (Self::Array(.., l_type, l_len), Self::Array(.., r_type, r_len)) => {
61                l_len == r_len && l_type.same_type(&r_type)
62            }
63            (Self::List(.., l), Self::List(.., r)) => l.same_type(r),
64            (Self::Map(.., l_key, l_value), Self::Map(.., r_key, r_value)) => {
65                l_key.same_type(r_key) && l_value.same_type(&r_value)
66            }
67            _ => discriminant(self) == discriminant(other),
68        }
69    }
70
71    pub fn is_null(&self) -> bool {
72        match self {
73            Value::Null
74            | Value::Boolean(None, ..)
75            | Value::Int8(None, ..)
76            | Value::Int16(None, ..)
77            | Value::Int32(None, ..)
78            | Value::Int64(None, ..)
79            | Value::Int128(None, ..)
80            | Value::UInt8(None, ..)
81            | Value::UInt16(None, ..)
82            | Value::UInt32(None, ..)
83            | Value::UInt64(None, ..)
84            | Value::UInt128(None, ..)
85            | Value::Float32(None, ..)
86            | Value::Float64(None, ..)
87            | Value::Decimal(None, ..)
88            | Value::Char(None, ..)
89            | Value::Varchar(None, ..)
90            | Value::Blob(None, ..)
91            | Value::Date(None, ..)
92            | Value::Time(None, ..)
93            | Value::Timestamp(None, ..)
94            | Value::TimestampWithTimezone(None, ..)
95            | Value::Interval(None, ..)
96            | Value::Uuid(None, ..)
97            | Value::Array(None, ..)
98            | Value::List(None, ..)
99            | Value::Map(None, ..)
100            | Value::Struct(None, ..) => true,
101            _ => false,
102        }
103    }
104
105    pub fn as_null(&self) -> Value {
106        match self {
107            Value::Null => Value::Null,
108            Value::Boolean(..) => Value::Boolean(None),
109            Value::Int8(..) => Value::Int8(None),
110            Value::Int16(..) => Value::Int16(None),
111            Value::Int32(..) => Value::Int32(None),
112            Value::Int64(..) => Value::Int64(None),
113            Value::Int128(..) => Value::Int128(None),
114            Value::UInt8(..) => Value::UInt8(None),
115            Value::UInt16(..) => Value::UInt16(None),
116            Value::UInt32(..) => Value::UInt32(None),
117            Value::UInt64(..) => Value::UInt64(None),
118            Value::UInt128(..) => Value::UInt128(None),
119            Value::Float32(..) => Value::Float32(None),
120            Value::Float64(..) => Value::Float64(None),
121            Value::Decimal(.., w, s) => Value::Decimal(None, *w, *s),
122            Value::Char(..) => Value::Char(None),
123            Value::Varchar(..) => Value::Varchar(None),
124            Value::Blob(..) => Value::Blob(None),
125            Value::Date(..) => Value::Date(None),
126            Value::Time(..) => Value::Time(None),
127            Value::Timestamp(..) => Value::Timestamp(None),
128            Value::TimestampWithTimezone(..) => Value::TimestampWithTimezone(None),
129            Value::Interval(..) => Value::Interval(None),
130            Value::Uuid(..) => Value::Uuid(None),
131            Value::Array(.., t, len) => Value::Array(None, t.clone(), *len),
132            Value::List(.., t) => Value::List(None, t.clone()),
133            Value::Map(.., k, v) => Value::Map(None, k.clone(), v.clone()),
134            Value::Struct(.., t) => Value::Struct(None, t.clone()),
135        }
136    }
137}
138
139impl PartialEq for Value {
140    fn eq(&self, other: &Self) -> bool {
141        match (self, other) {
142            (Self::Null, Self::Null) => true,
143            (Self::Boolean(l), Self::Boolean(r)) => l == r,
144            (Self::Int8(l), Self::Int8(r)) => l == r,
145            (Self::Int16(l), Self::Int16(r)) => l == r,
146            (Self::Int32(l), Self::Int32(r)) => l == r,
147            (Self::Int64(l), Self::Int64(r)) => l == r,
148            (Self::Int128(l), Self::Int128(r)) => l == r,
149            (Self::UInt8(l), Self::UInt8(r)) => l == r,
150            (Self::UInt16(l), Self::UInt16(r)) => l == r,
151            (Self::UInt32(l), Self::UInt32(r)) => l == r,
152            (Self::UInt64(l), Self::UInt64(r)) => l == r,
153            (Self::UInt128(l), Self::UInt128(r)) => l == r,
154            (Self::Float32(l), Self::Float32(r)) => {
155                l == r
156                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
157                        .unwrap_or_default()
158            }
159            (Self::Float64(l), Self::Float64(r)) => {
160                l == r
161                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
162                        .unwrap_or_default()
163            }
164            (Self::Decimal(l, l_width, l_scale), Self::Decimal(r, r_width, r_scale)) => {
165                l == r && l_width == r_width && l_scale == r_scale
166            }
167            (Self::Char(l), Self::Char(r)) => l == r,
168            (Self::Varchar(l), Self::Varchar(r)) => l == r,
169            (Self::Blob(l), Self::Blob(r)) => l == r,
170            (Self::Date(l), Self::Date(r)) => l == r,
171            (Self::Time(l), Self::Time(r)) => l == r,
172            (Self::Timestamp(l), Self::Timestamp(r)) => l == r,
173            (Self::TimestampWithTimezone(l), Self::TimestampWithTimezone(r)) => l == r,
174            (Self::Interval(l), Self::Interval(r)) => l == r,
175            (Self::Uuid(l), Self::Uuid(r)) => l == r,
176            (Self::Array(l, ..), Self::Array(r, ..)) => l == r && self.same_type(other),
177            (Self::List(l, ..), Self::List(r, ..)) => l == r && self.same_type(other),
178            (Self::Map(None, ..), Self::Map(None, ..)) => self.same_type(other),
179            (Self::Map(Some(l), ..), Self::Map(Some(r), ..)) => {
180                l.is_empty() == r.is_empty() && self.same_type(other)
181            }
182            (Self::Map(..), Self::Map(..)) => self.same_type(other),
183            _ => false,
184        }
185    }
186}
187
188impl Eq for Value {}
189
190impl Hash for Value {
191    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
192        use Value::*;
193        discriminant(self).hash(state);
194        match self {
195            Null => {}
196            Boolean(v) => v.hash(state),
197            Int8(v) => v.hash(state),
198            Int16(v) => v.hash(state),
199            Int32(v) => v.hash(state),
200            Int64(v) => v.hash(state),
201            Int128(v) => v.hash(state),
202
203            UInt8(v) => v.hash(state),
204            UInt16(v) => v.hash(state),
205            UInt32(v) => v.hash(state),
206            UInt64(v) => v.hash(state),
207            UInt128(v) => v.hash(state),
208            Float32(Some(v)) => {
209                v.to_bits().hash(state);
210            }
211            Float32(None) => None::<u32>.hash(state),
212            Float64(Some(v)) => {
213                v.to_bits().hash(state);
214            }
215            Float64(None) => None::<u64>.hash(state),
216            Decimal(v, width, scale) => {
217                v.hash(state);
218                width.hash(state);
219                scale.hash(state);
220            }
221            Char(v) => v.hash(state),
222            Varchar(v) => v.hash(state),
223            Blob(v) => v.hash(state),
224            Date(v) => v.hash(state),
225            Time(v) => v.hash(state),
226            Timestamp(v) => v.hash(state),
227            TimestampWithTimezone(v) => v.hash(state),
228            Interval(v) => v.hash(state),
229            Uuid(v) => v.hash(state),
230
231            Array(v, typ, len) => {
232                v.hash(state);
233                typ.hash(state);
234                len.hash(state);
235            }
236
237            List(v, typ) => {
238                v.hash(state);
239                typ.hash(state);
240            }
241
242            Map(v, key, val) => {
243                match v {
244                    Some(map) => {
245                        for (key, val) in map {
246                            key.hash(state);
247                            val.hash(state);
248                        }
249                    }
250                    None => {}
251                }
252                key.hash(state);
253                val.hash(state);
254            }
255            Struct(v, t) => {
256                match v {
257                    Some(v) => v.hash(state),
258                    None => {}
259                }
260                t.hash(state);
261            }
262        }
263    }
264}
265
266#[derive(Default)]
267pub struct TypeDecoded {
268    pub value: Value,
269    pub nullable: bool,
270    pub passive: bool,
271}
272
273pub type CheckPassive = Box<dyn Fn(TokenStream) -> TokenStream>;
274
275impl ToTokens for Value {
276    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
277        let ts = match self {
278            Value::Null => quote!(::tank::Value::Null),
279            Value::Boolean(..) => quote!(::tank::Value::Boolean(None)),
280            Value::Int8(..) => quote!(::tank::Value::Int8(None)),
281            Value::Int16(..) => quote!(::tank::Value::Int16(None)),
282            Value::Int32(..) => quote!(::tank::Value::Int32(None)),
283            Value::Int64(..) => quote!(::tank::Value::Int64(None)),
284            Value::Int128(..) => quote!(::tank::Value::Int128(None)),
285            Value::UInt8(..) => quote!(::tank::Value::UInt8(None)),
286            Value::UInt16(..) => quote!(::tank::Value::UInt16(None)),
287            Value::UInt32(..) => quote!(::tank::Value::UInt32(None)),
288            Value::UInt64(..) => quote!(::tank::Value::UInt64(None)),
289            Value::UInt128(..) => quote!(::tank::Value::UInt128(None)),
290            Value::Float32(..) => quote!(::tank::Value::Float32(None)),
291            Value::Float64(..) => quote!(::tank::Value::Float64(None)),
292            Value::Decimal(.., width, scale) => {
293                quote!(::tank::Value::Decimal(None, #width, #scale))
294            }
295            Value::Char(..) => quote!(tank::Value::Char(None)),
296            Value::Varchar(..) => quote!(::tank::Value::Varchar(None)),
297            Value::Blob(..) => quote!(::tank::Value::Blob(None)),
298            Value::Date(..) => quote!(::tank::Value::Date(None)),
299            Value::Time(..) => quote!(::tank::Value::Time(None)),
300            Value::Timestamp(..) => quote!(::tank::Value::Timestamp(None)),
301            Value::TimestampWithTimezone(..) => quote!(::tank::Value::TimestampWithTimezone(None)),
302            Value::Interval(..) => quote!(::tank::Value::Interval(None)),
303            Value::Uuid(..) => quote!(::tank::Value::Uuid(None)),
304            Value::Array(.., inner, size) => {
305                quote!(::tank::Value::Array(None, Box::new(#inner), #size))
306            }
307            Value::List(.., inner) => {
308                let inner = inner.as_ref().to_token_stream();
309                quote!(::tank::Value::List(None, Box::new(#inner)))
310            }
311            Value::Map(.., key, value) => {
312                let key = key.as_ref().to_token_stream();
313                let value = value.as_ref().to_token_stream();
314                quote!(::tank::Value::Map(None, Box::new(#key), Box::new(#value)))
315            }
316            Value::Struct(.., t) => {
317                let values = t.into_iter().map(|(k, v)| quote!((#k.into(), #v)));
318                quote!(::tank::Value::Struct(None, vec!(#(#values),*)))
319            }
320        };
321        tokens.extend(ts);
322    }
323}