flux_common/
index.rs

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