1use std::hash::Hash;
11use std::hash::Hasher;
12
13#[cfg(feature = "json")]
14use qubit_budget::MeasuredBudgetError;
15#[cfg(feature = "json")]
16use qubit_budget::ResourceQuantity;
17#[cfg(feature = "json")]
18use qubit_budget::json::JsonValueBudget;
19
20use super::Value;
21use super::ValueRepr;
22use crate::identity::canonical_f32_bits;
23use crate::identity::canonical_f64_bits;
24#[cfg(feature = "big-decimal")]
25use crate::identity::hash_big_decimal;
26#[cfg(feature = "json")]
27use crate::identity::hash_json;
28use crate::identity::hash_string_map;
29#[cfg(feature = "json")]
30use crate::identity::json_eq;
31
32macro_rules! payload_eq {
34 (Float32, $left:expr, $right:expr) => {
35 canonical_f32_bits(*$left) == canonical_f32_bits(*$right)
36 };
37 (Float64, $left:expr, $right:expr) => {
38 canonical_f64_bits(*$left) == canonical_f64_bits(*$right)
39 };
40 (Json, $left:expr, $right:expr) => {
41 json_eq($left, $right)
42 };
43 ($variant:ident, $left:expr, $right:expr) => {
44 $left == $right
45 };
46}
47
48macro_rules! hash_payload {
50 (Float32, $value:expr, $state:expr) => {
51 canonical_f32_bits(*$value).hash($state)
52 };
53 (Float64, $value:expr, $state:expr) => {
54 canonical_f64_bits(*$value).hash($state)
55 };
56 (BigDecimal, $value:expr, $state:expr) => {
57 hash_big_decimal($value, $state)
58 };
59 (StringMap, $value:expr, $state:expr) => {
60 hash_string_map($value, $state)
61 };
62 (Json, $value:expr, $state:expr) => {
63 hash_json($value, $state)
64 };
65 ($variant:ident, $value:expr, $state:expr) => {
66 $value.hash($state)
67 };
68}
69
70#[cfg(feature = "json")]
72macro_rules! budgeted_hash_payload {
73 (Json, $value:expr, $state:expr) => {{
74 let _ = $value;
75 unreachable!("JSON payload hashing is handled by Value::hash_with_json_budget")
76 }};
77 ($variant:ident, $value:expr, $state:expr) => {
78 hash_payload!($variant, $value, $state)
79 };
80}
81
82#[cfg(feature = "json")]
84macro_rules! budgeted_payload_match {
85 ($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)*)),+ $(,)?) => {
86 match $repr {
87 ValueRepr::Unset(data_type) => data_type.hash($state),
88 $($(#[$cfg])* ValueRepr::$variant(value) => {
89 budgeted_hash_payload!($variant, value, $state)
90 },)+
91 }
92 };
93}
94
95#[cfg(feature = "json")]
119pub(crate) fn hash_value_payload_with_json_budget<H, R, Q>(
120 repr: &ValueRepr,
121 state: &mut H,
122 _budget: &mut JsonValueBudget<R, Q>,
123) -> Result<(), MeasuredBudgetError<R, Q>>
124where
125 H: Hasher,
126 R: Clone,
127 Q: ResourceQuantity,
128{
129 for_each_value_type!(budgeted_payload_match, repr, state);
130 Ok(())
131}
132
133macro_rules! impl_value_identity {
135 (
136 ;
137 $(([$($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)*)),+ $(,)?
138 ) => {
139 impl PartialEq for Value {
140 fn eq(&self, other: &Self) -> bool {
141 match (&self.repr, &other.repr) {
142 (ValueRepr::Unset(left), ValueRepr::Unset(right)) => left == right,
143 $($(#[$cfg])*
144 (ValueRepr::$variant(left), ValueRepr::$variant(right)) => {
145 payload_eq!($variant, left, right)
146 },)+
147 _ => false,
148 }
149 }
150 }
151
152 impl Eq for Value {}
153
154 impl Hash for Value {
155 fn hash<H: Hasher>(&self, state: &mut H) {
156 std::mem::discriminant(&self.repr).hash(state);
157 match &self.repr {
158 ValueRepr::Unset(data_type) => data_type.hash(state),
159 $($(#[$cfg])*
160 ValueRepr::$variant(value) => hash_payload!($variant, value, state),)+
161 }
162 }
163 }
164 };
165}
166
167for_each_value_type!(impl_value_identity);