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