andex
andex (Array iNDEX) is a single-file, zero-dependency rust crate that helps us create a strongly-typed, zero-cost, numerically bound array index and the corresponding array type with the provided size. The index is safe in the sense that an out-of-bounds value can't be created, and the array type can't be indexed by any other types.
This is useful in scenarios where we have different arrays inside a
struct and we want reference members without holding proper
references that could "lock" the whole struct. It may also be useful
when programming an
Entity Component System.
And it's all done without requiring the use of any macros.
Usage
Creating the andex types
Andex is the index type and AndexableArray is the type of
the array wrapper.
The recommended approach to use andex is as follows:
- Create a unique empty type
; - Create a type alias for the
Andextype that's parameterized with that type:type MyIdx = ; - Create a type alias for the
AndexableArraytype that's indexed by theAndexalias created above:type MyU32 = SIZE }>;
Creating andex instances
When an andex is created, it knows at compile time the size of the array it indexes, and all instances are assumed to be within bounds.
For this reason, it's useful to limit the way Andex's are
created. The ways we can get an instance is:
-
Via
new, passing the value as a generic const argument:const first : MyIdx = ;This checks that the value is valid at compile time, as long as you use it to create
constvariables. -
Via
try_from, which returnsResult<Andex, Error>that has to be checked or explicitly ignored:if let Ok = try_from -
By iterating:
for idx in iter
The assumption that the instances can only hold valid values allows us
to use get_unsafe and get_unsafe_mut in the indexer
implementation, which provides a bit of optimization by preventing the
bound check when indexing.
Creating andexable arrays
AndexableArray instances are less restrictive. They can be created
in several more ways:
- Using
Defaultif the underlying type supports it:type MyU32 = SIZE }>; let myu32 = default; - Using
Fromwith an appropriate array:let myu32 = from; - Collecting an iterator with the proper elements and size:
Note:let myu32 = .;collectpanics if the iterator returns a different number of elements.
Using andexable arrays
Besides indexing them with a coupled Andex instance, we can
also access the inner array by using as_ref, iterate it in a
for loop (using one of the IntoIterator implementations) or
even get the inner array by consuming the AndexableArray.
Full example
use TryFrom;
use *;
// Create the andex type alias:
// First, we need an empty type that we use as a marker:
;
// The andex type takes the marker (for uniqueness)
// and the size of the array as parameters:
type MyIdx = ;
// Create the array wrapper:
type MyU32 = SIZE }>;
// We can create other arrays indexable by the same Andex:
type MyF64 = SIZE }>;
Alternatives
These alternatives may fit better cases where we need unbound indexes (maybe for vector):