#map #container #send-sync #hash-map

anymap2

为每种类型的单个值提供安全且方便的存储

1 个不稳定版本

0.13.0 2021年4月10日

1031数据结构 中排名

Download history 20098/week @ 2023-12-16 12394/week @ 2023-12-23 16581/week @ 2023-12-30 25925/week @ 2024-01-06 25622/week @ 2024-01-13 25224/week @ 2024-01-20 26687/week @ 2024-01-27 26697/week @ 2024-02-03 28688/week @ 2024-02-10 29207/week @ 2024-02-17 37471/week @ 2024-02-24 30235/week @ 2024-03-02 28455/week @ 2024-03-09 28310/week @ 2024-03-16 32291/week @ 2024-03-23 22858/week @ 2024-03-30

115,982 每月下载量
219 个crate(13 个直接) 中使用

MIT/Apache

43KB
781

🗺️ AnyMap

存储零个或一个每种类型的映射。

Crates.io CI Coverage Status

AnyMap 是一个围绕 HashMap<TypeId, Box<Any>> 的包装器,暴露一个类型安全的、健壮的接口。

分开的 CloneAny* 特性意味着在映射中的所有类型上强制执行额外的 Send / Sync 约束,这是从 anymap crate 中的用户体验损失。这是避免以下警告的方法: https://github.com/rust-lang/rust/issues/51443

注意: 这是 anymap 的一个分支,具有额外的约束,即如果映射中的任何类型需要是 SendSync 或两者,则映射中的所有类型都具有该约束。当上述Rust问题修复后,这个分支应该消失。我只是创建它,以免更新Rust意外破坏映射功能。

用法

将以下内容添加到 Cargo.toml

anymap2 = "0.13.0"

代码

use anymap2::AnyMap; // Map<dyn Any>

let mut data = AnyMap::new();
assert_eq!(data.get(), None::<&i32>);

data.insert(42i32);
assert_eq!(data.get(), Some(&42i32));

data.remove::<i32>();
assert_eq!(data.get::<i32>(), None);

#[derive(Clone, PartialEq, Debug)]
struct Foo {
    value: String,
}

assert_eq!(data.get::<Foo>(), None);
data.insert(Foo {
    value: format!("foo"),
});
assert_eq!(
    data.get(),
    Some(&Foo {
        value: format!("foo")
    })
);

data.get_mut::<Foo>().map(|foo| foo.value.push('t'));
assert_eq!(&*data.get::<Foo>().unwrap().value, "foot");

unsafe 代码

此库出于多个原因使用了大量不安全代码

  • 为了支持 AnyCloneAny,需要使用 unsafe 代码(因为 downcast 方法是在 impl Any 中定义的,而不是作为 trait 方法;我认为这是 std::any::Any 结构的历史细节);如果您想放弃 Clone 支持,则可以移除这种不安全性。

  • 出于性能考虑,跳过因数据结构的不变性而无需进行的各种检查(当它被用作哈希表键时,不需要检查类型 ID)并简化哈希(类型 ID 已经是很好的哈希值,无需通过 SipHash 对其进行篡改)。

在不移除一些功能的情况下,无法从这个库中完全移除所有不安全性。不过,以牺牲 CloneAny 功能以及原始接口和可能的后台支持为代价,您肯定可以移除所有 unsafe 代码。以下是您如何做到这一点:

  • 移除其泛型性;
  • anymap::raw 合并到正常接口中,使其扁平化;
  • 将类似 .map(|any| unsafe { any.downcast_unchecked() }) 的代码更改为 .and_then(|any| any.downcast())(性能成本:一个额外的多余类型 ID 比较和间接比较);
  • 丢弃 TypeIdHasher,因为类型 ID 的转换是不允许的(成本:每次访问都进行 SIP 篡改 u64)。

是的,安全性的性能成本相当小。更严重的问题是失去了 Clone 以及可能 Send + Sync

但坦白说,如果您想完成所有这些工作,从头开始编写会更简单、更快。实际上,库的核心非常简单且完全安全,如第一个提交中的 src/lib.rs(请注意,该代码需要进行一些语法更改才能运行;它在 Rust 1.0 之前编写,有一些像 Any:'static 这样的代码,而现在我们有 Any + 'static)。

作者

Chris Morgan (chris-morgan) 是 AnyMap 的主要作者和维护者。

许可证

此库与 Rust 的条款类似:MIT 许可证和 Apache 许可证(版本 2.0)的双重许可。

有关详细信息,请参阅 LICENSE-APACHE、LICENSE-MIT 和 COPYRIGHT。

无运行时依赖项