#hash-map #typemap #dashmap #anymap #derive-debug

typedmap

哈希表(dash map)。通过在键类型上实现的trait定义值类型

7个版本 (4个重大更改)

0.5.0 2024年4月2日
0.4.0 2023年5月6日
0.3.1 2023年3月12日
0.3.0 2022年6月15日
0.1.1 2021年4月1日

#68 in 并发

Download history 1205/week @ 2024-04-15 1084/week @ 2024-04-22 1356/week @ 2024-04-29 998/week @ 2024-05-06 1461/week @ 2024-05-13 1031/week @ 2024-05-20 1179/week @ 2024-05-27 926/week @ 2024-06-03 1287/week @ 2024-06-10 1102/week @ 2024-06-17 857/week @ 2024-06-24 518/week @ 2024-07-01 668/week @ 2024-07-08 870/week @ 2024-07-15 636/week @ 2024-07-22 887/week @ 2024-07-29

每月3,077次下载
2个crates中使用(通过dbsp

MIT/Apache

155KB
2.5K SLoC

TypedMap

Docs Crates.io

TypedMap是一个类型化的HashMap。它允许您根据键类型定义不同的值类型。如果您想在单个哈希表中存储不同的键值对,例如在实现多个服务的HTTP应用程序中,这非常有用。

use typedmap::{TypedMap, TypedMapKey};

// Define key types
#[derive(Debug, PartialEq, Eq, Hash)]
struct Dog{name: String};
#[derive(Debug, PartialEq, Eq, Hash)]
struct Cat{name: String};

struct Bark{volume: u32};
struct Mew{pitch: f32};

// Define value type for key types
impl TypedMapKey for Dog {
    type Value = Bark;
}
impl TypedMapKey for Cat {
    type Value = Mew;
}
// Create a new empty map
let mut animal_sounds: TypedMap = TypedMap::new();
// Insert data
animal_sounds.insert(Dog { name: "Spiky".into() }, Bark { volume: 80 });
animal_sounds.insert(Cat { name: "Spot".into()  }, Mew  { pitch: 12000.0 });

// Get for Dog key get value of type Bark.
let spiky_volume = animal_sounds.get(&Dog { name: "Spiky".into() }).unwrap().volume;
assert_eq!(spiky_volume, 80); 
// Define key types
#[derive(Debug, PartialEq, Eq, Hash)]
struct EndpointGet(String);
#[derive(Debug, PartialEq, Eq, Hash)]
struct EndpointPost(usize);

// Define value type for key types
impl TypedMapKey for EndpointGet {
    type Value = String;
}

impl TypedMapKey for EndpointPost {
    type Value = u32;
}

// Create a new empty map
let mut data: TypedMap = TypedMap::new();

// Insert data
data.insert(EndpointGet("test".to_owned()), "data".to_owned());
data.insert(EndpointPost(32), 32);

您可以使用特殊的Marker类型创建更多的“类型”键值绑定。

struct Configs;
struct Services;

use typedmap::{TypedMap, TypedMapKey};

#[derive(Debug, PartialEq, Eq, Hash)]
struct EndpointGet(String);
#[derive(Debug, PartialEq, Eq, Hash)]
struct EndpointPost(usize);

struct EndpointGetConfig(String);
struct EndpointPostConfig(usize);

struct EndpointGetService {}

impl TypedMapKey<Configs> for EndpointGet {
    type Value = EndpointGetConfig;
}

impl TypedMapKey<Configs> for EndpointPost {
    type Value = EndpointPostConfig;
}

impl TypedMapKey<Services> for EndpointGet {
    type Value = EndpointGetService;
}

impl TypedMapKey<Services> for EndpointPost {
    type Value = EndpointPostService;
}


let mut configs: TypedMap<Configs> = TypedMap::new();
let mut services: TypedMap<Services> = TypedMap::new();

configs.insert(EndpointGet("test".to_owned()), EndpointGetConfig("config".to_owned()));
configs.insert(EndpointPost(10), EndpointPostConfig(20));

services.insert(EndpointGet("test".to_owned()), EndpointGetService {});
services.insert(EndpointPost(10), EndpointPostService {});

如果启用了dashmap功能,可以使用TypedDashMap,它可以并发使用,因为它底层使用Dashmap

use std::sync::Arc;
use typedmap::TypedDashMap;
use typedmap::TypedMapKey;

struct Configs;
struct Services;

#[derive(Hash, PartialEq, Eq)]
struct ServiceA(usize);

// Implement key-value mapping for Configs marker
impl TypedMapKey<Configs> for ServiceA {
    type Value = usize;
}

// Implement key-value mapping for Services marker
impl TypedMapKey<Services> for ServiceA {
    type Value = &'static str;
}

#[derive(Hash, PartialEq, Eq)]
struct ServiceB(&'static str);

// Implement key-value mapping for Configs marker
impl TypedMapKey<Configs> for ServiceB {
    type Value = Vec<&'static str>;
}

// Implement key-value mapping for Services marker
impl TypedMapKey<Services> for ServiceB {
    type Value = usize;
}

// Implement key-value mapping for default (i.e. ()) marker
impl TypedMapKey for ServiceB {
    type Value = String;
}

let configs: Arc<TypedDashMap<Configs>> = Arc::new(TypedDashMap::new());
let services: Arc<TypedDashMap<Services>> = Arc::new(TypedDashMap::new());
let default: Arc<TypedDashMap> = Arc::new(TypedDashMap::new());

let configs1 = Arc::clone(&configs);
let services1 = Arc::clone(&services);
let t1 = std::thread::spawn(move ||{
    configs1.insert(ServiceA(0), 1);
    services1.insert(ServiceA(0), "one");
});

// Line below would not compile, because TypeMapKey<Marker=()>
// is not implemented for Key.
// default.insert(Key(0), 1);

// Line below would not compile, because SerivceA key defines
// type value as usize for Configs marker (not &'static str)
// configs.insert(ServiceA(0), "one");

let configs2 = Arc::clone(&configs);
let services2 = Arc::clone(&services);
let default2 = Arc::clone(&default);
let t2 = std::thread::spawn(move || {
    configs2.insert(ServiceB("zero"), vec!["one"]);
    services2.insert(ServiceB("zero"), 32);
    default2.insert(ServiceB("zero"), "one".to_owned());
});

t1.join().unwrap();
t2.join().unwrap();

默认情况下,TypedMap接受实现std::any::Any trait(当然,还包括TypedMapKey trait)的键和值,而TypedDashMap要求键和值满足std::any::Any + Send + Sync界限。然而,TypedMapTypedDashMap都可以用两个类型参数参数化:键界限(KB)和值界限(VB)。这种机制允许限制可以存储在哈希表中的键和值的类型。这个crate提供了四种界限实现

  • bounds::AnyBounds - 表示Any界限(在TypedMap中默认使用),
  • bounds::SyncAnyBounds - 表示Any + Sync + Send界限(在TypedDashMap中默认使用),
  • clone::CloneBounds(如果启用了clone功能) - 表示Clone + Any界限 - 允许限制键/值到可克隆的类型,
  • clone::SyncCloneBounds(如果启用了 clone 功能)- 表示 Clone + Any + Send + Sync 的界限。

这些界限可以在类型签名中指定,例如。

use typedmap::{TypedMap, TypedMapKey};
use typedmap::clone::{CloneBounds};
let mut map: TypedMap::<(), CloneBounds, CloneBounds, _> = TypedMap::new_with_bounds();

可以使用 Bounds 和 HasBounds 特性来定义自己的界限,以对值添加自定义限制。例如,您可能希望强制每个值实现一个自定义的 Component 特性。这可以通过 impl_custom_bounds 和 impl_dyn_trait_wrapper 宏编写几行代码来实现。

// Your custom marker (could use also () as well)
use typedmap::{impl_custom_bounds, impl_dyn_trait_wrapper, SyncAnyBounds, TypedDashMap, TypedMapKey};
struct Components;

// Trait that each value should implement
trait Component {
    fn is_ready(&self) -> bool;
}

// Bounds
struct ComponentSyncBounds;

// This defines DynComponent that will be Any + Component, used internally to keep values
impl_dyn_trait_wrapper!(DynComponent, Component);
// This defines new "bounds" struct, that requires to impl Component and uses
// dyn DynComponent + Send + Sync as a value container
impl_custom_bounds!(ComponentSyncBounds, DynComponent, Component, +Send+Sync);

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
struct RepositoryKey(usize);
struct Repository(String);

impl TypedMapKey<Components> for RepositoryKey {
    type Value = Repository;
}

impl Component for Repository {
    fn is_ready(&self) -> bool {
        true
    }
}

// Create a new TypedDashMap that uses Components marker, keys may be Any, but value must impl Component
let state: TypedDashMap<Components, SyncAnyBounds, ComponentSyncBounds> = TypedDashMap::new_with_bounds();
state.insert(RepositoryKey(3), Repository("three".into()));

let iter = state.iter().filter(|v| {
    // We can obtain reference to DynContainer
    let dyn_container = v.value_container_ref();
    // and from DynContainer reference to &dyn Container using as_object function
    let component = dyn_container.as_object();
    component.is_ready()
});
assert_eq!(iter.count(), 1);
  • type-map - 使用类型作为键的 hashmap

许可证

根据您的选择,许可协议为以下之一:

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交的任何贡献,均应如上所述双重许可,无需任何附加条款或条件。

依赖项

~0–5.5MB