Skip to content

Commit

Permalink
✨ (MapExt): impl MapExt for indexmap::IndexMap
Browse files Browse the repository at this point in the history
  • Loading branch information
czy-29 committed Nov 23, 2024
1 parent e3ffea9 commit 005c643
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ all-features = true

[dependencies]
anyhow = "1.0.93"
indexmap = "2.6.0"
thiserror = "2.0.3"

[dev-dependencies]
Expand Down
75 changes: 75 additions & 0 deletions src/collections.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use indexmap::{Equivalent, IndexMap};
use std::{
borrow::Borrow,
collections::{BTreeMap, HashMap},
Expand Down Expand Up @@ -84,6 +85,38 @@ where
}
}

impl<K, Q, V, S> MapExt<K, Q> for IndexMap<K, V, S>
where
K: Borrow<Q> + Hash + Eq,
Q: ?Sized + Hash + Equivalent<K>,
S: BuildHasher,
{
fn replace_key(&mut self, k1: &Q, k2: K) -> Result<(), ReplaceKeyErr> {
let Some(i) = self.get_index_of(k1) else {
return Err(ReplaceKeyErr::OldKeyNotExist);
};

if k1.equivalent(&k2) {
return Ok(());
}

if self.contains_key(k2.borrow()) {
return Err(ReplaceKeyErr::NewKeyOccupied);
}

// Note, this temporarily displaces the last entry into `i`,
// but we'll swap it back after we insert the new key.
// See: https://github.com/indexmap-rs/indexmap/issues/362
let Some((_, v)) = self.swap_remove_index(i) else {
return Err(ReplaceKeyErr::OldKeyNotExist);
};

let (j, _) = self.insert_full(k2, v);
self.swap_indices(i, j);
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -159,4 +192,46 @@ mod tests {
assert_eq!(map["k3"], 123);
assert_eq!(map["k2"], 456);
}

#[test]
fn replace_key_indexmap() {
let mut map = indexmap::indexmap! {
"k1".to_string() => 123,
"k2".to_string() => 456
};

assert_eq!(map["k1"], 123);
assert_eq!(map["k2"], 456);
assert_eq!(map.get_index_of("k1"), Some(0));
assert_eq!(map.get_index(0), Some((&"k1".to_string(), &123)));

assert_eq!(
map.replace_key("k3", "k2".to_string()),
Err(ReplaceKeyErr::OldKeyNotExist)
);
assert_eq!(
map.replace_key("k3", "k3".to_string()),
Err(ReplaceKeyErr::OldKeyNotExist)
);
assert_eq!(
map.replace_key("k3", "k4".to_string()),
Err(ReplaceKeyErr::OldKeyNotExist)
);

let cloned = map.clone();
assert_eq!(map.replace_key("k1", "k1".to_string()), Ok(()));
assert_eq!(map, cloned);

assert_eq!(
map.replace_key("k1", "k2".to_string()),
Err(ReplaceKeyErr::NewKeyOccupied)
);

assert_eq!(map.replace_key("k1", "k3".to_string()), Ok(()));
assert!(!map.contains_key("k1"));
assert_eq!(map["k3"], 123);
assert_eq!(map["k2"], 456);
assert_eq!(map.get_index_of("k3"), Some(0));
assert_eq!(map.get_index(0), Some((&"k3".to_string(), &123)));
}
}

0 comments on commit 005c643

Please sign in to comment.