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}