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 在 数据结构
3,695 每月下载量
用于 29 个crate (12 直接)
94KB
2K SLoC
index_vec
此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
。如果你有一堆指向不同类型向量的索引,它最有用。
该代码最初基于rustc
的IndexVec
代码,但除了简单的情况(例如Vec包装器)外,几乎全部重写。
其他crate
indexed_vec
crate早于此crate,并且是rustc
代码的更接近的副本。遗憾的是,这意味着它无法在稳定版上编译。
如果你在找一个比vec更接近map的东西,你可能会发现handy
、slotmap
或slab更符合你的需求。
常见问题解答
将define_index_type
作为过程宏不是更好吗?
可能。它不是 proc 宏,因为我倾向于尽可能地避免它们,因为我想最小化编译时间。如果关于 proc-macro 编译时间的这些问题得到解决,那么我会重新审视这个问题。
我也可能最终会添加一个不是必需的,但避免了某些粗陋性的 proc-macro 功能。
define_index_type
做得太多吗?
可能。它定义了一个类型,并在其上实现了一堆函数,以及相当多的特质。话虽如此,它的目的是让从 Vec<T>
+ usize
到 IndexVec<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