tina-core 0.0.2

Tina platform
Documentation
//! Map相关工具

use indexmap::IndexMap;
use std::collections::HashMap;
use std::hash::Hash;

/// 添加
pub trait InsertOrAddToMap<K, V> {
    /// 添加键值
    fn insert_or_add_to_value(&mut self, key: K, value: V);
}

/// 展开
pub trait ExpandToListMap<L> {
    /// 展开
    fn to_list_map(&self) -> L;
}

impl<K, V> InsertOrAddToMap<K, V> for HashMap<K, Vec<V>>
where
    K: Eq + Hash,
{
    fn insert_or_add_to_value(&mut self, key: K, value: V) {
        match self.get_mut(&key) {
            None => {
                self.insert(key, vec![value]);
            }
            Some(v) => {
                v.push(value);
            }
        }
    }
}

impl<K, V> InsertOrAddToMap<K, V> for IndexMap<K, Vec<V>>
where
    K: Eq + Hash,
{
    fn insert_or_add_to_value(&mut self, key: K, value: V) {
        match self.get_mut(&key) {
            None => {
                self.insert(key, vec![value]);
            }
            Some(v) => {
                v.push(value);
            }
        }
    }
}

impl<K, KR, V, VR> ExpandToListMap<Vec<IndexMap<KR, VR>>> for IndexMap<K, Vec<V>>
where
    K: Eq + Hash + ToOwned<Owned = KR>,
    KR: Eq + Hash,
    V: ToOwned<Owned = VR>,
{
    fn to_list_map(&self) -> Vec<IndexMap<KR, VR>> {
        let mut capacity = 0;
        for v in self.values() {
            let len = v.len();
            if capacity == 0 && len > 0 {
                capacity = 1;
            }
            capacity *= len;
        }
        let mut list = Vec::with_capacity(capacity);
        list.resize_with(capacity, || IndexMap::new());

        for (key, value) in self.iter() {
            let mut idx = 0;
            while idx < list.len() {
                for value in value.iter() {
                    if let Some(map) = list.get_mut(idx) {
                        map.insert(key.to_owned(), value.to_owned());
                    }
                    idx += 1;
                }
            }
        }
        list
    }
}

#[allow(unused)]
mod test {
    use crate::tina::data::map::{ExpandToListMap, InsertOrAddToMap};

    use indexmap::IndexMap;
    use std::collections::HashMap;

    #[test]
    fn test_expand_to_list() {
        let mut map: IndexMap<i32, Vec<i32>> = IndexMap::new();
        map.insert_or_add_to_value(1, 1);
        map.insert_or_add_to_value(1, 2);
        map.insert_or_add_to_value(2, 1);
        map.insert_or_add_to_value(2, 2);
        map.insert_or_add_to_value(2, 3);

        let expand = map.to_list_map();
        let mut check: Vec<IndexMap<i32, i32>> = Vec::new();
        {
            let mut map = IndexMap::new();
            map.insert(1, 1);
            map.insert(2, 1);
            check.push(map);
        }
        {
            let mut map = IndexMap::new();
            map.insert(1, 2);
            map.insert(2, 2);
            check.push(map);
        }
        {
            let mut map = IndexMap::new();
            map.insert(1, 1);
            map.insert(2, 3);
            check.push(map);
        }
        {
            let mut map = IndexMap::new();
            map.insert(1, 2);
            map.insert(2, 1);
            check.push(map);
        }
        {
            let mut map = IndexMap::new();
            map.insert(1, 1);
            map.insert(2, 2);
            check.push(map);
        }
        {
            let mut map = IndexMap::new();
            map.insert(1, 2);
            map.insert(2, 3);
            check.push(map);
        }
        assert_eq!(expand, check);
    }
}