qubit_value/value/
value_identity.rs1use std::hash::Hash;
11use std::hash::Hasher;
12use std::mem::discriminant;
13
14use super::Value;
15use super::ValueRepr;
16use crate::identity::canonical_f32_bits;
17use crate::identity::canonical_f64_bits;
18#[cfg(feature = "big-decimal")]
19use crate::identity::hash_big_decimal;
20#[cfg(feature = "json")]
21use crate::identity::hash_json;
22use crate::identity::hash_string_map;
23#[cfg(feature = "json")]
24use crate::identity::json_eq;
25
26macro_rules! payload_eq {
28 (Float32, $left:expr, $right:expr) => {
29 canonical_f32_bits(*$left) == canonical_f32_bits(*$right)
30 };
31 (Float64, $left:expr, $right:expr) => {
32 canonical_f64_bits(*$left) == canonical_f64_bits(*$right)
33 };
34 (Json, $left:expr, $right:expr) => {
35 json_eq($left, $right)
36 };
37 ($variant:ident, $left:expr, $right:expr) => {
38 $left == $right
39 };
40}
41
42macro_rules! hash_payload {
44 (Float32, $value:expr, $state:expr) => {
45 canonical_f32_bits(*$value).hash($state)
46 };
47 (Float64, $value:expr, $state:expr) => {
48 canonical_f64_bits(*$value).hash($state)
49 };
50 (BigDecimal, $value:expr, $state:expr) => {
51 hash_big_decimal($value, $state)
52 };
53 (StringMap, $value:expr, $state:expr) => {
54 hash_string_map($value, $state)
55 };
56 (Json, $value:expr, $state:expr) => {
57 hash_json($value, $state)
58 };
59 ($variant:ident, $value:expr, $state:expr) => {
60 $value.hash($state)
61 };
62}
63
64#[cfg(feature = "json")]
66macro_rules! non_json_hash_payload {
67 (Json, $value:expr, $state:expr) => {{
68 let _ = $value;
69 unreachable!("JSON payload hashing is handled by Value::hash_with_json_budget")
70 }};
71 ($variant:ident, $value:expr, $state:expr) => {
72 hash_payload!($variant, $value, $state)
73 };
74}
75
76#[cfg(feature = "json")]
78macro_rules! non_json_payload_match {
79 ($repr:expr, $state:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
80 match $repr {
81 ValueRepr::Unset(data_type) => data_type.hash($state),
82 $($(#[$cfg])* ValueRepr::$variant(value) => {
83 non_json_hash_payload!($variant, value, $state)
84 },)+
85 }
86 };
87}
88
89#[cfg(feature = "json")]
108pub(crate) fn hash_non_json_value_payload<H: Hasher>(repr: &ValueRepr, state: &mut H) {
109 for_each_value_type!(non_json_payload_match, repr, state);
110}
111
112macro_rules! impl_value_identity {
114 (
115 ;
116 $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?
117 ) => {
118 impl PartialEq for Value {
119 fn eq(&self, other: &Self) -> bool {
130 match (&self.repr, &other.repr) {
131 (ValueRepr::Unset(left), ValueRepr::Unset(right)) => left == right,
132 $($(#[$cfg])*
133 (ValueRepr::$variant(left), ValueRepr::$variant(right)) => {
134 payload_eq!($variant, left, right)
135 },)+
136 _ => false,
137 }
138 }
139 }
140
141 impl Eq for Value {}
142
143 impl Hash for Value {
144 fn hash<H: Hasher>(&self, state: &mut H) {
154 discriminant(&self.repr).hash(state);
155 match &self.repr {
156 ValueRepr::Unset(data_type) => data_type.hash(state),
157 $($(#[$cfg])*
158 ValueRepr::$variant(value) => hash_payload!($variant, value, state),)+
159 }
160 }
161 }
162 };
163}
164
165for_each_value_type!(impl_value_identity);