185. Range<NonZeroU32> — Iterate NonZero Integers Without Re-Wrapping Every Step
NonZeroU32 keeps Option<Id> at 4 bytes — but until Rust 1.96 you couldn’t iterate lo..hi over them. You’d drop back to u32 and re-wrap every step.
NonZeroU32 and friends are great for indices and IDs because Option<NonZeroU32> fits the niche and stays 4 bytes wide. The catch: Range<NonZeroU32> wasn’t an iterator. The moment you wanted to walk a range of IDs, you fell back to plain u32 and unwrapped your way back in:
| |
Three problems: the Range drops the invariant, every step pays for an unwrap, and a future refactor that changes the bound type silently swaps your iterator out from under you.
Rust 1.96 stabilized Step for NonZero integers (PR #127534). Now the range itself is an iterator that yields NonZeroU32:
| |
It works for the inclusive form too, so you can sweep the whole representable range without overflow gymnastics:
| |
If you keep your IDs in a NonZeroU32 newtype to shrink Option, the iteration story now matches: the range yields the right type the whole way through, no per-step unwrap, no invariant laundering through u32.