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
61 #[cfg(feature = "with-uuid")]
62 (Self::Uuid(l), Self::Uuid(r)) => l == r,
63
64 #[cfg(feature = "with-rust_decimal")]
65 (Self::Decimal(l), Self::Decimal(r)) => l == r,
66
67 #[cfg(feature = "with-bigdecimal")]
68 (Self::BigDecimal(l), Self::BigDecimal(r)) => l == r,
69
70 #[cfg(feature = "postgres-array")]
71 (Self::Array(ty_l, values_l), Self::Array(ty_r, values_r)) => {
72 ty_l == ty_r && values_l == values_r
73 }
74
75 #[cfg(feature = "postgres-vector")]
76 (Self::Vector(l), Self::Vector(r)) => cmp_vector(l, r),
77
78 #[cfg(feature = "with-ipnetwork")]
79 (Self::IpNetwork(l), Self::IpNetwork(r)) => l == r,
80
81 #[cfg(feature = "with-mac_address")]
82 (Self::MacAddress(l), Self::MacAddress(r)) => l == r,
83
84 _ => false,
85 }
86 }
87}
88
89impl Eq for Value {}
90
91impl Hash for Value {
92 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
93 mem::discriminant(self).hash(state);
94 match self {
95 Value::Bool(v) => v.hash(state),
96 Value::TinyInt(v) => v.hash(state),
97 Value::SmallInt(v) => v.hash(state),
98 Value::Int(v) => v.hash(state),
99 Value::BigInt(v) => v.hash(state),
100 Value::TinyUnsigned(v) => v.hash(state),
101 Value::SmallUnsigned(v) => v.hash(state),
102 Value::Unsigned(v) => v.hash(state),
103 Value::BigUnsigned(v) => v.hash(state),
104 Value::Float(v) => hash_f32(v, state),
105 Value::Double(v) => hash_f64(v, state),
106 Value::String(v) => v.hash(state),
107 Value::Enum(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
145 #[cfg(feature = "with-uuid")]
146 Value::Uuid(uuid) => uuid.hash(state),
147
148 #[cfg(feature = "with-rust_decimal")]
149 Value::Decimal(decimal) => decimal.hash(state),
150
151 #[cfg(feature = "with-bigdecimal")]
152 Value::BigDecimal(big_decimal) => big_decimal.hash(state),
153
154 #[cfg(feature = "postgres-array")]
155 Value::Array(array_type, vec) => {
156 array_type.hash(state);
157 vec.hash(state);
158 }
159
160 #[cfg(feature = "postgres-vector")]
161 Value::Vector(vector) => hash_vector(vector, state),
162
163 #[cfg(feature = "with-ipnetwork")]
164 Value::IpNetwork(ip_network) => ip_network.hash(state),
165
166 #[cfg(feature = "with-mac_address")]
167 Value::MacAddress(mac_address) => mac_address.hash(state),
168
169 #[cfg(feature = "postgres-range")]
170 Value::Range(range) => range.hash(state),
171 }
172 }
173}
174
175fn hash_f32<H: Hasher>(v: &Option<f32>, state: &mut H) {
176 match v {
177 Some(v) => OrderedFloat(*v).hash(state),
178 None => "null".hash(state),
179 }
180}
181
182fn hash_f64<H: Hasher>(v: &Option<f64>, state: &mut H) {
183 match v {
184 Some(v) => OrderedFloat(*v).hash(state),
185 None => "null".hash(state),
186 }
187}
188
189fn cmp_f32(l: &Option<f32>, r: &Option<f32>) -> bool {
190 match (l, r) {
191 (Some(l), Some(r)) => OrderedFloat(*l).eq(&OrderedFloat(*r)),
192 (None, None) => true,
193 _ => false,
194 }
195}
196
197fn cmp_f64(l: &Option<f64>, r: &Option<f64>) -> bool {
198 match (l, r) {
199 (Some(l), Some(r)) => OrderedFloat(*l).eq(&OrderedFloat(*r)),
200 (None, None) => true,
201 _ => false,
202 }
203}
204
205#[cfg(feature = "with-json")]
206fn hash_json<H: Hasher>(v: &Option<Box<Json>>, state: &mut H) {
207 match v {
208 Some(v) => serde_json::to_string(v).unwrap().hash(state),
209 None => "null".hash(state),
210 }
211}
212
213#[cfg(feature = "with-json")]
214fn cmp_json(l: &Option<Box<Json>>, r: &Option<Box<Json>>) -> bool {
215 match (l, r) {
216 (Some(l), Some(r)) => serde_json::to_string(l)
217 .unwrap()
218 .eq(&serde_json::to_string(r).unwrap()),
219 (None, None) => true,
220 _ => false,
221 }
222}
223
224#[cfg(feature = "postgres-vector")]
225fn hash_vector<H: Hasher>(v: &Option<pgvector::Vector>, state: &mut H) {
226 match v {
227 Some(v) => {
228 for &value in v.as_slice().iter() {
229 hash_f32(&Some(value), state);
230 }
231 }
232 None => "null".hash(state),
233 }
234}
235
236#[cfg(feature = "postgres-vector")]
237fn cmp_vector(l: &Option<pgvector::Vector>, r: &Option<pgvector::Vector>) -> bool {
238 match (l, r) {
239 (Some(l), Some(r)) => {
240 let (l, r) = (l.as_slice(), r.as_slice());
241 if l.len() != r.len() {
242 return false;
243 }
244 for (l, r) in l.iter().zip(r.iter()) {
245 if !cmp_f32(&Some(*l), &Some(*r)) {
246 return false;
247 }
248 }
249 true
250 }
251 (None, None) => true,
252 _ => false,
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use crate::Value;
259 #[test]
260 fn test_hash_value_0() {
261 let hash_set: std::collections::HashSet<Value> = [
262 Value::Int(None),
263 Value::Int(None),
264 Value::BigInt(None),
265 Value::BigInt(None),
266 Value::Float(None),
267 Value::Float(None), Value::Float(Some(f32::NAN)), Value::Float(Some(f32::NAN)),
270 Value::Double(None),
271 Value::Double(None),
272 Value::Double(Some(f64::NAN)),
273 Value::Double(Some(f64::NAN)),
274 ]
275 .into_iter()
276 .collect();
277
278 let unique: std::collections::HashSet<Value> = [
279 Value::Int(None),
280 Value::BigInt(None),
281 Value::Float(None),
282 Value::Double(None),
283 Value::Float(Some(f32::NAN)),
284 Value::Double(Some(f64::NAN)),
285 ]
286 .into_iter()
287 .collect();
288
289 assert_eq!(hash_set, unique);
290 }
291
292 #[test]
293 fn test_hash_value_1() {
294 let hash_set: std::collections::HashSet<Value> = [
295 Value::Int(None),
296 Value::Int(Some(1)),
297 Value::Int(Some(1)),
298 Value::BigInt(Some(2)),
299 Value::BigInt(Some(2)),
300 Value::Float(Some(3.0)),
301 Value::Float(Some(3.0)),
302 Value::Double(Some(3.0)),
303 Value::Double(Some(3.0)),
304 Value::BigInt(Some(5)),
305 ]
306 .into_iter()
307 .collect();
308
309 let unique: std::collections::HashSet<Value> = [
310 Value::BigInt(Some(5)),
311 Value::Double(Some(3.0)),
312 Value::Float(Some(3.0)),
313 Value::BigInt(Some(2)),
314 Value::Int(Some(1)),
315 Value::Int(None),
316 ]
317 .into_iter()
318 .collect();
319
320 assert_eq!(hash_set, unique);
321 }
322
323 #[cfg(feature = "postgres-array")]
324 #[test]
325 fn test_hash_value_array() {
326 use crate::ArrayType;
327
328 assert_eq!(
329 Into::<Value>::into(vec![0i32, 1, 2]),
330 Value::Array(
331 ArrayType::Int,
332 Some(Box::new(vec![
333 Value::Int(Some(0)),
334 Value::Int(Some(1)),
335 Value::Int(Some(2))
336 ]))
337 )
338 );
339
340 assert_eq!(
341 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
342 Value::Array(
343 ArrayType::Float,
344 Some(Box::new(vec![
345 Value::Float(Some(0f32)),
346 Value::Float(Some(1.0)),
347 Value::Float(Some(2.0))
348 ]))
349 )
350 );
351
352 let hash_set: std::collections::HashSet<Value> = [
353 Into::<Value>::into(vec![0i32, 1, 2]),
354 Into::<Value>::into(vec![0i32, 1, 2]),
355 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
356 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
357 Into::<Value>::into(vec![3f32, 2.0, 1.0]),
358 ]
359 .into_iter()
360 .collect();
361
362 let unique: std::collections::HashSet<Value> = [
363 Into::<Value>::into(vec![0i32, 1, 2]),
364 Into::<Value>::into(vec![0f32, 1.0, 2.0]),
365 Into::<Value>::into(vec![3f32, 2.0, 1.0]),
366 ]
367 .into_iter()
368 .collect();
369
370 assert_eq!(hash_set, unique);
371 }
372}