Skip to content

Commit 9bdda62

Browse files
committed
refactor: find duplicates
1 parent b2f6d02 commit 9bdda62

1 file changed

Lines changed: 28 additions & 33 deletions

File tree

rust/types/src/topology.rs

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,37 @@
7777
7878
use std::collections::HashSet;
7979
use std::fmt::Debug;
80+
use std::hash::Hash;
8081

8182
use serde::Deserialize;
8283
use serde::Serialize;
8384
use thiserror::Error;
8485

86+
/// Finds duplicate values in a slice by extracting a key from each item.
87+
///
88+
/// Returns a sorted, deduplicated list of keys that appear more than once.
89+
fn find_duplicates<'a, T, K, F>(items: &'a [T], key_fn: F) -> Vec<K>
90+
where
91+
K: 'a + Clone + Eq + Hash + Ord,
92+
F: Fn(&'a T) -> &'a K,
93+
{
94+
let mut seen = HashSet::new();
95+
let mut duplicates: Vec<_> = items
96+
.iter()
97+
.filter_map(|item| {
98+
let key = key_fn(item);
99+
if !seen.insert(key) {
100+
Some(key.clone())
101+
} else {
102+
None
103+
}
104+
})
105+
.collect();
106+
duplicates.sort();
107+
duplicates.dedup();
108+
duplicates
109+
}
110+
85111
/// A strongly-typed region name.
86112
///
87113
/// This newtype wrapper ensures region names cannot be confused with other string types
@@ -552,39 +578,8 @@ impl<T: Clone + Debug + Eq + PartialEq + Serialize + for<'a> Deserialize<'a>>
552578
let mut error = ValidationError::default();
553579
let all_region_names: HashSet<_> = self.regions.iter().map(|r| &r.name).collect();
554580

555-
// Find duplicate region names, ensuring each duplicate is reported only once.
556-
let mut seen_regions = HashSet::new();
557-
let mut duplicate_regions: Vec<_> = self
558-
.regions
559-
.iter()
560-
.filter_map(|r| {
561-
if !seen_regions.insert(&r.name) {
562-
Some(r.name.clone())
563-
} else {
564-
None
565-
}
566-
})
567-
.collect();
568-
duplicate_regions.sort();
569-
duplicate_regions.dedup();
570-
error.duplicate_region_names = duplicate_regions;
571-
572-
// Find duplicate topology names, ensuring each duplicate is reported only once.
573-
let mut seen_topologies = HashSet::new();
574-
let mut duplicate_topologies: Vec<_> = self
575-
.topologies
576-
.iter()
577-
.filter_map(|t| {
578-
if !seen_topologies.insert(&t.name) {
579-
Some(t.name.clone())
580-
} else {
581-
None
582-
}
583-
})
584-
.collect();
585-
duplicate_topologies.sort();
586-
duplicate_topologies.dedup();
587-
error.duplicate_topology_names = duplicate_topologies;
581+
error.duplicate_region_names = find_duplicates(&self.regions, |r| &r.name);
582+
error.duplicate_topology_names = find_duplicates(&self.topologies, |t| &t.name);
588583

589584
// Find all unique unknown regions across all topologies.
590585
let mut unknown_regions: Vec<_> = self

0 commit comments

Comments
 (0)