@@ -8,22 +8,22 @@ use crate::ast::selection_set::{FieldSelection, InlineFragmentSelection, Selecti
88use crate :: ast:: value:: Value ;
99use crate :: state:: supergraph_state:: { self , OperationKind , TypeNode } ;
1010
11- /// Order -dependent hashing
11+ /// A trait for hashing AST nodes, with support for both order -dependent and order-independent hashing.
1212pub trait ASTHash {
13- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) ;
13+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) ;
1414}
1515
1616pub fn ast_hash ( query : & OperationDefinition ) -> u64 {
1717 let mut hasher = FxHasher :: default ( ) ;
18- query. ast_hash ( & mut hasher) ;
18+ query. ast_hash :: < _ , false > ( & mut hasher) ;
1919 hasher. finish ( )
2020}
2121// In all ShapeHash implementations, we never include anything to do with
2222// the position of the element in the query, i.e., fields that involve
2323// `Pos`
2424
2525impl ASTHash for & OperationKind {
26- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
26+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
2727 match self {
2828 OperationKind :: Query => "Query" . hash ( hasher) ,
2929 OperationKind :: Mutation => "Mutation" . hash ( hasher) ,
@@ -33,55 +33,72 @@ impl ASTHash for &OperationKind {
3333}
3434
3535impl ASTHash for OperationDefinition {
36- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
36+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
3737 self . operation_kind
3838 . as_ref ( )
3939 . or ( Some ( & supergraph_state:: OperationKind :: Query ) )
40- . ast_hash ( hasher) ;
40+ . ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
4141
42- self . selection_set . ast_hash ( hasher) ;
43- self . variable_definitions . ast_hash ( hasher) ;
42+ self . selection_set . ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
43+ self . variable_definitions
44+ . ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
4445 }
4546}
4647
4748impl < T : ASTHash > ASTHash for Option < T > {
48- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
49+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
4950 match self {
5051 None => false . hash ( hasher) ,
5152 Some ( t) => {
5253 Some ( true ) . hash ( hasher) ;
53- t. ast_hash ( hasher) ;
54+ t. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
5455 }
5556 }
5657 }
5758}
5859
5960impl ASTHash for SelectionSet {
60- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
61- for item in & self . items {
62- item. ast_hash ( hasher) ;
61+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
62+ if ORDER_INDEPENDENT {
63+ let mut combined_hash: u64 = 0 ;
64+ let build_hasher = FxBuildHasher ;
65+
66+ // To achieve an order-independent hash, we hash each key-value pair
67+ // individually and then combine their hashes using XOR (^).
68+ // Since XOR is commutative, the final hash is not affected by the iteration order.
69+ for item in & self . items {
70+ let mut key_val_hasher = build_hasher. build_hasher ( ) ;
71+ item. ast_hash :: < _ , ORDER_INDEPENDENT > ( & mut key_val_hasher) ;
72+ combined_hash ^= key_val_hasher. finish ( ) ;
73+ }
74+
75+ hasher. write_u64 ( combined_hash) ;
76+ } else {
77+ for item in & self . items {
78+ item. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
79+ }
6380 }
6481 }
6582}
6683
6784impl ASTHash for SelectionItem {
68- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
85+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
6986 match self {
70- SelectionItem :: Field ( field) => field. ast_hash ( hasher) ,
71- SelectionItem :: InlineFragment ( frag) => frag. ast_hash ( hasher) ,
87+ SelectionItem :: Field ( field) => field. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ,
88+ SelectionItem :: InlineFragment ( frag) => frag. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ,
7289 SelectionItem :: FragmentSpread ( name) => name. hash ( hasher) ,
7390 }
7491 }
7592}
7693
7794impl ASTHash for & FieldSelection {
78- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
95+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
7996 self . name . hash ( hasher) ;
8097 self . alias . hash ( hasher) ;
81- self . selections . ast_hash ( hasher) ;
98+ self . selections . ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
8299
83100 if let Some ( args) = & self . arguments {
84- args. ast_hash ( hasher) ;
101+ args. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
85102 }
86103
87104 if let Some ( var_name) = self . include_if . as_ref ( ) {
@@ -96,9 +113,9 @@ impl ASTHash for &FieldSelection {
96113}
97114
98115impl ASTHash for & InlineFragmentSelection {
99- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
116+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
100117 self . type_condition . hash ( hasher) ;
101- self . selections . ast_hash ( hasher) ;
118+ self . selections . ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
102119 if let Some ( var_name) = self . include_if . as_ref ( ) {
103120 "@include" . hash ( hasher) ;
104121 var_name. hash ( hasher) ;
@@ -111,7 +128,7 @@ impl ASTHash for &InlineFragmentSelection {
111128}
112129
113130impl ASTHash for ArgumentsMap {
114- fn ast_hash < H : Hasher > ( & self , state : & mut H ) {
131+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , state : & mut H ) {
115132 let mut combined_hash: u64 = 0 ;
116133 let build_hasher = FxBuildHasher ;
117134
@@ -121,7 +138,7 @@ impl ASTHash for ArgumentsMap {
121138 for ( key, value) in self . into_iter ( ) {
122139 let mut key_val_hasher = build_hasher. build_hasher ( ) ;
123140 key. hash ( & mut key_val_hasher) ;
124- value. ast_hash ( & mut key_val_hasher) ;
141+ value. ast_hash :: < _ , ORDER_INDEPENDENT > ( & mut key_val_hasher) ;
125142 combined_hash ^= key_val_hasher. finish ( ) ;
126143 }
127144
@@ -130,15 +147,15 @@ impl ASTHash for ArgumentsMap {
130147}
131148
132149impl ASTHash for Vec < VariableDefinition > {
133- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
150+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
134151 let mut combined_hash: u64 = 0 ;
135152 let build_hasher = FxBuildHasher ;
136153 // To achieve an order-independent hash, we hash each key-value pair
137154 // individually and then combine their hashes using XOR (^).
138155 // Since XOR is commutative, the final hash is not affected by the iteration order.
139156 for variable in self . iter ( ) {
140157 let mut local_hasher = build_hasher. build_hasher ( ) ;
141- variable. ast_hash ( & mut local_hasher) ;
158+ variable. ast_hash :: < _ , ORDER_INDEPENDENT > ( & mut local_hasher) ;
142159 combined_hash ^= local_hasher. finish ( ) ;
143160 }
144161
@@ -147,41 +164,41 @@ impl ASTHash for Vec<VariableDefinition> {
147164}
148165
149166impl ASTHash for VariableDefinition {
150- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
167+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
151168 self . name . hash ( hasher) ;
152- self . variable_type . ast_hash ( hasher) ;
153- self . default_value . ast_hash ( hasher) ;
169+ self . variable_type . ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
170+ self . default_value . ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
154171 }
155172}
156173
157174impl ASTHash for TypeNode {
158- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
175+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
159176 match self {
160177 TypeNode :: Named ( name) => name. hash ( hasher) ,
161178 TypeNode :: List ( inner) => {
162179 "list" . hash ( hasher) ;
163- inner. ast_hash ( hasher) ;
180+ inner. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
164181 }
165182 TypeNode :: NonNull ( inner) => {
166183 "non_null" . hash ( hasher) ;
167- inner. ast_hash ( hasher) ;
184+ inner. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
168185 }
169186 }
170187 }
171188}
172189
173190impl ASTHash for Value {
174- fn ast_hash < H : Hasher > ( & self , hasher : & mut H ) {
191+ fn ast_hash < H : Hasher , const ORDER_INDEPENDENT : bool > ( & self , hasher : & mut H ) {
175192 match self {
176193 Value :: List ( values) => {
177194 for value in values {
178- value. ast_hash ( hasher) ;
195+ value. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
179196 }
180197 }
181198 Value :: Object ( map) => {
182199 for ( name, value) in map {
183200 name. hash ( hasher) ;
184- value. ast_hash ( hasher) ;
201+ value. ast_hash :: < _ , ORDER_INDEPENDENT > ( hasher) ;
185202 }
186203 }
187204 Value :: Null => {
@@ -310,10 +327,10 @@ mod tests {
310327 args2. add_argument ( "a" . to_string ( ) , Value :: Int ( 1 ) ) ;
311328
312329 let mut hasher1 = FxHasher :: default ( ) ;
313- args1. ast_hash ( & mut hasher1) ;
330+ args1. ast_hash :: < _ , true > ( & mut hasher1) ;
314331
315332 let mut hasher2 = FxHasher :: default ( ) ;
316- args2. ast_hash ( & mut hasher2) ;
333+ args2. ast_hash :: < _ , true > ( & mut hasher2) ;
317334
318335 assert_eq ! (
319336 hasher1. finish( ) ,
@@ -351,10 +368,10 @@ mod tests {
351368 ] ;
352369
353370 let mut hasher1 = FxHasher :: default ( ) ;
354- vars1. ast_hash ( & mut hasher1) ;
371+ vars1. ast_hash :: < _ , true > ( & mut hasher1) ;
355372
356373 let mut hasher2 = FxHasher :: default ( ) ;
357- vars2. ast_hash ( & mut hasher2) ;
374+ vars2. ast_hash :: < _ , true > ( & mut hasher2) ;
358375
359376 assert_eq ! (
360377 hasher1. finish( ) ,
0 commit comments