tank_core/
value.rs

1use crate::{AsValue, Error, Result, interval::Interval};
2use proc_macro2::TokenStream;
3use quote::{ToTokens, quote};
4use rust_decimal::Decimal;
5use serde_json::Value as JsonValue;
6use std::{collections::HashMap, hash::Hash, mem::discriminant};
7use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
8use uuid::Uuid;
9
10/// Strongly-typed, nullable SQL value representation used across Tank.
11///
12/// Variants wrap `Option<T>` – `None` signifies SQL NULL (except `Null` which
13/// unconditionally represents a NULL of unknown type). Complex variants carry
14/// additional shape metadata (element type, length, precision, etc.).
15#[derive(Default, Debug, Clone)]
16pub enum Value {
17    /// Untyped NULL placeholder.
18    #[default]
19    Null,
20    Boolean(Option<bool>),
21    Int8(Option<i8>),
22    Int16(Option<i16>),
23    Int32(Option<i32>),
24    Int64(Option<i64>),
25    Int128(Option<i128>),
26    UInt8(Option<u8>),
27    UInt16(Option<u16>),
28    UInt32(Option<u32>),
29    UInt64(Option<u64>),
30    UInt128(Option<u128>),
31    Float32(Option<f32>),
32    Float64(Option<f64>),
33    /// Arbitrary precision decimal with width/scale hints.
34    Decimal(Option<Decimal>, /* width: */ u8, /* scale: */ u8),
35    Char(Option<char>),
36    Varchar(Option<String>),
37    Blob(Option<Box<[u8]>>),
38    Date(Option<Date>),
39    Time(Option<Time>),
40    Timestamp(Option<PrimitiveDateTime>),
41    TimestampWithTimezone(Option<OffsetDateTime>),
42    Interval(Option<Interval>),
43    Uuid(Option<Uuid>),
44    /// Fixed-size homogeneous array.
45    Array(
46        Option<Box<[Value]>>,
47        /* type: */ Box<Value>,
48        /* len: */ u32,
49    ),
50    /// Variable length homogeneous list.
51    List(Option<Vec<Value>>, /* type: */ Box<Value>),
52    /// Map with homogeneous key/value types.
53    Map(
54        Option<HashMap<Value, Value>>,
55        /* key: */ Box<Value>,
56        /* value: */ Box<Value>,
57    ),
58    Json(Option<JsonValue>),
59    /// Struct with named fields and their types.
60    Struct(
61        Option<Vec<(String, Value)>>,
62        /* type: */ Vec<(String, Value)>,
63    ),
64    /// Parsing fallback / unknown driver-provided type.
65    Unknown(Option<String>),
66}
67
68impl Value {
69    pub fn same_type(&self, other: &Self) -> bool {
70        match (self, other) {
71            (Self::Decimal(.., l_width, l_scale), Self::Decimal(.., r_width, r_scale)) => {
72                (*l_width == 0 || *r_width == 0 || l_width == r_width)
73                    && (*l_scale == 0 || *r_scale == 0 || l_scale == r_scale)
74            }
75            (Self::Array(.., l_type, l_len), Self::Array(.., r_type, r_len)) => {
76                l_len == r_len && l_type.same_type(&r_type)
77            }
78            (Self::List(.., l), Self::List(.., r)) => l.same_type(r),
79            (Self::Map(.., l_key, l_value), Self::Map(.., r_key, r_value)) => {
80                l_key.same_type(r_key) && l_value.same_type(&r_value)
81            }
82            _ => discriminant(self) == discriminant(other),
83        }
84    }
85
86    pub fn is_null(&self) -> bool {
87        match self {
88            Value::Null
89            | Value::Boolean(None, ..)
90            | Value::Int8(None, ..)
91            | Value::Int16(None, ..)
92            | Value::Int32(None, ..)
93            | Value::Int64(None, ..)
94            | Value::Int128(None, ..)
95            | Value::UInt8(None, ..)
96            | Value::UInt16(None, ..)
97            | Value::UInt32(None, ..)
98            | Value::UInt64(None, ..)
99            | Value::UInt128(None, ..)
100            | Value::Float32(None, ..)
101            | Value::Float64(None, ..)
102            | Value::Decimal(None, ..)
103            | Value::Char(None, ..)
104            | Value::Varchar(None, ..)
105            | Value::Blob(None, ..)
106            | Value::Date(None, ..)
107            | Value::Time(None, ..)
108            | Value::Timestamp(None, ..)
109            | Value::TimestampWithTimezone(None, ..)
110            | Value::Interval(None, ..)
111            | Value::Uuid(None, ..)
112            | Value::Array(None, ..)
113            | Value::List(None, ..)
114            | Value::Map(None, ..)
115            | Value::Json(None, ..)
116            | Value::Json(Some(serde_json::Value::Null), ..)
117            | Value::Struct(None, ..)
118            | Value::Unknown(None, ..) => true,
119            _ => false,
120        }
121    }
122
123    pub fn as_null(&self) -> Value {
124        match self {
125            Value::Null => Value::Null,
126            Value::Boolean(..) => Value::Boolean(None),
127            Value::Int8(..) => Value::Int8(None),
128            Value::Int16(..) => Value::Int16(None),
129            Value::Int32(..) => Value::Int32(None),
130            Value::Int64(..) => Value::Int64(None),
131            Value::Int128(..) => Value::Int128(None),
132            Value::UInt8(..) => Value::UInt8(None),
133            Value::UInt16(..) => Value::UInt16(None),
134            Value::UInt32(..) => Value::UInt32(None),
135            Value::UInt64(..) => Value::UInt64(None),
136            Value::UInt128(..) => Value::UInt128(None),
137            Value::Float32(..) => Value::Float32(None),
138            Value::Float64(..) => Value::Float64(None),
139            Value::Decimal(.., w, s) => Value::Decimal(None, *w, *s),
140            Value::Char(..) => Value::Char(None),
141            Value::Varchar(..) => Value::Varchar(None),
142            Value::Blob(..) => Value::Blob(None),
143            Value::Date(..) => Value::Date(None),
144            Value::Time(..) => Value::Time(None),
145            Value::Timestamp(..) => Value::Timestamp(None),
146            Value::TimestampWithTimezone(..) => Value::TimestampWithTimezone(None),
147            Value::Interval(..) => Value::Interval(None),
148            Value::Uuid(..) => Value::Uuid(None),
149            Value::Array(.., t, len) => Value::Array(None, t.clone(), *len),
150            Value::List(.., t) => Value::List(None, t.clone()),
151            Value::Map(.., k, v) => Value::Map(None, k.clone(), v.clone()),
152            Value::Json(..) => Value::Json(None),
153            Value::Struct(.., t) => Value::Struct(None, t.clone()),
154            Value::Unknown(..) => Value::Unknown(None),
155        }
156    }
157
158    pub fn try_as(self, value: &Value) -> Result<Value> {
159        if self.same_type(value) {
160            return Ok(self);
161        }
162        match value {
163            Value::Boolean(..) => bool::try_from_value(self).map(AsValue::as_value),
164            Value::Int8(..) => i8::try_from_value(self).map(AsValue::as_value),
165            Value::Int16(..) => i16::try_from_value(self).map(AsValue::as_value),
166            Value::Int32(..) => i32::try_from_value(self).map(AsValue::as_value),
167            Value::Int64(..) => i64::try_from_value(self).map(AsValue::as_value),
168            Value::Int128(..) => i128::try_from_value(self).map(AsValue::as_value),
169            Value::UInt8(..) => u8::try_from_value(self).map(AsValue::as_value),
170            Value::UInt16(..) => u16::try_from_value(self).map(AsValue::as_value),
171            Value::UInt32(..) => u32::try_from_value(self).map(AsValue::as_value),
172            Value::UInt64(..) => u64::try_from_value(self).map(AsValue::as_value),
173            Value::UInt128(..) => u128::try_from_value(self).map(AsValue::as_value),
174            Value::Float32(..) => f32::try_from_value(self).map(AsValue::as_value),
175            Value::Float64(..) => f64::try_from_value(self).map(AsValue::as_value),
176            Value::Decimal(..) => Decimal::try_from_value(self).map(AsValue::as_value),
177            Value::Char(..) => char::try_from_value(self).map(AsValue::as_value),
178            Value::Varchar(..) => String::try_from_value(self).map(AsValue::as_value),
179            Value::Blob(..) => Box::<[u8]>::try_from_value(self).map(AsValue::as_value),
180            Value::Date(..) => Date::try_from_value(self).map(AsValue::as_value),
181            Value::Time(..) => Time::try_from_value(self).map(AsValue::as_value),
182            Value::Timestamp(..) => PrimitiveDateTime::try_from_value(self).map(AsValue::as_value),
183            Value::TimestampWithTimezone(..) => {
184                OffsetDateTime::try_from_value(self).map(AsValue::as_value)
185            }
186            Value::Interval(..) => Interval::try_from_value(self).map(AsValue::as_value),
187            Value::Uuid(..) => Uuid::try_from_value(self).map(AsValue::as_value),
188            // Value::Array(.., ty, len) => {
189            //     Box::<[Value]>::try_from_value(self).map(AsValue::as_value)
190            // }
191            // Value::List(..) => Box::<[Value]>::try_from_value(self).map(AsValue::as_value),
192            // Value::Map(..) => Date::try_from_value(self).map(AsValue::as_value),
193            _ => {
194                return Err(Error::msg(format!(
195                    "Cannot convert value {:?} into value {:?}",
196                    self, value
197                )));
198            }
199        }
200    }
201}
202
203impl PartialEq for Value {
204    fn eq(&self, other: &Self) -> bool {
205        match (self, other) {
206            (Self::Null, Self::Null) => true,
207            (Self::Boolean(l), Self::Boolean(r)) => l == r,
208            (Self::Int8(l), Self::Int8(r)) => l == r,
209            (Self::Int16(l), Self::Int16(r)) => l == r,
210            (Self::Int32(l), Self::Int32(r)) => l == r,
211            (Self::Int64(l), Self::Int64(r)) => l == r,
212            (Self::Int128(l), Self::Int128(r)) => l == r,
213            (Self::UInt8(l), Self::UInt8(r)) => l == r,
214            (Self::UInt16(l), Self::UInt16(r)) => l == r,
215            (Self::UInt32(l), Self::UInt32(r)) => l == r,
216            (Self::UInt64(l), Self::UInt64(r)) => l == r,
217            (Self::UInt128(l), Self::UInt128(r)) => l == r,
218            (Self::Float32(l), Self::Float32(r)) => {
219                l == r
220                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
221                        .unwrap_or_default()
222            }
223            (Self::Float64(l), Self::Float64(r)) => {
224                l == r
225                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
226                        .unwrap_or_default()
227            }
228            (Self::Decimal(l, l_width, l_scale), Self::Decimal(r, r_width, r_scale)) => {
229                l == r && l_width == r_width && l_scale == r_scale
230            }
231            (Self::Char(l), Self::Char(r)) => l == r,
232            (Self::Varchar(l), Self::Varchar(r)) => l == r,
233            (Self::Blob(l), Self::Blob(r)) => l == r,
234            (Self::Date(l), Self::Date(r)) => l == r,
235            (Self::Time(l), Self::Time(r)) => l == r,
236            (Self::Timestamp(l), Self::Timestamp(r)) => l == r,
237            (Self::TimestampWithTimezone(l), Self::TimestampWithTimezone(r)) => l == r,
238            (Self::Interval(l), Self::Interval(r)) => l == r,
239            (Self::Uuid(l), Self::Uuid(r)) => l == r,
240            (Self::Array(l, ..), Self::Array(r, ..)) => l == r && self.same_type(other),
241            (Self::List(l, ..), Self::List(r, ..)) => l == r && self.same_type(other),
242            (Self::Map(None, ..), Self::Map(None, ..)) => self.same_type(other),
243            (Self::Map(Some(l), ..), Self::Map(Some(r), ..)) => {
244                l.is_empty() == r.is_empty() && self.same_type(other)
245            }
246            (Self::Map(..), Self::Map(..)) => self.same_type(other),
247            (Self::Json(l), Self::Json(r)) => l == r,
248            (Self::Unknown(..), Self::Unknown(..)) => false,
249            _ => false,
250        }
251    }
252}
253
254impl Eq for Value {}
255
256impl Hash for Value {
257    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
258        use Value::*;
259        discriminant(self).hash(state);
260        match self {
261            Null => {}
262            Boolean(v) => v.hash(state),
263            Int8(v) => v.hash(state),
264            Int16(v) => v.hash(state),
265            Int32(v) => v.hash(state),
266            Int64(v) => v.hash(state),
267            Int128(v) => v.hash(state),
268
269            UInt8(v) => v.hash(state),
270            UInt16(v) => v.hash(state),
271            UInt32(v) => v.hash(state),
272            UInt64(v) => v.hash(state),
273            UInt128(v) => v.hash(state),
274            Float32(Some(v)) => {
275                v.to_bits().hash(state);
276            }
277            Float32(None) => None::<u32>.hash(state),
278            Float64(Some(v)) => {
279                v.to_bits().hash(state);
280            }
281            Float64(None) => None::<u64>.hash(state),
282            Decimal(v, width, scale) => {
283                v.hash(state);
284                width.hash(state);
285                scale.hash(state);
286            }
287            Char(v) => v.hash(state),
288            Varchar(v) => v.hash(state),
289            Blob(v) => v.hash(state),
290            Date(v) => v.hash(state),
291            Time(v) => v.hash(state),
292            Timestamp(v) => v.hash(state),
293            TimestampWithTimezone(v) => v.hash(state),
294            Interval(v) => v.hash(state),
295            Uuid(v) => v.hash(state),
296            Array(v, typ, len) => {
297                v.hash(state);
298                typ.hash(state);
299                len.hash(state);
300            }
301            List(v, typ) => {
302                v.hash(state);
303                typ.hash(state);
304            }
305            Map(v, key, val) => {
306                match v {
307                    Some(map) => {
308                        for (key, val) in map {
309                            key.hash(state);
310                            val.hash(state);
311                        }
312                    }
313                    None => {}
314                }
315                key.hash(state);
316                val.hash(state);
317            }
318            Json(v) => v.hash(state),
319            Struct(v, t) => {
320                match v {
321                    Some(v) => v.hash(state),
322                    None => {}
323                }
324                t.hash(state);
325            }
326            Unknown(v) => v.hash(state),
327        }
328    }
329}
330
331/// Intermediate decoded type information used by derive macros.
332#[derive(Default)]
333pub struct TypeDecoded {
334    /// Representative value establishing variant & metadata.
335    pub value: Value,
336    /// Nullability indicator.
337    pub nullable: bool,
338    /// Passive flag (exclude from INSERT column/value list).
339    pub passive: bool,
340}
341
342pub type CheckPassive = Box<dyn Fn(TokenStream) -> TokenStream>;
343
344impl ToTokens for Value {
345    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
346        let ts = match self {
347            Value::Null => quote!(::tank::Value::Null),
348            Value::Boolean(..) => quote!(::tank::Value::Boolean(None)),
349            Value::Int8(..) => quote!(::tank::Value::Int8(None)),
350            Value::Int16(..) => quote!(::tank::Value::Int16(None)),
351            Value::Int32(..) => quote!(::tank::Value::Int32(None)),
352            Value::Int64(..) => quote!(::tank::Value::Int64(None)),
353            Value::Int128(..) => quote!(::tank::Value::Int128(None)),
354            Value::UInt8(..) => quote!(::tank::Value::UInt8(None)),
355            Value::UInt16(..) => quote!(::tank::Value::UInt16(None)),
356            Value::UInt32(..) => quote!(::tank::Value::UInt32(None)),
357            Value::UInt64(..) => quote!(::tank::Value::UInt64(None)),
358            Value::UInt128(..) => quote!(::tank::Value::UInt128(None)),
359            Value::Float32(..) => quote!(::tank::Value::Float32(None)),
360            Value::Float64(..) => quote!(::tank::Value::Float64(None)),
361            Value::Decimal(.., width, scale) => {
362                quote!(::tank::Value::Decimal(None, #width, #scale))
363            }
364            Value::Char(..) => quote!(tank::Value::Char(None)),
365            Value::Varchar(..) => quote!(::tank::Value::Varchar(None)),
366            Value::Blob(..) => quote!(::tank::Value::Blob(None)),
367            Value::Date(..) => quote!(::tank::Value::Date(None)),
368            Value::Time(..) => quote!(::tank::Value::Time(None)),
369            Value::Timestamp(..) => quote!(::tank::Value::Timestamp(None)),
370            Value::TimestampWithTimezone(..) => quote!(::tank::Value::TimestampWithTimezone(None)),
371            Value::Interval(..) => quote!(::tank::Value::Interval(None)),
372            Value::Uuid(..) => quote!(::tank::Value::Uuid(None)),
373            Value::Array(.., inner, size) => {
374                quote!(::tank::Value::Array(None, Box::new(#inner), #size))
375            }
376            Value::List(.., inner) => {
377                let inner = inner.as_ref().to_token_stream();
378                quote!(::tank::Value::List(None, Box::new(#inner)))
379            }
380            Value::Map(.., key, value) => {
381                let key = key.as_ref().to_token_stream();
382                let value = value.as_ref().to_token_stream();
383                quote!(::tank::Value::Map(None, Box::new(#key), Box::new(#value)))
384            }
385            Value::Json(..) => quote!(::tank::Value::Json(None)),
386            Value::Struct(.., t) => {
387                let values = t.into_iter().map(|(k, v)| quote!((#k.into(), #v)));
388                quote!(::tank::Value::Struct(None, vec!(#(#values),*)))
389            }
390            Value::Unknown(..) => quote!(::tank::Value::Unknown(None)),
391        };
392        tokens.extend(ts);
393    }
394}