1use std::collections::HashMap;
9use std::hash::{Hash, Hasher};
10
11use crate::arch::addr::{LaneAddr, LocationAddr, ZoneAddr};
12use crate::arch::types::ArchSpec;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct AtomStateData {
25 pub locations_to_qubit: HashMap<LocationAddr, u32>,
27 pub qubit_to_locations: HashMap<u32, LocationAddr>,
29 pub collision: HashMap<u32, u32>,
35 pub prev_lanes: HashMap<u32, LaneAddr>,
38 pub move_count: HashMap<u32, u32>,
41}
42
43impl Hash for AtomStateData {
44 fn hash<H: Hasher>(&self, state: &mut H) {
45 fn hash_sorted_map<H: Hasher, K: Ord + Hash, V: Hash>(
48 state: &mut H,
49 tag: u8,
50 entries: &mut [(K, V)],
51 ) {
52 tag.hash(state);
53 entries.len().hash(state);
54 entries.sort_by(|a, b| a.0.cmp(&b.0));
55 for (k, v) in entries.iter() {
56 k.hash(state);
57 v.hash(state);
58 }
59 }
60
61 let mut loc_entries: Vec<_> = self
62 .locations_to_qubit
63 .iter()
64 .map(|(k, v)| (k.encode(), *v))
65 .collect();
66 hash_sorted_map(state, 0, &mut loc_entries);
67
68 let mut qubit_entries: Vec<_> = self
69 .qubit_to_locations
70 .iter()
71 .map(|(k, v)| (*k, v.encode()))
72 .collect();
73 hash_sorted_map(state, 1, &mut qubit_entries);
74
75 let mut collision_entries: Vec<_> = self.collision.iter().map(|(k, v)| (*k, *v)).collect();
76 hash_sorted_map(state, 2, &mut collision_entries);
77
78 let mut lane_entries: Vec<_> = self
79 .prev_lanes
80 .iter()
81 .map(|(k, v)| (*k, v.encode_u64()))
82 .collect();
83 hash_sorted_map(state, 3, &mut lane_entries);
84
85 let mut count_entries: Vec<_> = self.move_count.iter().map(|(k, v)| (*k, *v)).collect();
86 hash_sorted_map(state, 4, &mut count_entries);
87 }
88}
89
90impl AtomStateData {
91 pub fn new() -> Self {
93 Self {
94 locations_to_qubit: HashMap::new(),
95 qubit_to_locations: HashMap::new(),
96 collision: HashMap::new(),
97 prev_lanes: HashMap::new(),
98 move_count: HashMap::new(),
99 }
100 }
101
102 pub fn from_locations(locations: &[(u32, LocationAddr)]) -> Self {
107 let mut locations_to_qubit = HashMap::new();
108 let mut qubit_to_locations = HashMap::new();
109
110 for &(qubit, loc) in locations {
111 qubit_to_locations.insert(qubit, loc);
112 locations_to_qubit.insert(loc, qubit);
113 }
114
115 Self {
116 locations_to_qubit,
117 qubit_to_locations,
118 collision: HashMap::new(),
119 prev_lanes: HashMap::new(),
120 move_count: HashMap::new(),
121 }
122 }
123
124 pub fn add_atoms(&self, locations: &[(u32, LocationAddr)]) -> Result<Self, &'static str> {
133 let mut qubit_to_locations = self.qubit_to_locations.clone();
134 let mut locations_to_qubit = self.locations_to_qubit.clone();
135
136 for &(qubit, loc) in locations {
137 if qubit_to_locations.contains_key(&qubit) {
138 return Err("Attempted to add atom that already exists");
139 }
140 if locations_to_qubit.contains_key(&loc) {
141 return Err("Attempted to add atom to occupied location");
142 }
143 qubit_to_locations.insert(qubit, loc);
144 locations_to_qubit.insert(loc, qubit);
145 }
146
147 Ok(Self {
148 locations_to_qubit,
149 qubit_to_locations,
150 collision: HashMap::new(),
151 prev_lanes: HashMap::new(),
152 move_count: HashMap::new(),
153 })
154 }
155
156 pub fn apply_moves(&self, lanes: &[LaneAddr], arch_spec: &ArchSpec) -> Option<Self> {
168 let mut qubit_to_locations = self.qubit_to_locations.clone();
169 let mut locations_to_qubit = self.locations_to_qubit.clone();
170 let mut collisions = self.collision.clone();
171 let mut move_count = self.move_count.clone();
172 let mut prev_lanes: HashMap<u32, LaneAddr> = HashMap::new();
173
174 for lane in lanes {
175 let (src, dst) = arch_spec.lane_endpoints(lane)?;
176
177 let qubit = match locations_to_qubit.remove(&src) {
178 Some(q) => q,
179 None => continue,
180 };
181
182 *move_count.entry(qubit).or_insert(0) += 1;
183 prev_lanes.insert(qubit, *lane);
184
185 if let Some(other_qubit) = locations_to_qubit.remove(&dst) {
186 qubit_to_locations.remove(&qubit);
187 qubit_to_locations.remove(&other_qubit);
188 collisions.insert(qubit, other_qubit);
189 } else {
190 qubit_to_locations.insert(qubit, dst);
191 locations_to_qubit.insert(dst, qubit);
192 }
193 }
194
195 Some(Self {
196 locations_to_qubit,
197 qubit_to_locations,
198 prev_lanes,
199 collision: collisions,
200 move_count,
201 })
202 }
203
204 pub fn get_qubit(&self, location: &LocationAddr) -> Option<u32> {
206 self.locations_to_qubit.get(location).copied()
207 }
208
209 pub fn get_qubit_pairing(
221 &self,
222 zone: &ZoneAddr,
223 arch_spec: &ArchSpec,
224 ) -> Option<(Vec<u32>, Vec<u32>, Vec<u32>)> {
225 let _zone_data = arch_spec.zone_by_id(zone.zone_id)?;
228 let zone_id = zone.zone_id;
229
230 let mut controls = Vec::new();
231 let mut targets = Vec::new();
232 let mut unpaired = Vec::new();
233 let mut visited = std::collections::HashSet::new();
234
235 let mut sorted_qubits: Vec<_> = self.qubit_to_locations.iter().collect();
237 sorted_qubits.sort_by_key(|(qubit, _)| **qubit);
238
239 for (qubit, loc) in &sorted_qubits {
240 let qubit = **qubit;
241 let loc = **loc;
242 if visited.contains(&qubit) {
243 continue;
244 }
245 visited.insert(qubit);
246
247 if loc.zone_id != zone_id {
248 continue;
249 }
250
251 let blockaded = match arch_spec.get_cz_partner(&loc) {
252 Some(b) => b,
253 None => {
254 unpaired.push(qubit);
255 continue;
256 }
257 };
258
259 let target_qubit = match self.get_qubit(&blockaded) {
260 Some(t) => t,
261 None => {
262 unpaired.push(qubit);
263 continue;
264 }
265 };
266
267 controls.push(qubit);
268 targets.push(target_qubit);
269 visited.insert(target_qubit);
270 }
271
272 Some((controls, targets, unpaired))
273 }
274}
275
276impl Default for AtomStateData {
277 fn default() -> Self {
278 Self::new()
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285 use crate::arch::addr::{SiteRef, WordRef, ZonedWordRef};
286 use crate::arch::types::{Bus, Grid, Mode, Word, Zone};
287 use crate::version::Version;
288
289 fn make_test_spec() -> crate::arch::ArchSpec {
293 let grid0 = Grid::from_positions(&[0.0, 5.0, 10.0], &[0.0, 3.0]);
294 let grid1 = Grid::from_positions(&[0.0, 7.5, 15.0], &[0.0, 4.0]);
295
296 crate::arch::ArchSpec {
297 version: Version::new(2, 0),
298 words: vec![
299 Word {
300 sites: vec![[0, 0], [0, 1]],
301 },
302 Word {
303 sites: vec![[1, 0], [1, 1]],
304 },
305 ],
306 zones: vec![
307 Zone {
308 name: String::new(),
309 grid: grid0,
310 site_buses: vec![Bus {
311 src: vec![SiteRef(0)],
312 dst: vec![SiteRef(1)],
313 }],
314 word_buses: vec![Bus {
315 src: vec![WordRef(0)],
316 dst: vec![WordRef(1)],
317 }],
318 words_with_site_buses: vec![0, 1],
319 sites_with_word_buses: vec![0],
320 entangling_pairs: vec![[0, 1]],
321 },
322 Zone {
323 name: String::new(),
324 grid: grid1,
325 site_buses: vec![],
326 word_buses: vec![],
327 words_with_site_buses: vec![],
328 sites_with_word_buses: vec![],
329 entangling_pairs: vec![],
330 },
331 ],
332 zone_buses: vec![Bus {
333 src: vec![ZonedWordRef {
334 zone_id: 0,
335 word_id: 0,
336 }],
337 dst: vec![ZonedWordRef {
338 zone_id: 1,
339 word_id: 0,
340 }],
341 }],
342 modes: vec![Mode {
343 name: "full".to_string(),
344 zones: vec![0, 1],
345 bitstring_order: vec![],
346 }],
347 paths: None,
348 feed_forward: false,
349 atom_reloading: false,
350 blockade_radius: None,
351 }
352 }
353
354 #[test]
355 fn new_state_is_empty() {
356 let state = AtomStateData::new();
357 assert!(state.locations_to_qubit.is_empty());
358 assert!(state.qubit_to_locations.is_empty());
359 assert!(state.collision.is_empty());
360 assert!(state.prev_lanes.is_empty());
361 assert!(state.move_count.is_empty());
362 }
363
364 #[test]
365 fn from_locations_creates_bidirectional_map() {
366 let locs = vec![
367 (
368 0,
369 LocationAddr {
370 zone_id: 0,
371 word_id: 0,
372 site_id: 0,
373 },
374 ),
375 (
376 1,
377 LocationAddr {
378 zone_id: 0,
379 word_id: 1,
380 site_id: 0,
381 },
382 ),
383 ];
384 let state = AtomStateData::from_locations(&locs);
385 assert_eq!(
386 state.get_qubit(&LocationAddr {
387 zone_id: 0,
388 word_id: 0,
389 site_id: 0
390 }),
391 Some(0)
392 );
393 assert_eq!(
394 state.get_qubit(&LocationAddr {
395 zone_id: 0,
396 word_id: 1,
397 site_id: 0
398 }),
399 Some(1)
400 );
401 }
402
403 #[test]
404 fn add_atoms_succeeds_and_fields_match() {
405 let state = AtomStateData::new();
406 let loc0 = LocationAddr {
407 zone_id: 0,
408 word_id: 0,
409 site_id: 0,
410 };
411 let loc1 = LocationAddr {
412 zone_id: 0,
413 word_id: 1,
414 site_id: 0,
415 };
416 let new_state = state.add_atoms(&[(0, loc0), (1, loc1)]).unwrap();
417
418 assert_eq!(new_state.qubit_to_locations.len(), 2);
419 assert_eq!(new_state.qubit_to_locations[&0], loc0);
420 assert_eq!(new_state.qubit_to_locations[&1], loc1);
421 assert_eq!(new_state.locations_to_qubit[&loc0], 0);
422 assert_eq!(new_state.locations_to_qubit[&loc1], 1);
423 assert!(new_state.collision.is_empty());
424 assert!(new_state.prev_lanes.is_empty());
425 assert!(new_state.move_count.is_empty());
426 }
427
428 #[test]
429 fn add_atoms_duplicate_qubit_fails() {
430 let state = AtomStateData::from_locations(&[(
431 0,
432 LocationAddr {
433 zone_id: 0,
434 word_id: 0,
435 site_id: 0,
436 },
437 )]);
438 let result = state.add_atoms(&[(
439 0,
440 LocationAddr {
441 zone_id: 0,
442 word_id: 1,
443 site_id: 0,
444 },
445 )]);
446 assert!(result.is_err());
447 }
448
449 #[test]
450 fn add_atoms_occupied_location_fails() {
451 let state = AtomStateData::from_locations(&[(
452 0,
453 LocationAddr {
454 zone_id: 0,
455 word_id: 0,
456 site_id: 0,
457 },
458 )]);
459 let result = state.add_atoms(&[(
460 1,
461 LocationAddr {
462 zone_id: 0,
463 word_id: 0,
464 site_id: 0,
465 },
466 )]);
467 assert!(result.is_err());
468 }
469
470 #[test]
471 fn apply_moves_basic() {
472 let spec = make_test_spec();
473 let state = AtomStateData::from_locations(&[
475 (
476 0,
477 LocationAddr {
478 zone_id: 0,
479 word_id: 0,
480 site_id: 0,
481 },
482 ),
483 (
484 1,
485 LocationAddr {
486 zone_id: 0,
487 word_id: 1,
488 site_id: 0,
489 },
490 ),
491 ]);
492
493 let lane = LaneAddr {
495 direction: crate::arch::addr::Direction::Forward,
496 move_type: crate::arch::addr::MoveType::SiteBus,
497 zone_id: 0,
498 word_id: 0,
499 site_id: 0,
500 bus_id: 0,
501 };
502
503 let new_state = state.apply_moves(&[lane], &spec).unwrap();
504 assert_eq!(
505 new_state.get_qubit(&LocationAddr {
506 zone_id: 0,
507 word_id: 0,
508 site_id: 1
509 }),
510 Some(0)
511 );
512 assert_eq!(
513 new_state.get_qubit(&LocationAddr {
514 zone_id: 0,
515 word_id: 0,
516 site_id: 0
517 }),
518 None
519 );
520 assert_eq!(*new_state.move_count.get(&0).unwrap(), 1);
521 }
522
523 #[test]
524 fn apply_moves_collision() {
525 let spec = make_test_spec();
526 let state = AtomStateData::from_locations(&[
528 (
529 0,
530 LocationAddr {
531 zone_id: 0,
532 word_id: 0,
533 site_id: 0,
534 },
535 ),
536 (
537 1,
538 LocationAddr {
539 zone_id: 0,
540 word_id: 0,
541 site_id: 1,
542 },
543 ),
544 ]);
545
546 let lane = LaneAddr {
547 direction: crate::arch::addr::Direction::Forward,
548 move_type: crate::arch::addr::MoveType::SiteBus,
549 zone_id: 0,
550 word_id: 0,
551 site_id: 0,
552 bus_id: 0,
553 };
554
555 let new_state = state.apply_moves(&[lane], &spec).unwrap();
556 assert!(new_state.collision.contains_key(&0));
557 assert_eq!(*new_state.collision.get(&0).unwrap(), 1);
558 assert!(new_state.qubit_to_locations.is_empty());
559 }
560
561 #[test]
562 fn apply_moves_verifies_all_fields() {
563 let spec = make_test_spec();
564 let loc_0_0 = LocationAddr {
565 zone_id: 0,
566 word_id: 0,
567 site_id: 0,
568 };
569 let loc_0_1 = LocationAddr {
570 zone_id: 0,
571 word_id: 0,
572 site_id: 1,
573 };
574 let loc_1_0 = LocationAddr {
575 zone_id: 0,
576 word_id: 1,
577 site_id: 0,
578 };
579 let state = AtomStateData::from_locations(&[(0, loc_0_0), (1, loc_1_0)]);
580
581 let lane = LaneAddr {
582 direction: crate::arch::addr::Direction::Forward,
583 move_type: crate::arch::addr::MoveType::SiteBus,
584 zone_id: 0,
585 word_id: 0,
586 site_id: 0,
587 bus_id: 0,
588 };
589
590 let new_state = state.apply_moves(&[lane], &spec).unwrap();
591
592 assert_eq!(new_state.qubit_to_locations[&0], loc_0_1);
594 assert_eq!(new_state.locations_to_qubit[&loc_0_1], 0);
595 assert_eq!(new_state.qubit_to_locations[&1], loc_1_0);
597 assert_eq!(new_state.locations_to_qubit[&loc_1_0], 1);
598 assert!(!new_state.locations_to_qubit.contains_key(&loc_0_0));
600 assert_eq!(new_state.prev_lanes.len(), 1);
602 assert_eq!(new_state.prev_lanes[&0], lane);
603 assert_eq!(new_state.move_count[&0], 1);
605 assert!(new_state.collision.is_empty());
607 }
608
609 #[test]
610 fn apply_moves_collision_verifies_all_fields() {
611 let spec = make_test_spec();
612 let state = AtomStateData::from_locations(&[
613 (
614 0,
615 LocationAddr {
616 zone_id: 0,
617 word_id: 0,
618 site_id: 0,
619 },
620 ),
621 (
622 1,
623 LocationAddr {
624 zone_id: 0,
625 word_id: 0,
626 site_id: 1,
627 },
628 ),
629 ]);
630
631 let lane = LaneAddr {
632 direction: crate::arch::addr::Direction::Forward,
633 move_type: crate::arch::addr::MoveType::SiteBus,
634 zone_id: 0,
635 word_id: 0,
636 site_id: 0,
637 bus_id: 0,
638 };
639
640 let new_state = state.apply_moves(&[lane], &spec).unwrap();
641
642 assert!(new_state.qubit_to_locations.is_empty());
644 assert!(new_state.locations_to_qubit.is_empty());
645 assert_eq!(new_state.collision[&0], 1);
647 assert_eq!(new_state.prev_lanes[&0], lane);
649 assert_eq!(new_state.move_count[&0], 1);
651 }
652
653 #[test]
654 fn apply_moves_skips_empty_source() {
655 let spec = make_test_spec();
656 let state = AtomStateData::from_locations(&[(
658 1,
659 LocationAddr {
660 zone_id: 0,
661 word_id: 1,
662 site_id: 0,
663 },
664 )]);
665
666 let lane = LaneAddr {
667 direction: crate::arch::addr::Direction::Forward,
668 move_type: crate::arch::addr::MoveType::SiteBus,
669 zone_id: 0,
670 word_id: 0,
671 site_id: 0,
672 bus_id: 0,
673 };
674
675 let new_state = state.apply_moves(&[lane], &spec).unwrap();
676 assert_eq!(new_state.qubit_to_locations.len(), 1);
678 assert!(new_state.prev_lanes.is_empty());
679 assert!(new_state.move_count.is_empty());
680 }
681
682 #[test]
683 fn apply_moves_invalid_lane_returns_none() {
684 let spec = make_test_spec();
685 let state = AtomStateData::from_locations(&[(
686 0,
687 LocationAddr {
688 zone_id: 0,
689 word_id: 0,
690 site_id: 0,
691 },
692 )]);
693
694 let bad_lane = LaneAddr {
695 direction: crate::arch::addr::Direction::Forward,
696 move_type: crate::arch::addr::MoveType::SiteBus,
697 zone_id: 0,
698 word_id: 0,
699 site_id: 0,
700 bus_id: 99, };
702
703 assert!(state.apply_moves(&[bad_lane], &spec).is_none());
704 }
705
706 #[test]
707 fn apply_moves_accumulates_move_count() {
708 let spec = make_test_spec();
709 let state = AtomStateData::from_locations(&[(
710 0,
711 LocationAddr {
712 zone_id: 0,
713 word_id: 0,
714 site_id: 0,
715 },
716 )]);
717
718 let lane_fwd = LaneAddr {
720 direction: crate::arch::addr::Direction::Forward,
721 move_type: crate::arch::addr::MoveType::SiteBus,
722 zone_id: 0,
723 word_id: 0,
724 site_id: 0,
725 bus_id: 0,
726 };
727 let state2 = state.apply_moves(&[lane_fwd], &spec).unwrap();
728 assert_eq!(state2.move_count[&0], 1);
729
730 let lane_bwd = LaneAddr {
733 direction: crate::arch::addr::Direction::Backward,
734 move_type: crate::arch::addr::MoveType::SiteBus,
735 zone_id: 0,
736 word_id: 0,
737 site_id: 0,
738 bus_id: 0,
739 };
740 let state3 = state2.apply_moves(&[lane_bwd], &spec).unwrap();
741 assert_eq!(state3.move_count[&0], 2);
742 }
743
744 #[test]
745 fn get_qubit_empty_location() {
746 let state = AtomStateData::from_locations(&[(
747 0,
748 LocationAddr {
749 zone_id: 0,
750 word_id: 0,
751 site_id: 0,
752 },
753 )]);
754 assert_eq!(
755 state.get_qubit(&LocationAddr {
756 zone_id: 0,
757 word_id: 1,
758 site_id: 0
759 }),
760 None
761 );
762 }
763
764 #[test]
765 fn get_qubit_pairing_all_unpaired() {
766 let spec = make_test_spec();
767 let state = AtomStateData::from_locations(&[
770 (
771 0,
772 LocationAddr {
773 zone_id: 0,
774 word_id: 0,
775 site_id: 0,
776 },
777 ),
778 (
779 1,
780 LocationAddr {
781 zone_id: 0,
782 word_id: 0,
783 site_id: 1,
784 },
785 ),
786 ]);
787
788 let zone = ZoneAddr { zone_id: 0 };
789 let (controls, targets, unpaired) = state.get_qubit_pairing(&zone, &spec).unwrap();
790
791 assert!(controls.is_empty());
792 assert!(targets.is_empty());
793 assert_eq!(unpaired.len(), 2);
794 }
795
796 #[test]
797 fn get_qubit_pairing_with_pairs() {
798 let spec = make_test_spec();
799 let state = AtomStateData::from_locations(&[
805 (
806 0,
807 LocationAddr {
808 zone_id: 0,
809 word_id: 0,
810 site_id: 0,
811 },
812 ),
813 (
814 1,
815 LocationAddr {
816 zone_id: 0,
817 word_id: 1,
818 site_id: 0,
819 },
820 ),
821 (
822 2,
823 LocationAddr {
824 zone_id: 0,
825 word_id: 0,
826 site_id: 1,
827 },
828 ),
829 ]);
830
831 let zone = ZoneAddr { zone_id: 0 };
832 let (controls, targets, unpaired) = state.get_qubit_pairing(&zone, &spec).unwrap();
833
834 assert_eq!(controls.len(), 1);
836 assert_eq!(targets.len(), 1);
837 use std::collections::HashSet;
838 let control_set: HashSet<u32> = controls.iter().copied().collect();
839 let target_set: HashSet<u32> = targets.iter().copied().collect();
840 assert_eq!(control_set, HashSet::from([0]));
841 assert_eq!(target_set, HashSet::from([1]));
842 assert_eq!(unpaired, vec![2]);
844 }
845
846 #[test]
847 fn get_qubit_pairing_invalid_zone() {
848 let spec = make_test_spec();
849 let state = AtomStateData::new();
850 let zone = ZoneAddr { zone_id: 99 };
851 assert!(state.get_qubit_pairing(&zone, &spec).is_none());
852 }
853
854 #[test]
855 fn get_qubit_pairing_skips_qubits_outside_zone() {
856 let spec = make_test_spec();
857 let state = AtomStateData::from_locations(&[(
860 0,
861 LocationAddr {
862 zone_id: 0,
863 word_id: 0,
864 site_id: 0,
865 },
866 )]);
867
868 let zone = ZoneAddr { zone_id: 0 };
870 let (controls, targets, unpaired) = state.get_qubit_pairing(&zone, &spec).unwrap();
871
872 assert!(controls.is_empty());
873 assert!(targets.is_empty());
874 assert_eq!(unpaired, vec![0]);
875 }
876
877 #[test]
878 fn default_is_empty() {
879 let state = AtomStateData::default();
880 assert!(state.locations_to_qubit.is_empty());
881 assert!(state.qubit_to_locations.is_empty());
882 }
883
884 #[test]
885 fn clone_produces_equal_state() {
886 let state = AtomStateData::from_locations(&[
887 (
888 0,
889 LocationAddr {
890 zone_id: 0,
891 word_id: 0,
892 site_id: 0,
893 },
894 ),
895 (
896 1,
897 LocationAddr {
898 zone_id: 0,
899 word_id: 1,
900 site_id: 0,
901 },
902 ),
903 ]);
904 let cloned = state.clone();
905 assert_eq!(state, cloned);
906 }
907
908 #[test]
909 fn hash_is_deterministic() {
910 use std::collections::hash_map::DefaultHasher;
911
912 let state1 = AtomStateData::from_locations(&[
913 (
914 0,
915 LocationAddr {
916 zone_id: 0,
917 word_id: 0,
918 site_id: 0,
919 },
920 ),
921 (
922 1,
923 LocationAddr {
924 zone_id: 0,
925 word_id: 1,
926 site_id: 0,
927 },
928 ),
929 ]);
930 let state2 = AtomStateData::from_locations(&[
931 (
932 1,
933 LocationAddr {
934 zone_id: 0,
935 word_id: 1,
936 site_id: 0,
937 },
938 ),
939 (
940 0,
941 LocationAddr {
942 zone_id: 0,
943 word_id: 0,
944 site_id: 0,
945 },
946 ),
947 ]);
948
949 let mut h1 = DefaultHasher::new();
950 let mut h2 = DefaultHasher::new();
951 state1.hash(&mut h1);
952 state2.hash(&mut h2);
953 assert_eq!(h1.finish(), h2.finish());
954 }
955}