47 lines
1.1 KiB
Rust
47 lines
1.1 KiB
Rust
![]() |
//!
|
||
|
|
||
|
use std::collections::HashMap;
|
||
|
|
||
|
pub struct Duplicate<T> {
|
||
|
pub name: String,
|
||
|
pub spanned: Vec<T>,
|
||
|
}
|
||
|
|
||
|
impl<T> Duplicate<T> {
|
||
|
pub fn find_by_key<'a, F>(items: &'a [T], name: F) -> Option<Vec<Duplicate<&'a T>>>
|
||
|
where
|
||
|
T: 'a,
|
||
|
F: Fn(&'a T) -> &'a str,
|
||
|
{
|
||
|
let mut mapping: HashMap<&str, Vec<&T>> = HashMap::with_capacity(items.len());
|
||
|
|
||
|
for item in items {
|
||
|
if let Some(vals) = mapping.get_mut(name(item)) {
|
||
|
vals.push(item);
|
||
|
} else {
|
||
|
mapping.insert(name(item), vec![item]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let duplicates = mapping
|
||
|
.into_iter()
|
||
|
.filter_map(|(k, v)| {
|
||
|
if v.len() != 1 {
|
||
|
Some(Duplicate {
|
||
|
name: k.to_string(),
|
||
|
spanned: v,
|
||
|
})
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
})
|
||
|
.collect::<Vec<_>>();
|
||
|
|
||
|
if !duplicates.is_empty() {
|
||
|
Some(duplicates)
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
}
|