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 }
172}
173
174fn hash_f32<H: Hasher>(v: &Option<f32>, state: &mut H) {
175 match v {
176 Some(v) => OrderedFloat(*v).hash(state),
177 None => "null".hash(state),
178 }
179}
180
181fn hash_f64<H: Hasher>(v: &Option<f64>, state: &mut H) {
182 match v {
183 Some(v) => OrderedFloat(*v).hash(state),
184 None => "null".hash(state),
185 }
186}
187
188fn cmp_f32(l: &Option<f32>, r: &Option<f32>) -> bool {
189 match (l, r) {
190 (Some(l), Some(r)) => OrderedFloat(*l).eq(&OrderedFloat(*r)),
191 (None, None) => true,
192 _ => false,
193 }
194}
195
196fn cmp_f64(l: &Option<f64>, r: &Option<f64>) -> bool {
197 match (l, r) {
198 (Some(l), Some(r)) => OrderedFloat(*l).eq(&OrderedFloat(*r)),
199 (None, None) => true,
200 _ => false,
201 }
202}
203
204#[cfg(feature = "with-json")]
205fn hash_json<H: Hasher>(v: &Option<Json>, state: &mut H) {
206 match v {
207 Some(v) => serde_json::to_string(v).unwrap().hash(state),
208 None => "null".hash(state),
209 }
210}
211
212#[cfg(feature = "with-json")]
213fn cmp_json(l: &Option<Json>, r: &Option<Json>) -> bool {
214 match (l, r) {
215 (Some(l), Some(r)) => serde_json::to_string(l)
216 .unwrap()
217 .eq(&serde_json::to_string(r).unwrap()),
218 (None, None) => true,
219 _ => false,
220 }
221}
222
223#[cfg(feature = "postgres-vector")]
224fn hash_vector<H: Hasher>(v: &Option<pgvector::Vector>, state: &mut H) {
225 match v {
226 Some(v) => {
227 for &value in v.as_slice().iter() {
228 hash_f32(&Some(value), state);
229 }
230 }
231 None => "null".hash(state),
232 }
233}
234
235#[cfg(feature = "postgres-vector")]
236fn cmp_vector(l: &Option<pgvector::Vector>, r: &Option<pgvector::Vector>) -> bool {
237 match (l, r) {
238 (Some(l), Some(r)) => {
239 let (l, r) = (l.as_slice(), r.as_slice());
240 if l.len() != r.len() {
241 return false;
242 }
243 for (l, r) in l.iter().zip(r.iter()) {
244 if !cmp_f32(&Some(*l), &Some(*r)) {
245 return false;
246 }
247 }
248 true
249 }
250 (None, None) => true,
251 _ => false,
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use crate::Value;
258 #[test]
259 fn test_hash_value_0() {
260 let hash_set: std::collections::HashSet<Value> = [
261 Value::Int(None),
262 Value::Int(None),
263 Value::BigInt(None),
264 Value::BigInt(None),
265 Value::Float(None),
266 Value::Float(None), Value::Float(Some(f32::NAN)), Value::Float(Some(f32::NAN)),
269 Value::Double(None),
270 Value::Double(None),
271 Value::Double(Some(f64::NAN)),
272 Value::Double(Some(f64::NAN)),
273 ]
274 .into_iter()
275 .collect();
276
277 let unique: std::collections::HashSet<Value> = [
278 Value::Int(None),
279 Value::BigInt(None),
280 Value::Float(None),
281 Value::Double(None),
282 Value::Float(Some(f32::NAN)),
283 Value::Double(Some(f64::NAN)),
284 ]
285 .into_iter()
286 .collect();
287
288 assert_eq!(hash_set, unique);
289 }
290
291 #[test]
292 fn test_hash_value_1() {
293 let hash_set: std::collections::HashSet<Value> = [
294 Value::Int(None),
295 Value::Int(Some(1)),
296 Value::Int(Some(1)),
297 Value::BigInt(Some(2)),
298 Value::BigInt(Some(2)),
299 Value::Float(Some(3.0)),
300 Value::Float(Some(3.0)),
301 Value::Double(Some(3.0)),
302 Value::Double(Some(3.0)),
303 Value::BigInt(Some(5)),
304 ]
305 .into_iter()
306 .collect();
307
308 let unique: std::collections::HashSet<Value> = [
309 Value::BigInt(Some(5)),
310 Value::Double(Some(3.0)),
311 Value::Float(Some(3.0)),
312 Value::BigInt(Some(2)),
313 Value::Int(Some(1)),
314 Value::Int(None),
315 ]
316 .into_iter()
317 .collect();
318
319 assert_eq!(hash_set, unique);
320 }
321
322 #[cfg(feature = "postgres-array")]
323 #[test]
324 fn test_hash_value_array() {
325 use crate::ArrayType;
326
327 assert_eq!(
328 Into::<Value>::into(vec![0i32, 1, 2]),
329 Value::Array(
330 ArrayType::Int,
331 Some(Box::new(vec![
332 Value::Int(Some(0)),
333 Value::Int(Some(1)),
334 Value::Int(Some(2))
335 ]))
336 )
337 );
338
339 assert_eq!(
340 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
341 Value::Array(
342 ArrayType::Float,
343 Some(Box::new(vec![
344 Value::Float(Some(0f32)),
345 Value::Float(Some(1.0)),
346 Value::Float(Some(2.0))
347 ]))
348 )
349 );
350
351 let hash_set: std::collections::HashSet<Value> = [
352 Into::<Value>::into(vec![0i32, 1, 2]),
353 Into::<Value>::into(vec![0i32, 1, 2]),
354 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
355 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
356 Into::<Value>::into(vec![3f32, 2.0, 1.0]),
357 ]
358 .into_iter()
359 .collect();
360
361 let unique: std::collections::HashSet<Value> = [
362 Into::<Value>::into(vec![0i32, 1, 2]),
363 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
364 Into::<Value>::into(vec![3f32, 2.0, 1.0]),
365 ]
366 .into_iter()
367 .collect();
368
369 assert_eq!(hash_set, unique);
370 }
371}