10次发布

0.1.4 2024年8月17日
0.1.3 2021年10月1日
0.1.2 2020年6月28日
0.1.1 2020年5月30日
0.0.3 2019年9月17日

#61数据结构

Download history 1445/week @ 2024-05-03 1426/week @ 2024-05-10 1538/week @ 2024-05-17 1428/week @ 2024-05-24 54055/week @ 2024-05-31 43821/week @ 2024-06-07 1552/week @ 2024-06-14 1071/week @ 2024-06-21 1030/week @ 2024-06-28 888/week @ 2024-07-05 998/week @ 2024-07-12 931/week @ 2024-07-19 980/week @ 2024-07-26 1122/week @ 2024-08-02 689/week @ 2024-08-09 764/week @ 2024-08-16

3,695 每月下载量
用于 29 个crate (12 直接)

MIT/Apache

94KB
2K SLoC

index_vec

Docs crates.io Github CI

此crate帮助定义围绕usize(或其他整数)和Vec<T>的“newtype”风格的包装,以在零成本下获得额外的类型安全性。

示例/概述

use index_vec::{IndexVec, IndexSlice, index_vec};

index_vec::define_index_type! {
    // Define StrIdx to use only 32 bits internally (you can use usize, u16,
    // and even u8).
    pub struct StrIdx = u32;

    // The defaults are very reasonable, but this macro can let
    // you customize things quite a bit:

    // By default, creating a StrIdx would check an incoming `usize against
    // `u32::max_value()`, as u32 is the wrapped index type. Lets imagine that
    // StrIdx has to interface with an external system that uses signed ints.
    // We can change the checking behavior to complain on i32::max_value()
    // instead:
    MAX_INDEX = i32::max_value() as usize;

    // We can also disable checking all-together if we are more concerned with perf
    // than any overflow problems, or even do so, but only for debug builds: Quite
    // pointless here, but an okay example
    DISABLE_MAX_INDEX_CHECK = cfg!(not(debug_assertions));

    // And more too, see this macro's docs for more info.
}

// Create a vector which can be accessed using `StrIdx`s.
let mut strs: IndexVec<StrIdx, &'static str> = index_vec!["strs", "bar", "baz"];

// l is a `StrIdx`
let l = strs.last_idx();
assert_eq!(strs[l], "baz");

let new_i = strs.push("quux");
assert_eq!(strs[new_i], "quux");

// The slice APIs are wrapped as well.
let s: &IndexSlice<StrIdx, [&'static str]> = &strs[StrIdx::new(1)..];
assert_eq!(s[0], "bar");

// Indices are mostly interoperable with `usize`, and support
// a lot of what you might want to do to an index.

// Comparison
assert_eq!(StrIdx::new(0), 0usize);

// Addition
assert_eq!(StrIdx::new(0) + 1, StrIdx::new(1));

// Subtraction
assert_eq!(StrIdx::new(1) - 1, StrIdx::new(0));

// Wrapping
assert_eq!(StrIdx::new(5) % strs.len(), StrIdx::new(1));
// ...

背景

目标是帮助使用type FooIdx = usize来访问具有某种东西的Vec<Foo>,从而可以静态地防止在Vec<Bar>中使用FooIdx。如果你有一堆指向不同类型向量的索引,它最有用。

该代码最初基于rustcIndexVec代码,但除了简单的情况(例如Vec包装器)外,几乎全部重写。

其他crate

indexed_vec crate早于此crate,并且是rustc代码的更接近的副本。遗憾的是,这意味着它无法在稳定版上编译。

如果你在找一个比vec更接近map的东西,你可能会发现handyslotmapslab更符合你的需求。

常见问题解答

define_index_type作为过程宏不是更好吗?

可能。它不是 proc 宏,因为我倾向于尽可能地避免它们,因为我想最小化编译时间。如果关于 proc-macro 编译时间的这些问题得到解决,那么我会重新审视这个问题。

我也可能最终会添加一个不是必需的,但避免了某些粗陋性的 proc-macro 功能。

define_index_type 做得太多吗?

可能。它定义了一个类型,并在其上实现了一堆函数,以及相当多的特质。话虽如此,它的目的是让从 Vec<T> + usizeIndexVec<I, T> 的旅程尽可能轻松。如果让它由开发者来做这些事情,那么使用起来将会非常繁琐,以至于不值得使用。

define_index_type 中的选项语法很糟糕。

我欢迎建议。

它支持 no_std 吗?

是的,尽管它当然使用了 extern crate alloc;

它支持 serde 吗?

是的,但只有当你开启 serde 功能时。

计划的功能有哪些?

计划是有点强,但以下是我觉得有用的东西。

  • 支持切片/vec API 的任何剩余部分。
  • 添加 SmallVec/ArrayVec 的类型安全包装器(当然,在 cargo feature 后面)。
  • 为 define_index_type 宏提供更好的语法(没有具体的想法)。
  • 允许生成的类型是元组结构体,或使用特定的字段名。
  • 允许使用索引的类型,如 NonZeroU32 等,如果可以做到合理的话。
  • 如果可以做到合理的话,允许使用像 NonZeroU32 这样的索引类型。
  • ...

许可证

这是基于 rustc 源代码,保留了它的双许可状态,即 MIT (LICENSE-MIT) / Apache 2.0 (LICENSE-APACHE)。

依赖

~0–475KB
~11K SLoC