flux_common/index.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
use std::{marker::PhantomData, sync::atomic::AtomicUsize};
pub use rustc_index::{Idx, IndexVec};
/// A generator of fresh indices.
///
/// It can generate any index created with the [`newtype_index`] macro.
///
/// If you use more than one [`IndexGen`] uniqueness is only guaranteed for indices that come from
/// the same generator.
///
/// [`newtype_index`]: rustc_index::newtype_index
pub struct IndexGen<I> {
count: AtomicUsize,
_marker: PhantomData<I>,
}
impl<I: Idx> IndexGen<I> {
pub fn new() -> Self {
Self { count: AtomicUsize::new(0), _marker: PhantomData }
}
pub fn skipping(skip: usize) -> Self {
let gen = IndexGen::new();
gen.skip(skip);
gen
}
/// Generate a fresh index of type `I`.
///
/// ```ignore
/// # use flux_common::index::IndexGen;
/// # use flux_common::newtype_index;
///
/// newtype_index! {
/// struct Idx {
/// DEBUG_FORMAT = "idx_{}",
/// }
/// }
///
/// let mut gen = IndexGen::new();
/// let idx1: Idx = gen.fresh();
/// let idx2: Idx = gen.fresh();
/// assert_ne!(idx1, idx2);
/// ```
pub fn fresh(&self) -> I {
let index = self
.count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
I::new(index)
}
/// Skip `n` indices
pub fn skip(&self, n: usize) {
self.count
.fetch_add(n, std::sync::atomic::Ordering::Relaxed);
}
}
impl<I: Idx> Default for IndexGen<I> {
fn default() -> Self {
Self::new()
}
}