diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2021-09-01 15:15:43 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2021-09-01 15:15:53 +0200 |
commit | b3620079ad18aa84ec57245bcd0723d1dc24656e (patch) | |
tree | 71e28389f80e964b6c1ba9cdee92ee069672d7de | |
parent | 0c9ad7e14fd0b828ddbd02a35251900c960abbb7 (diff) |
Add same iterator adapter for BTreeMap
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | src/btreemap.rs | 99 | ||||
-rw-r--r-- | src/lib.rs | 3 |
3 files changed, 114 insertions, 3 deletions
@@ -1,8 +1,9 @@ # collect-once-hashmap -This crate provides a type `CollectOnceHashMap` that can be collected from an -iterator just like a normal `std::collections::HashMap`, but it makes sure that -a duplicated key results in an error. +This crate provides a type `CollectOnceHashMap` (and the same for `BTreeMap` +that can be collected from an iterator just like a normal +`std::collections::HashMap`, but it makes sure that a duplicated key results in +an error. Example: @@ -15,6 +16,14 @@ let hm = vec![(1, 1), (1, 2)] assert!(hm.is_err()); assert!(std::matches!(hm, Err(Error::DuplicatedKey(1)))); + +let bm = vec![(1, 1), (1, 2)] + .into_iter() + .collect::<CollectOnceBTreeMap<u8, u8>>() + .into_inner(); + +assert!(bm.is_err()); +assert!(std::matches!(bm, Err(Error::DuplicatedKey(1)))); ``` diff --git a/src/btreemap.rs b/src/btreemap.rs new file mode 100644 index 0000000..2ada9aa --- /dev/null +++ b/src/btreemap.rs @@ -0,0 +1,99 @@ +use std::cmp::Ord; +use std::collections::BTreeMap; +use std::fmt::Debug; +use std::hash::Hash; +use std::iter::FromIterator; +use std::iter::IntoIterator; + +#[derive(Debug, thiserror::Error)] +pub enum Error<K> + where K: Debug, +{ + #[error("duplicated key in iterator: {:?}", _0)] + DuplicatedKey(K), + + #[error("unknown error")] + Unknown, +} + +pub struct CollectOnceBTreeMap<K, V> + where K: Eq + Ord + Hash + Debug +{ + inner: std::result::Result<BTreeMap<K, V>, Error<K>> +} + +impl<K, V> CollectOnceBTreeMap<K, V> + where K: Eq + Ord + Hash + Debug +{ + pub fn into_inner(self) -> std::result::Result<BTreeMap<K, V>, Error<K>> { + self.inner + } +} + +impl<K, V> FromIterator<(K, V)> for CollectOnceBTreeMap<K, V> + where K: Eq + Ord + Hash + Debug +{ + fn from_iter<T>(iter: T) -> Self + where T: IntoIterator<Item = (K, V)> + { + let mut hm = BTreeMap::new(); + + for (element_key, element_value) in iter.into_iter() { + if hm.contains_key(&element_key) { + return CollectOnceBTreeMap { + inner: Err(Error::DuplicatedKey(element_key)) + } + } else { + hm.insert(element_key, element_value); + } + } + + CollectOnceBTreeMap { + inner: Ok(hm) + } + } +} + + +#[cfg(test)] +mod tests { + use super::CollectOnceBTreeMap; + use super::Error; + + #[test] + fn test_empty() { + let hm = vec![] + .into_iter() + .collect::<CollectOnceBTreeMap<u8, u8>>() + .into_inner() + .unwrap(); + + assert_eq!(0, hm.keys().count()); + } + + #[test] + fn test_simple() { + let hm = vec![(1, 1)] + .into_iter() + .collect::<CollectOnceBTreeMap<u8, u8>>() + .into_inner() + .unwrap(); + + assert_eq!(1, hm.keys().count()); + assert!(hm.contains_key(&1)); + assert!(hm.keys().all(|k| *k == 1)); + assert!(hm.values().all(|k| *k == 1)); + } + + #[test] + fn test_duplicate() { + let hm = vec![(1, 1), (1, 2)] + .into_iter() + .collect::<CollectOnceBTreeMap<u8, u8>>() + .into_inner(); + + assert!(hm.is_err()); + assert!(std::matches!(hm, Err(Error::DuplicatedKey(1)))); + } +} + @@ -9,3 +9,6 @@ mod hashmap; pub use hashmap::*; +mod btreemap; +pub use btreemap::*; + |