[][src]Crate index_vec

This crate helps with defining "newtype"-style wrappers around usize (or other integers), and Vec<T> so that some additional type safety can be gained at zero cost.

It's was initially derived from some code in rustc, but has diverged since then.

Example / Overview

use index_vec::{IndexVec, 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");

// 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, 1usize);

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

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

Background

The goal is to help with the pattern of using a type FooIdx = usize to access a Vec<Foo> with something that can statically prevent using a FooIdx in a Vec<Bar>. It's most useful if you have a bunch of indices referring to different sorts of vectors.

Much of the code for this is taken from rustc's IndexVec code, however it's diverged a decent amount at this point. Some notable changes:

  • No usage of unstable features.
  • Different syntax for defining index types.
  • More complete mirroring of Vec's API.
  • Allows use of using other index types than u32/usize.
  • More flexible behavior around how strictly some checks are performed,

Other crates

The indexed_vec crate predates this, and is a much closer copy of the code from rustc. Unfortunately, this means it does not compile on stable.

If you're looking for something further from a vec and closer to a map, you might find handy, slotmap, or slab to be closer what you want.

Modules

example_generated

This module is just for documentation purposes, and is hidden behind the example_generated feature, which is off by default.

Macros

define_index_type

Generate the boilerplate for a newtyped index struct, for use with IndexVec.

index_vec

A macro equivalent to the stdlib's vec![], but producing an IndexVec.

Structs

IndexVec

A Vec that only accepts indices of a specific type.

Traits

Idx

Represents a wrapped value convertable to and from a usize.