use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::iter::zip;
#[derive(Debug)]
pub enum ListToHashMapError<K> {
LengthMismatch { keys_len: usize, values_len: usize },
DuplicateKeys { duplicates: Vec<K> },
}
pub trait HashMapValuesToHashSet<V>
where
V: Eq + Hash + Clone,
{
fn h_hashmap_values_to_hashset(&self) -> HashSet<V>;
}
impl<K, V> HashMapValuesToHashSet<V> for HashMap<K, V>
where
V: Eq + Hash + Clone,
{
fn h_hashmap_values_to_hashset(&self) -> HashSet<V> {
let mut set: HashSet<V> = HashSet::new();
for (_key, value) in self.iter() {
set.insert(value.clone());
}
set
}
}
pub trait HashMapKeysToHashSet<K>
where
K: Eq + Hash + Clone,
{
fn h_hashmap_keys_to_hashset(&self) -> HashSet<K>;
}
impl<K, V> HashMapKeysToHashSet<K> for HashMap<K, V>
where
K: Eq + Hash + Clone,
{
fn h_hashmap_keys_to_hashset(&self) -> HashSet<K> {
let mut set: HashSet<K> = HashSet::new();
for (key, _value) in self.iter() {
set.insert(key.clone());
}
set
}
}
pub fn h_list_to_hashmap<K, V>(keys: &[K], values: &[V]) -> Result<HashMap<K, V>, Vec<ListToHashMapError<K>>>
where
K: Eq + Hash + Clone,
V: Clone,
{
if keys.len() != values.len() {
return Err(vec![ListToHashMapError::LengthMismatch {
keys_len: keys.len(),
values_len: values.len(),
}]);
}
let mut map = HashMap::new();
let mut duplicates = Vec::new();
for (key, value) in keys.iter().zip(values.iter()) {
if map.contains_key(key) {
duplicates.push(key.clone());
} else {
map.insert(key.clone(), value.clone());
}
}
if !duplicates.is_empty() {
return Err(vec![ListToHashMapError::DuplicateKeys {
duplicates,
}]);
}
Ok(map)
}
pub trait ListToHashSet {
type Item;
fn h_list_to_hashset(&self) -> (HashSet<Self::Item>, usize)
where
Self::Item: Eq + Hash + Clone;
}
impl<T> ListToHashSet for [T]
where
T: Eq + Hash + Clone,
{
type Item = T;
fn h_list_to_hashset(&self) -> (HashSet<Self::Item>, usize) {
let mut set = HashSet::new();
let mut duplicates = 0;
for item in self.iter() {
if !set.insert(item.clone()) {
duplicates += 1;
}
}
(set, duplicates)
}
}
use std::time::Duration;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct HBlockPreformance {
label: Option<&'static str>,
duration: Duration,
file: &'static str,
line: u32,
}
impl HBlockPreformance {
pub fn new() -> Self {
HBlockPreformance { label: None, duration: Duration::new(0, 0), line: 0, file: "" }
}
pub fn set_new(label: Option<&'static str>, duration: Duration, line: u32, file: &'static str) -> Self {
HBlockPreformance { label: label, duration: duration, line: line, file: file}
}
pub fn print(&self) {
println!("label: {:?}, duration: {:?}, line: {}, file: {}", self.label, self.duration, self.line, self.file);
}
pub fn print_fields_specified(&self, fields: &[HBlockPreformanceField]) {
let mut count: usize = 1;
if fields.contains(&HBlockPreformanceField::Label) {
if fields.len() == count {
print!("label: {:?}\n", self.label);
}
else {
print!("label: {:?}, ", self.label);
}
count += 1;
}
if fields.contains(&HBlockPreformanceField::Duration) {
if fields.len() == count {
print!("duration: {:?}\n", self.duration);
}
else {
print!("duration: {:?}, ", self.duration);
}
count += 1;
}
if fields.contains(&HBlockPreformanceField::File) {
if fields.len() == count {
print!("file: {:?}\n", self.file);
}
else {
print!("file: {:?}, ", self.file);
}
}
if fields.contains(&HBlockPreformanceField::Line) {
print!("line: {:?}\n", self.line);
}
}
pub fn print_label(&self) {
println!("label: {:?}", self.label);
}
pub fn print_duration(&self) {
println!("duration: {:?}", self.duration);
}
pub fn print_file(&self) {
println!("label: {}", self.file);
}
pub fn print_line(&self) {
println!("line: {}", self.line);
}
}
#[macro_export]
macro_rules! h_block_preformance {
($code:block) => {
{
let start = std::time::Instant::now();
$code
HBlockPreformance::set_new(None, start.elapsed(), line!(), file!())
}
};
}
#[derive(Debug, PartialEq, Eq)]
pub enum HBlockPreformanceLogPrintOrder {
Normal,
LabelAlphabeticAscending,
DurationAscending,
FileAlphabeticalAscending,
LineAscending,
}
#[derive(Debug, PartialEq, Eq)]
pub enum HBlockPreformanceField {
Label,
Duration,
File,
Line,
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_hashmap_values_to_hashset() {
let mut map = HashMap::new();
map.insert(1, "a");
map.insert(2, "b");
map.insert(3, "a");
let set = map.h_hashmap_values_to_hashset();
assert_eq!(set.len(), 2);
assert!(set.contains("a"));
assert!(set.contains("b"));
}
#[test]
fn test_hashmap_keys_to_hashset() {
let mut map = HashMap::new();
map.insert(1, "a");
map.insert(2, "b");
map.insert(3, "a");
let set = map.h_hashmap_keys_to_hashset();
assert_eq!(set.len(), 3);
assert!(set.contains(&1));
assert!(set.contains(&2));
assert!(set.contains(&3));
}
#[test]
fn test_h_list_to_hashmap() {
let keys = vec![1, 2, 3];
let values = vec!["a", "b", "c"];
let map = h_list_to_hashmap(&keys, &values).unwrap();
assert_eq!(map.get(&1), Some(&"a"));
assert_eq!(map.get(&2), Some(&"b"));
assert_eq!(map.get(&3), Some(&"c"));
}
#[test]
fn test_h_list_to_hashmap_length_mismatch() {
let keys = vec![1, 2];
let values = vec!["a", "b", "c"];
let result = h_list_to_hashmap(&keys, &values);
assert!(result.is_err());
}
#[test]
fn test_h_list_to_hashmap_duplicate_keys() {
let keys = vec![1, 1, 2];
let values = vec!["a", "b", "c"];
let result = h_list_to_hashmap(&keys, &values);
assert!(result.is_err());
}
#[test]
fn test_list_to_hashset() {
let list = vec!["a", "b", "a", "c"];
let (set, dupes) = list.h_list_to_hashset();
assert_eq!(set.len(), 3);
assert!(set.contains("a"));
assert!(set.contains("b"));
assert!(set.contains("c"));
assert_eq!(dupes, 1);
}
}