take_some/
hash_map.rs

1use std::collections::HashMap;
2use std::hash::{BuildHasher, Hash};
3use TakeSome;
4
5impl<K, V, S> TakeSome for HashMap<K, V, S>
6where
7    K: Eq + Hash,
8    S: BuildHasher,
9{
10    type Item = (K, V);
11
12    /// `unsafe` under the cover!
13    fn take_some(&mut self) -> Option<(K, V)> {
14        // If the key corresponds to the "first" element (the one we store separately), we have
15        // to take a "random" element from the map (`self.rest`) and put is as the "first".
16        let temp_key: *const K = match self.keys().next() {
17            Some(x) => x,
18            None => return None,
19        };
20        // We need that unsafe magic because we are going to remove an element a reference to
21        // which we kinda hold.
22        let temp_key: &K = unsafe { &*temp_key };
23        Some(
24            self.remove_entry(temp_key)
25                .expect("We've just pulled a key from the map"),
26        )
27    }
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33    use std::iter::once;
34
35    #[test]
36    fn check_hash_map() {
37        let mut empty: HashMap<String, String> = HashMap::new();
38        assert_eq!(None, empty.take_some());
39
40        let mut one_element: HashMap<_, _> =
41            once(("check".to_string(), "checked".to_string())).collect();
42        assert_eq!(
43            Some(("check".into(), "checked".into())),
44            one_element.take_some()
45        );
46        assert!(one_element.is_empty());
47
48        let mut map: HashMap<_, _> = vec![
49            ("check".to_string(), "lol".to_string()),
50            ("wut".into(), "ahaha".into()),
51            ("123123".into(), "....".into()),
52        ].into_iter()
53            .collect();
54        assert!(map.take_some().is_some());
55        assert_eq!(2, map.len());
56    }
57}