platform_value/
eq.rs

1use crate::Value;
2
3macro_rules! implpartialeq {
4    ($($t:ty),+ $(,)?) => {
5        $(
6            impl PartialEq<$t> for Value {
7                #[inline]
8                fn eq(&self, other: &$t) -> bool {
9                    if let Some(i) = self.as_integer::<$t>() {
10                        &i == other
11                    } else {
12                        false
13                    }
14                }
15            }
16
17            impl PartialEq<$t> for &Value {
18                #[inline]
19                fn eq(&self, other: &$t) -> bool {
20                    if let Some(i) = self.as_integer::<$t>() {
21                        &i == other
22                    } else {
23                        false
24                    }
25                }
26            }
27        )+
28    };
29}
30
31implpartialeq! {
32    u128,
33    u64,
34    u32,
35    u16,
36    u8,
37    i128,
38    i64,
39    i32,
40    i16,
41    i8,
42}
43
44impl PartialEq<String> for Value {
45    #[inline]
46    fn eq(&self, other: &String) -> bool {
47        if let Some(i) = self.as_text() {
48            i == other
49        } else {
50            false
51        }
52    }
53}
54
55impl PartialEq<String> for &Value {
56    #[inline]
57    fn eq(&self, other: &String) -> bool {
58        if let Some(i) = self.as_str() {
59            i == other
60        } else {
61            false
62        }
63    }
64}
65
66impl PartialEq<&str> for Value {
67    #[inline]
68    fn eq(&self, other: &&str) -> bool {
69        if let Some(i) = self.as_str() {
70            &i == other
71        } else {
72            false
73        }
74    }
75}
76
77impl PartialEq<&str> for &Value {
78    #[inline]
79    fn eq(&self, other: &&str) -> bool {
80        if let Some(i) = self.as_str() {
81            &i == other
82        } else {
83            false
84        }
85    }
86}
87
88impl PartialEq<f64> for Value {
89    #[inline]
90    fn eq(&self, other: &f64) -> bool {
91        if let Some(i) = self.as_float() {
92            &i == other
93        } else {
94            false
95        }
96    }
97}
98
99impl PartialEq<f64> for &Value {
100    #[inline]
101    fn eq(&self, other: &f64) -> bool {
102        if let Some(i) = self.as_float() {
103            &i == other
104        } else {
105            false
106        }
107    }
108}
109
110impl PartialEq<Vec<u8>> for Value {
111    #[inline]
112    fn eq(&self, other: &Vec<u8>) -> bool {
113        self.as_bytes_slice() == Ok(other.as_slice())
114    }
115}
116impl PartialEq<Vec<u8>> for &Value {
117    #[inline]
118    fn eq(&self, other: &Vec<u8>) -> bool {
119        self.as_bytes_slice() == Ok(other.as_slice())
120    }
121}
122
123macro_rules! impl_bytes_array_eq {
124    ($($n:expr),+ $(,)?) => {$(
125        impl PartialEq<[u8; $n]> for Value {
126            #[inline]
127            fn eq(&self, other: &[u8; $n]) -> bool {
128                self.as_bytes_slice() == Ok(other.as_slice())
129            }
130        }
131        impl PartialEq<[u8; $n]> for &Value {
132            #[inline]
133            fn eq(&self, other: &[u8; $n]) -> bool {
134                self.as_bytes_slice() == Ok(other.as_slice())
135            }
136        }
137    )+};
138}
139impl_bytes_array_eq! { 20, 32, 36 }
140
141impl Value {
142    /* -------------------------------------------------------- *
143     *  equality on underlying data                             *
144     * -------------------------------------------------------- */
145
146    /// Returns `true` when the *data* represented by the two `Value`s
147    /// is identical, even if they are stored in different but
148    /// compatible variants.
149    ///
150    /// * All “bytes-like” variants (`Bytes`, `Bytes20`, `Bytes32`,
151    ///   `Bytes36`, `Identifier`) compare equal when their byte
152    ///   sequences match.
153    /// * All integer variants (`U*`, `I*`) compare equal when they
154    ///   represent the same numeric value.
155    /// * Otherwise falls back to normal `==` (`PartialEq`) behaviour.
156    #[inline]
157    pub fn equal_underlying_data(&self, other: &Value) -> bool {
158        // 1) bytes-like cross-variant equality
159        if let (Ok(a), Ok(b)) = (self.as_bytes_slice(), other.as_bytes_slice()) {
160            return a == b;
161        }
162
163        // 2) integer cross-variant equality
164        if let (Some(a), Some(b)) = (self.as_i128_unified(), other.as_i128_unified()) {
165            return a == b;
166        }
167
168        // 3) default
169        self == other
170    }
171}
172
173#[cfg(test)]
174mod tests {
175    use crate::Value;
176
177    // ---- PartialEq<integer types> ----
178
179    #[test]
180    fn u8_eq() {
181        assert_eq!(Value::U8(42), 42u8);
182        assert_ne!(Value::U8(42), 43u8);
183    }
184
185    #[test]
186    fn i8_eq() {
187        assert_eq!(Value::I8(-1), -1i8);
188        assert_ne!(Value::I8(-1), 0i8);
189    }
190
191    #[test]
192    fn u16_eq() {
193        assert_eq!(Value::U16(1000), 1000u16);
194        assert_ne!(Value::U16(1000), 999u16);
195    }
196
197    #[test]
198    fn i16_eq() {
199        assert_eq!(Value::I16(-500), -500i16);
200        assert_ne!(Value::I16(-500), 500i16);
201    }
202
203    #[test]
204    fn u32_eq() {
205        assert_eq!(Value::U32(100_000), 100_000u32);
206        assert_ne!(Value::U32(100_000), 0u32);
207    }
208
209    #[test]
210    fn i32_eq() {
211        assert_eq!(Value::I32(-100), -100i32);
212        assert_ne!(Value::I32(-100), 100i32);
213    }
214
215    #[test]
216    fn u64_eq() {
217        assert_eq!(Value::U64(u64::MAX), u64::MAX);
218        assert_ne!(Value::U64(0), 1u64);
219    }
220
221    #[test]
222    fn i64_eq() {
223        assert_eq!(Value::I64(i64::MIN), i64::MIN);
224        assert_ne!(Value::I64(0), 1i64);
225    }
226
227    #[test]
228    fn u128_eq() {
229        assert_eq!(Value::U128(u128::MAX), u128::MAX);
230        assert_ne!(Value::U128(0), 1u128);
231    }
232
233    #[test]
234    fn i128_eq() {
235        assert_eq!(Value::I128(i128::MIN), i128::MIN);
236        assert_ne!(Value::I128(0), 1i128);
237    }
238
239    // ---- cross-type integer comparison via as_integer ----
240
241    #[test]
242    fn u8_value_eq_u64_type() {
243        // Value::U8(10) should equal 10u64 through as_integer
244        assert_eq!(Value::U8(10), 10u64);
245    }
246
247    #[test]
248    fn u64_value_eq_u8_type_when_fits() {
249        assert_eq!(Value::U64(200), 200u8);
250    }
251
252    #[test]
253    fn u64_value_ne_u8_type_when_overflow() {
254        // 256 doesn't fit in u8
255        assert_ne!(Value::U64(256), 0u8); // as_integer::<u8> returns None
256    }
257
258    #[test]
259    fn i8_value_eq_i64_type() {
260        assert_eq!(Value::I8(-10), -10i64);
261    }
262
263    #[test]
264    fn non_integer_ne_integer() {
265        assert_ne!(Value::Text("hello".to_string()), 0u64);
266        assert_ne!(Value::Null, 0i32);
267        assert_ne!(Value::Bool(true), 1u8);
268    }
269
270    // ---- PartialEq<String> ----
271
272    #[test]
273    fn string_eq() {
274        let val = Value::Text("hello".to_string());
275        assert_eq!(val, "hello".to_string());
276        assert_ne!(val, "world".to_string());
277    }
278
279    #[test]
280    fn non_text_ne_string() {
281        assert_ne!(Value::U8(0), "0".to_string());
282        assert_ne!(Value::Null, "".to_string());
283    }
284
285    // ---- PartialEq<&str> ----
286
287    #[test]
288    fn str_ref_eq() {
289        let val = Value::Text("test".to_string());
290        assert_eq!(val, "test");
291        assert_ne!(val, "other");
292    }
293
294    #[test]
295    fn non_text_ne_str_ref() {
296        assert_ne!(Value::Bool(false), "false");
297    }
298
299    // ---- PartialEq<f64> ----
300
301    #[test]
302    fn float_eq() {
303        assert_eq!(Value::Float(3.14), 3.14f64);
304        assert_ne!(Value::Float(3.14), 3.15f64);
305    }
306
307    #[test]
308    fn integer_eq_float_through_as_float() {
309        // as_float converts integers to f64, so Value::U64(10) == 10.0f64
310        assert_eq!(Value::U64(10), 10.0f64);
311    }
312
313    #[test]
314    fn non_numeric_ne_float() {
315        assert_ne!(Value::Text("3.14".to_string()), 3.14f64);
316    }
317
318    // ---- PartialEq<Vec<u8>> ----
319
320    #[test]
321    fn bytes_eq_vec_u8() {
322        let data = vec![1, 2, 3];
323        assert_eq!(Value::Bytes(data.clone()), data);
324    }
325
326    #[test]
327    fn bytes_ne_vec_u8() {
328        assert_ne!(Value::Bytes(vec![1, 2, 3]), vec![1, 2, 4]);
329    }
330
331    #[test]
332    fn identifier_eq_vec_u8() {
333        let id = [42u8; 32];
334        assert_eq!(Value::Identifier(id), id.to_vec());
335    }
336
337    #[test]
338    fn bytes20_eq_vec_u8() {
339        let b = [5u8; 20];
340        assert_eq!(Value::Bytes20(b), b.to_vec());
341    }
342
343    #[test]
344    fn non_bytes_ne_vec_u8() {
345        assert_ne!(Value::U8(1), vec![1u8]);
346    }
347
348    // ---- PartialEq<[u8; 32]> ----
349
350    #[test]
351    fn bytes32_eq_array() {
352        let b = [0xffu8; 32];
353        assert_eq!(Value::Bytes32(b), b);
354    }
355
356    #[test]
357    fn identifier_eq_array_32() {
358        let id = [7u8; 32];
359        assert_eq!(Value::Identifier(id), id);
360    }
361
362    #[test]
363    fn bytes_eq_array_32() {
364        let data = [3u8; 32];
365        assert_eq!(Value::Bytes(data.to_vec()), data);
366    }
367
368    #[test]
369    fn non_bytes_ne_array_32() {
370        assert_ne!(Value::Null, [0u8; 32]);
371    }
372
373    // ---- PartialEq<[u8; 20]> ----
374
375    #[test]
376    fn bytes20_eq_array_20() {
377        let b = [1u8; 20];
378        assert_eq!(Value::Bytes20(b), b);
379    }
380
381    // ---- PartialEq<[u8; 36]> ----
382
383    #[test]
384    fn bytes36_eq_array_36() {
385        let b = [2u8; 36];
386        assert_eq!(Value::Bytes36(b), b);
387    }
388
389    // ---- PartialEq for &Value ----
390
391    #[test]
392    fn ref_value_eq_integer() {
393        let val = Value::U64(42);
394        assert_eq!(&val, 42u64);
395    }
396
397    #[test]
398    fn ref_value_eq_string() {
399        let val = Value::Text("hi".to_string());
400        assert_eq!(&val, "hi".to_string());
401    }
402
403    #[test]
404    fn ref_value_eq_str_ref() {
405        let val = Value::Text("hi".to_string());
406        assert_eq!(&val, "hi");
407    }
408
409    #[test]
410    fn ref_value_eq_float() {
411        let val = Value::Float(1.0);
412        assert_eq!(&val, 1.0f64);
413    }
414
415    #[test]
416    fn ref_value_eq_vec_u8() {
417        let val = Value::Bytes(vec![10, 20]);
418        assert_eq!(&val, vec![10u8, 20]);
419    }
420
421    #[test]
422    fn ref_value_eq_array_32() {
423        let b = [0u8; 32];
424        let val = Value::Bytes32(b);
425        assert_eq!(&val, b);
426    }
427
428    // ---- equal_underlying_data tests ----
429
430    #[test]
431    fn equal_underlying_data_bytes_vs_identifier_same_data() {
432        let data = [42u8; 32];
433        let bytes = Value::Bytes(data.to_vec());
434        let ident = Value::Identifier(data);
435        assert!(bytes.equal_underlying_data(&ident));
436        assert!(ident.equal_underlying_data(&bytes));
437    }
438
439    #[test]
440    fn equal_underlying_data_bytes_vs_identifier_different_data() {
441        let bytes = Value::Bytes(vec![0u8; 32]);
442        let ident = Value::Identifier([1u8; 32]);
443        assert!(!bytes.equal_underlying_data(&ident));
444    }
445
446    #[test]
447    fn equal_underlying_data_bytes32_vs_identifier() {
448        let data = [99u8; 32];
449        let b32 = Value::Bytes32(data);
450        let ident = Value::Identifier(data);
451        assert!(b32.equal_underlying_data(&ident));
452    }
453
454    #[test]
455    fn equal_underlying_data_bytes20_vs_bytes() {
456        let data = [5u8; 20];
457        let b20 = Value::Bytes20(data);
458        let bytes = Value::Bytes(data.to_vec());
459        assert!(b20.equal_underlying_data(&bytes));
460    }
461
462    #[test]
463    fn equal_underlying_data_u8_vs_u64_same_value() {
464        let a = Value::U8(10);
465        let b = Value::U64(10);
466        assert!(a.equal_underlying_data(&b));
467    }
468
469    #[test]
470    fn equal_underlying_data_i8_vs_i128_same_value() {
471        let a = Value::I8(-5);
472        let b = Value::I128(-5);
473        assert!(a.equal_underlying_data(&b));
474    }
475
476    #[test]
477    fn equal_underlying_data_u8_vs_u64_different_value() {
478        let a = Value::U8(10);
479        let b = Value::U64(20);
480        assert!(!a.equal_underlying_data(&b));
481    }
482
483    #[test]
484    fn equal_underlying_data_u16_vs_i32_same_value() {
485        let a = Value::U16(100);
486        let b = Value::I32(100);
487        assert!(a.equal_underlying_data(&b));
488    }
489
490    #[test]
491    fn equal_underlying_data_negative_i8_vs_u64() {
492        // negative can't match unsigned
493        let a = Value::I8(-1);
494        let b = Value::U64(255);
495        assert!(!a.equal_underlying_data(&b));
496    }
497
498    #[test]
499    fn equal_underlying_data_same_variant_same_value() {
500        let a = Value::U64(42);
501        let b = Value::U64(42);
502        assert!(a.equal_underlying_data(&b));
503    }
504
505    #[test]
506    fn equal_underlying_data_fallback_to_partial_eq() {
507        // Text vs Text uses default PartialEq
508        let a = Value::Text("hello".to_string());
509        let b = Value::Text("hello".to_string());
510        assert!(a.equal_underlying_data(&b));
511
512        let c = Value::Text("world".to_string());
513        assert!(!a.equal_underlying_data(&c));
514    }
515
516    #[test]
517    fn equal_underlying_data_null_vs_null() {
518        assert!(Value::Null.equal_underlying_data(&Value::Null));
519    }
520
521    #[test]
522    fn equal_underlying_data_different_types_not_equal() {
523        // A string vs a number should not be equal
524        let a = Value::Text("42".to_string());
525        let b = Value::U64(42);
526        assert!(!a.equal_underlying_data(&b));
527    }
528
529    #[test]
530    fn equal_underlying_data_bool_vs_bool() {
531        assert!(Value::Bool(true).equal_underlying_data(&Value::Bool(true)));
532        assert!(!Value::Bool(true).equal_underlying_data(&Value::Bool(false)));
533    }
534
535    #[test]
536    fn equal_underlying_data_float_vs_float() {
537        assert!(Value::Float(1.5).equal_underlying_data(&Value::Float(1.5)));
538        assert!(!Value::Float(1.5).equal_underlying_data(&Value::Float(2.5)));
539    }
540}