index_type 0.1.2

Type-safe newtype indices for Rust
Documentation
# 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:
```rust
let nodes: Vec<Node> = vec![Node::default(); 10];  // 10 nodes
let edges: Vec<Edge> = vec![Edge::default(); 5];   // 5 edges
let node_index = 3;
nodes[node_index];
edges[node_index]; // compiles just fine!
```

With typed indices, cross-contamination becomes a compile error:
```rust
#[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> = typed_vec![Node::default(); 10];
let edges: TypedVec<EdgeId, Edge> = typed_vec![Edge::default(); 10];
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_std` Support**: Works in embedded systems and other `no_std` environments
- **Memory Efficiency**: Use smaller integer types (`u8`, `u16`) for indices when collections are bounded
- **Niche Optimization**: Supports [`NonZero`]core::num::NonZero types so `Option<Index>` has the same size as `Index`
- **Rich Collections**: Provides [`TypedSlice`]crate::typed_slice::TypedSlice, [`TypedVec`]crate::typed_vec::TypedVec, [`TypedArray`]crate::typed_array::TypedArray, and [`TypedArrayVec`]crate::typed_array_vec::TypedArrayVec
- **Derive Macros**: Easy to define custom index types with `#[derive(IndexType)]`
- **Range Iterators**: Iterate over ranges using custom index types

### Quick Start

```rust
use index_type::IndexType;
use index_type::typed_vec::TypedVec;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct MyIndex(u32);

let mut vec: TypedVec<MyIndex, i32> = TypedVec::new();
let idx = vec.push(42);

assert_eq!(vec[idx], 42);
// vec[0usize]; // This won't compile - requires MyIndex type
```

### Defining Index Types

Use the `#[derive(IndexType)]` macro on a newtype struct:

```rust
use index_type::IndexType;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct MyIndex(u32);
```

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:

```rust
use index_type::IndexType;
use index_type::IndexTooBigError;

#[derive(Debug, IndexTooBigError)]
#[index_too_big_error(msg = "item id too big")]
struct ItemIdTooBigError;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[index_type(error = ItemIdTooBigError)]
struct ItemId(u32);
```

### Typed Collections

#### TypedVec

A growable vector with typed indexing. See [`TypedVec`](crate::typed_vec::TypedVec) for the full API.

```rust
use index_type::IndexType;
use index_type::typed_vec::TypedVec;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct NodeId(u32);

let mut nodes: TypedVec<NodeId, String> = TypedVec::new();
let id0 = nodes.push("Alice".to_string());
let id1 = nodes.push("Bob".to_string());

println!("Node 0: {}", nodes[id0]);
```

Operations that can fail due to index overflow have both panicking and fallible variants:

```rust
let mut vec: TypedVec<MyIndex, i32> = TypedVec::new();
vec.push(1);                              // Panics if index too big
let result = vec.try_push(2);             // Returns Result<(), Error>
```

#### TypedSlice

A slice wrapper with typed indexing. See [`TypedSlice`](crate::typed_slice::TypedSlice) for the full API.

```rust
use index_type::IndexType;
use index_type::typed_vec::TypedVec;
use index_type::typed_slice::TypedSlice;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct RowId(u16);

let vec: TypedVec<RowId, f64> = TypedVec::from_vec(vec![1.0, 2.0, 3.0]);
let slice: &TypedSlice<RowId, f64> = vec.as_slice();

// Safe indexing with custom type
let first = slice[RowId::ZERO];
```

#### 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`](crate::typed_array::TypedArray) for the full API.

```rust
use index_type::IndexType;
use index_type::typed_array::TypedArray;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct PixelIdx(u8);

let mut pixels: TypedArray<PixelIdx, [u8; 3], 4> = TypedArray::default();
pixels[PixelIdx::ZERO] = [255, 0, 0];  // Red
pixels[PixelIdx(1)] = [0, 255, 0];     // Green
```

#### TypedArrayVec

A fixed-capacity vector ideal for embedded systems. It never allocates after creation.
See [`TypedArrayVec`](crate::typed_array_vec::TypedArrayVec) for the full API.

```rust
use index_type::IndexType;
use index_type::typed_array_vec::TypedArrayVec;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct BufferIndex(u8);

let mut buffer: TypedArrayVec<BufferIndex, u8, 16> = TypedArrayVec::new();
buffer.push(42);
assert_eq!(buffer.len().to_raw_index(), 1);
```

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:

```rust
#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct SmallIndex(u8);  // Only 1 byte per index!

println!("SmallIndex: {} bytes", std::mem::size_of::<SmallIndex>());
println!("u32 index: {} bytes", std::mem::size_of::<u32>());
```

For collections with at most 255 elements, `u8` saves 75% memory compared to `u32`.

### NonZero Indices and Niche Optimization

Using [`NonZero`](core::num::NonZero) types enables niche optimization, where `Option<Index>`
has the same size as `Index`:

```rust
use index_type::IndexType;
use core::num::NonZeroU32;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct SafeId(NonZeroU32);

// Option<SafeId> takes only 4 bytes, not 8!
assert_eq!(std::mem::size_of::<SafeId>(), 4);
assert_eq!(std::mem::size_of::<Option<SafeId>>(), 4);
```

### Range Iterators

Standard Rust ranges require the unstable [`Step`](core::iter::Step) trait. This crate provides
[`TypedRangeIterExt`](crate::typed_range_iter::TypedRangeIterExt) for iterating over ranges with custom index types:

```rust
use index_type::IndexType;
use index_type::typed_range_iter::TypedRangeIterExt;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct MyIdx(u32);

let start = MyIdx(5);
let end = MyIdx(10);

for idx in (start..end).iter() {
    println!("{:?}", idx);
}
```

### Typed Enumerate

Use [`TypedIteratorExt`](crate::typed_enumerate::TypedIteratorExt) to enumerate any iterator with typed indices:

```rust
use index_type::IndexType;
use index_type::typed_enumerate::TypedIteratorExt;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct RowIdx(u32);

let pairs: Vec<_> = ["a", "b", "c"]
    .into_iter()
    .typed_enumerate::<RowIdx>()
    .collect();

assert_eq!(pairs[1].0, RowIdx(1));
assert_eq!(pairs[1].1, "b");
```

### Macros

Convenience macros for creating typed collections:

```rust
use index_type::{typed_vec, typed_array, typed_array_vec, typed_slice, typed_slice_mut, IndexType};
use index_type::typed_vec::TypedVec;
use index_type::typed_array::TypedArray;
use index_type::typed_array_vec::TypedArrayVec;
use index_type::typed_slice::TypedSlice;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct MyIndex(u32);

// Create a TypedVec
let v: TypedVec<MyIndex, i32> = typed_vec![1, 2, 3];

// Create a TypedArray
let a: TypedArray<MyIndex, i32, 3> = typed_array![1, 2, 3];

// Create a TypedArrayVec
let av: TypedArrayVec<MyIndex, u8, 4> = typed_array_vec![1, 2, 3, 4];

// Create a TypedSlice reference
let s: &TypedSlice<MyIndex, i32> = typed_slice![1, 2, 3];
```

### Error Handling

Operations that can fail due to index overflow return `Result` types:

```rust
use index_type::IndexType;
use index_type::typed_vec::TypedVec;

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct MyIndex(u8);  // MAX_RAW_INDEX = 255

let mut vec: TypedVec<MyIndex, i32> = TypedVec::new();

// Fill up to capacity
for i in 0..255 {
    vec.try_push(i).unwrap();
}

// This fails gracefully
assert!(vec.try_push(255).is_err());
```

### no_std Compatibility

This crate is `no_std` compatible. The `alloc` feature (enabled by default) enables
heap-allocated collections ([`TypedVec`](crate::typed_vec::TypedVec) and related macros).

For pure `no_std` environments without heap allocation, disable the `alloc` feature:

```toml
[dependencies]
index_type = { version = "...", default-features = false }
```


License: MIT OR Apache-2.0