use parking_lot::Mutex;
use wgt::Backend;
use crate::{id, Epoch, Index};
use std::fmt::Debug;
#[derive(Debug, Default)]
pub struct IdentityManager {
free: Vec<Index>,
epochs: Vec<Epoch>,
}
impl IdentityManager {
pub fn alloc<I: id::TypedId>(&mut self, backend: Backend) -> I {
match self.free.pop() {
Some(index) => I::zip(index, self.epochs[index as usize], backend),
None => {
let epoch = 1;
let id = I::zip(self.epochs.len() as Index, epoch, backend);
self.epochs.push(epoch);
id
}
}
}
pub fn free<I: id::TypedId + Debug>(&mut self, id: I) {
let (index, epoch, _backend) = id.unzip();
let pe = &mut self.epochs[index as usize];
assert_eq!(*pe, epoch);
if epoch < id::EPOCH_MASK {
*pe = epoch + 1;
self.free.push(index);
}
}
}
pub trait IdentityHandler<I>: Debug {
type Input: Clone + Debug;
fn process(&self, id: Self::Input, backend: Backend) -> I;
fn free(&self, id: I);
}
impl<I: id::TypedId + Debug> IdentityHandler<I> for Mutex<IdentityManager> {
type Input = ();
fn process(&self, _id: Self::Input, backend: Backend) -> I {
self.lock().alloc(backend)
}
fn free(&self, id: I) {
self.lock().free(id)
}
}
pub trait IdentityHandlerFactory<I> {
type Filter: IdentityHandler<I>;
fn spawn(&self) -> Self::Filter;
}
#[derive(Debug)]
pub struct IdentityManagerFactory;
impl<I: id::TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
type Filter = Mutex<IdentityManager>;
fn spawn(&self) -> Self::Filter {
Mutex::new(IdentityManager::default())
}
}
pub trait GlobalIdentityHandlerFactory:
IdentityHandlerFactory<id::AdapterId>
+ IdentityHandlerFactory<id::DeviceId>
+ IdentityHandlerFactory<id::PipelineLayoutId>
+ IdentityHandlerFactory<id::ShaderModuleId>
+ IdentityHandlerFactory<id::BindGroupLayoutId>
+ IdentityHandlerFactory<id::BindGroupId>
+ IdentityHandlerFactory<id::CommandBufferId>
+ IdentityHandlerFactory<id::RenderBundleId>
+ IdentityHandlerFactory<id::RenderPipelineId>
+ IdentityHandlerFactory<id::ComputePipelineId>
+ IdentityHandlerFactory<id::QuerySetId>
+ IdentityHandlerFactory<id::BufferId>
+ IdentityHandlerFactory<id::StagingBufferId>
+ IdentityHandlerFactory<id::TextureId>
+ IdentityHandlerFactory<id::TextureViewId>
+ IdentityHandlerFactory<id::SamplerId>
+ IdentityHandlerFactory<id::SurfaceId>
{
}
impl GlobalIdentityHandlerFactory for IdentityManagerFactory {}
pub type Input<G, I> = <<G as IdentityHandlerFactory<I>>::Filter as IdentityHandler<I>>::Input;
#[test]
fn test_epoch_end_of_life() {
use id::TypedId as _;
let mut man = IdentityManager::default();
man.epochs.push(id::EPOCH_MASK);
man.free.push(0);
let id1 = man.alloc::<id::BufferId>(Backend::Empty);
assert_eq!(id1.unzip().0, 0);
man.free(id1);
let id2 = man.alloc::<id::BufferId>(Backend::Empty);
assert_eq!(id2.unzip().0, 1);
}