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