Skip to main content

qubit_value/value/
value_identity.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Equality and hashing for [`super::Value`].
9
10use std::hash::{
11    Hash,
12    Hasher,
13};
14
15use super::{
16    Value,
17    ValueRepr,
18};
19#[cfg(feature = "big-decimal")]
20use crate::identity::hash_big_decimal;
21use crate::identity::{
22    canonical_f32_bits,
23    canonical_f64_bits,
24    hash_string_map,
25};
26#[cfg(feature = "json")]
27use crate::identity::{
28    hash_json,
29    json_eq,
30};
31
32macro_rules! payload_eq {
33    (Float32, $left:expr, $right:expr) => {
34        canonical_f32_bits(*$left) == canonical_f32_bits(*$right)
35    };
36    (Float64, $left:expr, $right:expr) => {
37        canonical_f64_bits(*$left) == canonical_f64_bits(*$right)
38    };
39    (Json, $left:expr, $right:expr) => {
40        json_eq($left, $right)
41    };
42    ($variant:ident, $left:expr, $right:expr) => {
43        $left == $right
44    };
45}
46
47macro_rules! hash_payload {
48    (Float32, $value:expr, $state:expr) => {
49        canonical_f32_bits(*$value).hash($state)
50    };
51    (Float64, $value:expr, $state:expr) => {
52        canonical_f64_bits(*$value).hash($state)
53    };
54    (BigDecimal, $value:expr, $state:expr) => {
55        hash_big_decimal($value, $state)
56    };
57    (StringMap, $value:expr, $state:expr) => {
58        hash_string_map($value, $state)
59    };
60    (Json, $value:expr, $state:expr) => {
61        hash_json($value, $state)
62    };
63    ($variant:ident, $value:expr, $state:expr) => {
64        $value.hash($state)
65    };
66}
67
68macro_rules! impl_value_identity {
69    (
70        ;
71        $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal)),+ $(,)?
72    ) => {
73        impl PartialEq for Value {
74            fn eq(&self, other: &Self) -> bool {
75                match (&self.repr, &other.repr) {
76                    (ValueRepr::Unset(left), ValueRepr::Unset(right)) => left == right,
77                    $($(#[$cfg])*
78                    (ValueRepr::$variant(left), ValueRepr::$variant(right)) => {
79                        payload_eq!($variant, left, right)
80                    },)+
81                    _ => false,
82                }
83            }
84        }
85
86        impl Eq for Value {}
87
88        impl Hash for Value {
89            fn hash<H: Hasher>(&self, state: &mut H) {
90                std::mem::discriminant(&self.repr).hash(state);
91                match &self.repr {
92                    ValueRepr::Unset(data_type) => data_type.hash(state),
93                    $($(#[$cfg])*
94                    ValueRepr::$variant(value) => hash_payload!($variant, value, state),)+
95                }
96            }
97        }
98    };
99}
100
101for_each_value_type!(impl_value_identity);