1use alloc::vec::Vec;
2use core::{fmt::Debug, marker::PhantomData};
3
4use crate::{
5 id::{Id, Marker},
6 lock::{rank, Mutex},
7 Epoch, Index,
8};
9
10#[derive(Copy, Clone, Debug, PartialEq)]
11enum IdSource {
12 External,
13 Allocated,
14 None,
15}
16
17#[derive(Debug)]
40pub(super) struct IdentityValues {
41 free: Vec<(Index, Epoch)>,
42 next_index: Index,
43 count: usize,
44 id_source: IdSource,
48}
49
50impl IdentityValues {
51 pub fn alloc<T: Marker>(&mut self) -> Id<T> {
56 assert!(
57 self.id_source != IdSource::External,
58 "Mix of internally allocated and externally provided IDs"
59 );
60 self.id_source = IdSource::Allocated;
61
62 self.count += 1;
63 match self.free.pop() {
64 Some((index, epoch)) => Id::zip(index, epoch + 1),
65 None => {
66 let index = self.next_index;
67 self.next_index += 1;
68 let epoch = 1;
69 Id::zip(index, epoch)
70 }
71 }
72 }
73
74 pub fn mark_as_used<T: Marker>(&mut self, id: Id<T>) -> Id<T> {
75 assert!(
76 self.id_source != IdSource::Allocated,
77 "Mix of internally allocated and externally provided IDs"
78 );
79 self.id_source = IdSource::External;
80
81 self.count += 1;
82 id
83 }
84
85 pub fn release<T: Marker>(&mut self, id: Id<T>) {
87 if let IdSource::Allocated = self.id_source {
88 let (index, epoch) = id.unzip();
89 self.free.push((index, epoch));
90 }
91 self.count -= 1;
92 }
93
94 pub fn count(&self) -> usize {
95 self.count
96 }
97}
98
99#[derive(Debug)]
100pub struct IdentityManager<T: Marker> {
101 pub(super) values: Mutex<IdentityValues>,
102 _phantom: PhantomData<T>,
103}
104
105impl<T: Marker> IdentityManager<T> {
106 pub fn process(&self) -> Id<T> {
107 self.values.lock().alloc()
108 }
109 pub fn mark_as_used(&self, id: Id<T>) -> Id<T> {
110 self.values.lock().mark_as_used(id)
111 }
112 pub fn free(&self, id: Id<T>) {
113 self.values.lock().release(id)
114 }
115}
116
117impl<T: Marker> IdentityManager<T> {
118 pub fn new() -> Self {
119 Self {
120 values: Mutex::new(
121 rank::IDENTITY_MANAGER_VALUES,
122 IdentityValues {
123 free: Vec::new(),
124 next_index: 0,
125 count: 0,
126 id_source: IdSource::None,
127 },
128 ),
129 _phantom: PhantomData,
130 }
131 }
132}
133
134#[test]
135fn test_epoch_end_of_life() {
136 use crate::id;
137 let man = IdentityManager::<id::markers::Buffer>::new();
138 let id1 = man.process();
139 assert_eq!(id1.unzip(), (0, 1));
140 man.free(id1);
141 let id2 = man.process();
142 assert_eq!(id2.unzip(), (0, 2));
144}