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