Looking in more detail at your implementation that tests exhausting the range of IDs, it’s still unsafe. Okay it panics if one thread gets max, but another thread will allocate a wrapped ID. Trying to undo the increment will race with all the other threads. Okay you can allow a buffer range to protect against that, but it seems messy. Also I don’t like panicking if IDs run out.
Thinking more about it, using features to switch the implementation globally isn’t that nice either, as this could potentially be used by several crates, maybe way down the dependency chain. It’s hard for a crate owner to reason about it if they don’t know what implementation they’re getting.
Finally I’ve found a way to solve this. I keep the current
u32 owner ID. The current
QCellOwner::new() will be moved to
fast_new() and marked unsafe. Just that one call is marked unsafe because unsafe use of that call (e.g. calling it 2^32 times) is the only way for things to go wrong. The replacement “slow but safe”
new() call will use a mutex and a free list to allocate owner IDs. This suits the pattern of ID allocation that I expect to see in practice, i.e. relatively small sets of owner IDs used by each component, but maybe very many components created and destroyed. The fast and slow implementations allocate from different pools of owner IDs. I think this cannot be used maliciously now.
I’ll get this tested and published soonish.