index_type
A Rust library providing strongly typed indices for collections, designed for both std and no_std environments.
What are typed indices?
In standard Rust, collections use usize for indexing. This works well but provides no compile-time
protection against using an index from one collection with another. Typed indices solve this by
creating custom index types that are statically associated with specific collections.
In standard Rust, a raw usize can index any collection. This allows subtle bugs:
let nodes: = vec!; // 10 nodes
let edges: = vec!; // 5 edges
let node_index = 3;
nodes;
edges; // compiles just fine!
With typed indices, cross-contamination becomes a compile error:
# use index_type::{IndexType, typed_vec::TypedVec};
# #[derive(Default, Clone, Copy)]
# struct Node;
# #[derive(Default, Clone, Copy)]
# struct Edge;
#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct NodeId(u32);
#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct EdgeId(u32);
let nodes: TypedVec<NodeId, Node> = TypedVec::new();
let edges: TypedVec<EdgeId, Edge> = TypedVec::new();
let node_id = NodeId(3);
nodes[node_id]; // OK
edges[node_id]; // COMPILE ERROR: expected EdgeId, found NodeId
Features
- Type Safety: Prevents accidental misuse of indices between different collections at compile time
no_stdSupport: Works in embedded systems and otherno_stdenvironments- Memory Efficiency: Use smaller integer types (
u8,u16) for indices when collections are bounded - Niche Optimization: Supports
NonZerotypes soOption<Index>has the same size asIndex - Rich Collections: Provides
TypedSlice,TypedVec,TypedArray, andTypedArrayVec - Derive Macros: Easy to define custom index types with
#[derive(IndexType)] - Range Iterators: Iterate over ranges using custom index types
Quick Start
use IndexType;
use TypedVec;
;
let mut vec: = new;
let idx = vec.push;
assert_eq!;
// vec[0usize]; // This won't compile - requires MyIndex type
Defining Index Types
Use the #[derive(IndexType)] macro on a newtype struct:
use IndexType;
;
The macro automatically implements the [IndexType] trait for your custom type. By default,
it generates an error type MyIndexTooBigError. You can specify a custom error type:
use IndexType;
use IndexTooBigError;
;
;
Typed Collections
TypedVec
A growable vector with typed indexing. See TypedVec for the full API.
use IndexType;
use TypedVec;
;
let mut nodes: = new;
let id0 = nodes.push;
let id1 = nodes.push;
println!;
Operations that can fail due to index overflow have both panicking and fallible variants:
let mut vec: = new;
vec.push; // Panics if index too big
let result = vec.try_push; // Returns Result<(), Error>
TypedSlice
A slice wrapper with typed indexing. See TypedSlice for the full API.
use IndexType;
use TypedVec;
use TypedSlice;
;
let vec: = from_vec;
let slice: & = vec.as_slice;
// Safe indexing with custom type
let first = slice;
TypedArray
A fixed-size array with typed indexing. The array length N is checked at compile time
to ensure it fits within the index type's range. See TypedArray for the full API.
use IndexType;
use TypedArray;
;
let mut pixels: = default;
pixels = ; // Red
pixels = ; // Green
TypedArrayVec
A fixed-capacity vector ideal for embedded systems. It never allocates after creation.
See TypedArrayVec for the full API.
use IndexType;
use TypedArrayVec;
;
let mut buffer: = new;
buffer.push;
assert_eq!;
A TypedArrayVec<u8, u8, 3> is only 4 bytes (3 bytes for data + 1 byte for length).
Memory-Efficient Indices
Using smaller integer types reduces memory when storing many indices:
; // Only 1 byte per index!
println!;
println!;
For collections with at most 255 elements, u8 saves 75% memory compared to u32.
NonZero Indices and Niche Optimization
Using NonZero types enables niche optimization, where Option<Index>
has the same size as Index:
use IndexType;
use NonZeroU32;
;
// Option<SafeId> takes only 4 bytes, not 8!
assert_eq!;
assert_eq!;
Range Iterators
Standard Rust ranges require the unstable Step trait. This crate provides
TypedRangeIterExt for iterating over ranges with custom index types:
use IndexType;
use TypedRangeIterExt;
;
let start = MyIdx;
let end = MyIdx;
for idx in .iter
Typed Enumerate
Use TypedIteratorExt to enumerate any iterator with typed indices:
use IndexType;
use TypedIteratorExt;
;
let pairs: =
.into_iter
.
.collect;
assert_eq!;
assert_eq!;
Macros
Convenience macros for creating typed collections:
use ;
use TypedVec;
use TypedArray;
use TypedArrayVec;
use TypedSlice;
;
// Create a TypedVec
let v: = typed_vec!;
// Create a TypedArray
let a: = typed_array!;
// Create a TypedArrayVec
let av: = typed_array_vec!;
// Create a TypedSlice reference
let s: & = typed_slice!;
Error Handling
Operations that can fail due to index overflow return Result types:
use IndexType;
use TypedVec;
; // MAX_RAW_INDEX = 255
let mut vec: = new;
// Fill up to capacity
for i in 0..255
// This fails gracefully
assert!;
no_std Compatibility
This crate is no_std compatible. The alloc feature (enabled by default) enables
heap-allocated collections (TypedVec and related macros).
For pure no_std environments without heap allocation, disable the alloc feature:
[]
= { = "...", = false }
License: MIT OR Apache-2.0