Skip to main content

qubit_value/multi_values/
multi_values_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::MultiValues`].
9
10use std::hash::{
11    Hash,
12    Hasher,
13};
14
15use super::multi_values::{
16    MultiValues,
17    MultiValuesRepr,
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
32/// Compares ordered payloads using the identity rule for their element type.
33macro_rules! payloads_eq {
34    (Float32, $left:expr, $right:expr) => {
35        $left.len() == $right.len()
36            && $left.iter().zip($right).all(|(left, right)| {
37                canonical_f32_bits(*left) == canonical_f32_bits(*right)
38            })
39    };
40    (Float64, $left:expr, $right:expr) => {
41        $left.len() == $right.len()
42            && $left.iter().zip($right).all(|(left, right)| {
43                canonical_f64_bits(*left) == canonical_f64_bits(*right)
44            })
45    };
46    (Json, $left:expr, $right:expr) => {
47        $left.len() == $right.len()
48            && $left
49                .iter()
50                .zip($right)
51                .all(|(left, right)| json_eq(left, right))
52    };
53    ($variant:ident, $left:expr, $right:expr) => {
54        $left == $right
55    };
56}
57
58/// Hashes ordered payloads using the identity rule for their element type.
59macro_rules! hash_payloads {
60    (Float32, $values:expr, $state:expr) => {{
61        $values.len().hash($state);
62        for value in $values {
63            canonical_f32_bits(*value).hash($state);
64        }
65    }};
66    (Float64, $values:expr, $state:expr) => {{
67        $values.len().hash($state);
68        for value in $values {
69            canonical_f64_bits(*value).hash($state);
70        }
71    }};
72    (BigDecimal, $values:expr, $state:expr) => {{
73        $values.len().hash($state);
74        for value in $values {
75            hash_big_decimal(value, $state);
76        }
77    }};
78    (StringMap, $values:expr, $state:expr) => {{
79        $values.len().hash($state);
80        for value in $values {
81            hash_string_map(value, $state);
82        }
83    }};
84    (Json, $values:expr, $state:expr) => {{
85        $values.len().hash($state);
86        for value in $values {
87            hash_json(value, $state);
88        }
89    }};
90    ($variant:ident, $values:expr, $state:expr) => {
91        $values.hash($state)
92    };
93}
94
95/// Implements lawful equality and hashing for the complete value-type table.
96macro_rules! impl_multi_values_identity {
97    (
98        ;
99        $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal)),+ $(,)?
100    ) => {
101        impl PartialEq for MultiValues {
102            fn eq(&self, other: &Self) -> bool {
103                match (&self.repr, &other.repr) {
104                    (MultiValuesRepr::Unset(left), MultiValuesRepr::Unset(right)) => left == right,
105                    $($(#[$cfg])*
106                    (MultiValuesRepr::$variant(left), MultiValuesRepr::$variant(right)) => {
107                        payloads_eq!($variant, left, right)
108                    },)+
109                    _ => false,
110                }
111            }
112        }
113
114        impl Eq for MultiValues {}
115
116        impl Hash for MultiValues {
117            fn hash<H: Hasher>(&self, state: &mut H) {
118                std::mem::discriminant(&self.repr).hash(state);
119                match &self.repr {
120                    MultiValuesRepr::Unset(data_type) => data_type.hash(state),
121                    $($(#[$cfg])*
122                    MultiValuesRepr::$variant(values) => {
123                        hash_payloads!($variant, values, state)
124                    },)+
125                }
126            }
127        }
128    };
129}
130
131for_each_value_type!(impl_multi_values_identity);