1use super::*;
2use ordered_float::OrderedFloat;
3use std::{
4 hash::{Hash, Hasher},
5 mem,
6};
7
8impl PartialEq for Value {
9 fn eq(&self, other: &Self) -> bool {
10 match (self, other) {
11 (Self::Bool(l), Self::Bool(r)) => l == r,
12 (Self::TinyInt(l), Self::TinyInt(r)) => l == r,
13 (Self::SmallInt(l), Self::SmallInt(r)) => l == r,
14 (Self::Int(l), Self::Int(r)) => l == r,
15 (Self::BigInt(l), Self::BigInt(r)) => l == r,
16 (Self::TinyUnsigned(l), Self::TinyUnsigned(r)) => l == r,
17 (Self::SmallUnsigned(l), Self::SmallUnsigned(r)) => l == r,
18 (Self::Unsigned(l), Self::Unsigned(r)) => l == r,
19 (Self::BigUnsigned(l), Self::BigUnsigned(r)) => l == r,
20 (Self::Float(l), Self::Float(r)) => cmp_f32(l, r),
21 (Self::Double(l), Self::Double(r)) => cmp_f64(l, r),
22 (Self::String(l), Self::String(r)) => l == r,
23 (Self::Char(l), Self::Char(r)) => l == r,
24 (Self::Bytes(l), Self::Bytes(r)) => l == r,
25
26 #[cfg(feature = "with-json")]
27 (Self::Json(l), Self::Json(r)) => cmp_json(l, r),
28
29 #[cfg(feature = "with-chrono")]
30 (Self::ChronoDate(l), Self::ChronoDate(r)) => l == r,
31 #[cfg(feature = "with-chrono")]
32 (Self::ChronoTime(l), Self::ChronoTime(r)) => l == r,
33 #[cfg(feature = "with-chrono")]
34 (Self::ChronoDateTime(l), Self::ChronoDateTime(r)) => l == r,
35 #[cfg(feature = "with-chrono")]
36 (Self::ChronoDateTimeUtc(l), Self::ChronoDateTimeUtc(r)) => l == r,
37 #[cfg(feature = "with-chrono")]
38 (Self::ChronoDateTimeLocal(l), Self::ChronoDateTimeLocal(r)) => l == r,
39 #[cfg(feature = "with-chrono")]
40 (Self::ChronoDateTimeWithTimeZone(l), Self::ChronoDateTimeWithTimeZone(r)) => l == r,
41
42 #[cfg(feature = "with-time")]
43 (Self::TimeDate(l), Self::TimeDate(r)) => l == r,
44 #[cfg(feature = "with-time")]
45 (Self::TimeTime(l), Self::TimeTime(r)) => l == r,
46 #[cfg(feature = "with-time")]
47 (Self::TimeDateTime(l), Self::TimeDateTime(r)) => l == r,
48 #[cfg(feature = "with-time")]
49 (Self::TimeDateTimeWithTimeZone(l), Self::TimeDateTimeWithTimeZone(r)) => l == r,
50
51 #[cfg(feature = "with-jiff")]
52 (Self::JiffDate(l), Self::JiffDate(r)) => l == r,
53 #[cfg(feature = "with-jiff")]
54 (Self::JiffTime(l), Self::JiffTime(r)) => l == r,
55 #[cfg(feature = "with-jiff")]
56 (Self::JiffDateTime(l), Self::JiffDateTime(r)) => l == r,
57 #[cfg(feature = "with-jiff")]
58 (Self::JiffTimestamp(l), Self::JiffTimestamp(r)) => l == r,
59 #[cfg(feature = "with-jiff")]
60 (Self::JiffZoned(l), Self::JiffZoned(r)) => l == r,
61
62 #[cfg(feature = "with-uuid")]
63 (Self::Uuid(l), Self::Uuid(r)) => l == r,
64
65 #[cfg(feature = "with-rust_decimal")]
66 (Self::Decimal(l), Self::Decimal(r)) => l == r,
67
68 #[cfg(feature = "with-bigdecimal")]
69 (Self::BigDecimal(l), Self::BigDecimal(r)) => l == r,
70
71 #[cfg(feature = "postgres-array")]
72 (Self::Array(ty_l, values_l), Self::Array(ty_r, values_r)) => {
73 ty_l == ty_r && values_l == values_r
74 }
75
76 #[cfg(feature = "postgres-vector")]
77 (Self::Vector(l), Self::Vector(r)) => cmp_vector(l, r),
78
79 #[cfg(feature = "with-ipnetwork")]
80 (Self::IpNetwork(l), Self::IpNetwork(r)) => l == r,
81
82 #[cfg(feature = "with-mac_address")]
83 (Self::MacAddress(l), Self::MacAddress(r)) => l == r,
84
85 _ => false,
86 }
87 }
88}
89
90impl Eq for Value {}
91
92impl Hash for Value {
93 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
94 mem::discriminant(self).hash(state);
95 match self {
96 Value::Bool(v) => v.hash(state),
97 Value::TinyInt(v) => v.hash(state),
98 Value::SmallInt(v) => v.hash(state),
99 Value::Int(v) => v.hash(state),
100 Value::BigInt(v) => v.hash(state),
101 Value::TinyUnsigned(v) => v.hash(state),
102 Value::SmallUnsigned(v) => v.hash(state),
103 Value::Unsigned(v) => v.hash(state),
104 Value::BigUnsigned(v) => v.hash(state),
105 Value::Float(v) => hash_f32(v, state),
106 Value::Double(v) => hash_f64(v, state),
107 Value::String(v) => v.hash(state),
108 Value::Char(v) => v.hash(state),
109 Value::Bytes(v) => v.hash(state),
110
111 #[cfg(feature = "with-json")]
112 Value::Json(value) => hash_json(value, state),
113
114 #[cfg(feature = "with-chrono")]
115 Value::ChronoDate(naive_date) => naive_date.hash(state),
116 #[cfg(feature = "with-chrono")]
117 Value::ChronoTime(naive_time) => naive_time.hash(state),
118 #[cfg(feature = "with-chrono")]
119 Value::ChronoDateTime(naive_date_time) => naive_date_time.hash(state),
120 #[cfg(feature = "with-chrono")]
121 Value::ChronoDateTimeUtc(date_time) => date_time.hash(state),
122 #[cfg(feature = "with-chrono")]
123 Value::ChronoDateTimeLocal(date_time) => date_time.hash(state),
124 #[cfg(feature = "with-chrono")]
125 Value::ChronoDateTimeWithTimeZone(date_time) => date_time.hash(state),
126
127 #[cfg(feature = "with-time")]
128 Value::TimeDate(date) => date.hash(state),
129 #[cfg(feature = "with-time")]
130 Value::TimeTime(time) => time.hash(state),
131 #[cfg(feature = "with-time")]
132 Value::TimeDateTime(primitive_date_time) => primitive_date_time.hash(state),
133 #[cfg(feature = "with-time")]
134 Value::TimeDateTimeWithTimeZone(offset_date_time) => offset_date_time.hash(state),
135
136 #[cfg(feature = "with-jiff")]
137 Value::JiffDate(date) => date.hash(state),
138 #[cfg(feature = "with-jiff")]
139 Value::JiffTime(time) => time.hash(state),
140 #[cfg(feature = "with-jiff")]
141 Value::JiffDateTime(datetime) => datetime.hash(state),
142 #[cfg(feature = "with-jiff")]
143 Value::JiffTimestamp(timestamp) => timestamp.hash(state),
144 #[cfg(feature = "with-jiff")]
145 Value::JiffZoned(zoned) => zoned.hash(state),
146
147 #[cfg(feature = "with-uuid")]
148 Value::Uuid(uuid) => uuid.hash(state),
149
150 #[cfg(feature = "with-rust_decimal")]
151 Value::Decimal(decimal) => decimal.hash(state),
152
153 #[cfg(feature = "with-bigdecimal")]
154 Value::BigDecimal(big_decimal) => big_decimal.hash(state),
155
156 #[cfg(feature = "postgres-array")]
157 Value::Array(array_type, vec) => {
158 array_type.hash(state);
159 vec.hash(state);
160 }
161
162 #[cfg(feature = "postgres-vector")]
163 Value::Vector(vector) => hash_vector(vector, state),
164
165 #[cfg(feature = "with-ipnetwork")]
166 Value::IpNetwork(ip_network) => ip_network.hash(state),
167
168 #[cfg(feature = "with-mac_address")]
169 Value::MacAddress(mac_address) => mac_address.hash(state),
170
171 #[cfg(feature = "postgres-range")]
172 Value::Range(range) => range.hash(state),
173 }
174 }
175}
176
177fn hash_f32<H: Hasher>(v: &Option<f32>, state: &mut H) {
178 match v {
179 Some(v) => OrderedFloat(*v).hash(state),
180 None => "null".hash(state),
181 }
182}
183
184fn hash_f64<H: Hasher>(v: &Option<f64>, state: &mut H) {
185 match v {
186 Some(v) => OrderedFloat(*v).hash(state),
187 None => "null".hash(state),
188 }
189}
190
191fn cmp_f32(l: &Option<f32>, r: &Option<f32>) -> bool {
192 match (l, r) {
193 (Some(l), Some(r)) => OrderedFloat(*l).eq(&OrderedFloat(*r)),
194 (None, None) => true,
195 _ => false,
196 }
197}
198
199fn cmp_f64(l: &Option<f64>, r: &Option<f64>) -> bool {
200 match (l, r) {
201 (Some(l), Some(r)) => OrderedFloat(*l).eq(&OrderedFloat(*r)),
202 (None, None) => true,
203 _ => false,
204 }
205}
206
207#[cfg(feature = "with-json")]
208fn hash_json<H: Hasher>(v: &Option<Box<Json>>, state: &mut H) {
209 match v {
210 Some(v) => serde_json::to_string(v).unwrap().hash(state),
211 None => "null".hash(state),
212 }
213}
214
215#[cfg(feature = "with-json")]
216fn cmp_json(l: &Option<Box<Json>>, r: &Option<Box<Json>>) -> bool {
217 match (l, r) {
218 (Some(l), Some(r)) => serde_json::to_string(l)
219 .unwrap()
220 .eq(&serde_json::to_string(r).unwrap()),
221 (None, None) => true,
222 _ => false,
223 }
224}
225
226#[cfg(feature = "postgres-vector")]
227fn hash_vector<H: Hasher>(v: &Option<pgvector::Vector>, state: &mut H) {
228 match v {
229 Some(v) => {
230 for &value in v.as_slice().iter() {
231 hash_f32(&Some(value), state);
232 }
233 }
234 None => "null".hash(state),
235 }
236}
237
238#[cfg(feature = "postgres-vector")]
239fn cmp_vector(l: &Option<pgvector::Vector>, r: &Option<pgvector::Vector>) -> bool {
240 match (l, r) {
241 (Some(l), Some(r)) => {
242 let (l, r) = (l.as_slice(), r.as_slice());
243 if l.len() != r.len() {
244 return false;
245 }
246 for (l, r) in l.iter().zip(r.iter()) {
247 if !cmp_f32(&Some(*l), &Some(*r)) {
248 return false;
249 }
250 }
251 true
252 }
253 (None, None) => true,
254 _ => false,
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use crate::Value;
261 #[test]
262 fn test_hash_value_0() {
263 let hash_set: std::collections::HashSet<Value> = [
264 Value::Int(None),
265 Value::Int(None),
266 Value::BigInt(None),
267 Value::BigInt(None),
268 Value::Float(None),
269 Value::Float(None), Value::Float(Some(f32::NAN)), Value::Float(Some(f32::NAN)),
272 Value::Double(None),
273 Value::Double(None),
274 Value::Double(Some(f64::NAN)),
275 Value::Double(Some(f64::NAN)),
276 ]
277 .into_iter()
278 .collect();
279
280 let unique: std::collections::HashSet<Value> = [
281 Value::Int(None),
282 Value::BigInt(None),
283 Value::Float(None),
284 Value::Double(None),
285 Value::Float(Some(f32::NAN)),
286 Value::Double(Some(f64::NAN)),
287 ]
288 .into_iter()
289 .collect();
290
291 assert_eq!(hash_set, unique);
292 }
293
294 #[test]
295 fn test_hash_value_1() {
296 let hash_set: std::collections::HashSet<Value> = [
297 Value::Int(None),
298 Value::Int(Some(1)),
299 Value::Int(Some(1)),
300 Value::BigInt(Some(2)),
301 Value::BigInt(Some(2)),
302 Value::Float(Some(3.0)),
303 Value::Float(Some(3.0)),
304 Value::Double(Some(3.0)),
305 Value::Double(Some(3.0)),
306 Value::BigInt(Some(5)),
307 ]
308 .into_iter()
309 .collect();
310
311 let unique: std::collections::HashSet<Value> = [
312 Value::BigInt(Some(5)),
313 Value::Double(Some(3.0)),
314 Value::Float(Some(3.0)),
315 Value::BigInt(Some(2)),
316 Value::Int(Some(1)),
317 Value::Int(None),
318 ]
319 .into_iter()
320 .collect();
321
322 assert_eq!(hash_set, unique);
323 }
324
325 #[cfg(feature = "postgres-array")]
326 #[test]
327 fn test_hash_value_array() {
328 use crate::ArrayType;
329
330 assert_eq!(
331 Into::<Value>::into(vec![0i32, 1, 2]),
332 Value::Array(
333 ArrayType::Int,
334 Some(Box::new(vec![
335 Value::Int(Some(0)),
336 Value::Int(Some(1)),
337 Value::Int(Some(2))
338 ]))
339 )
340 );
341
342 assert_eq!(
343 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
344 Value::Array(
345 ArrayType::Float,
346 Some(Box::new(vec![
347 Value::Float(Some(0f32)),
348 Value::Float(Some(1.0)),
349 Value::Float(Some(2.0))
350 ]))
351 )
352 );
353
354 let hash_set: std::collections::HashSet<Value> = [
355 Into::<Value>::into(vec![0i32, 1, 2]),
356 Into::<Value>::into(vec![0i32, 1, 2]),
357 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
358 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
359 Into::<Value>::into(vec![3f32, 2.0, 1.0]),
360 ]
361 .into_iter()
362 .collect();
363
364 let unique: std::collections::HashSet<Value> = [
365 Into::<Value>::into(vec![0i32, 1, 2]),
366 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
367 Into::<Value>::into(vec![3f32, 2.0, 1.0]),
368 ]
369 .into_iter()
370 .collect();
371
372 assert_eq!(hash_set, unique);
373 }
374}