88 lines
1.6 KiB
Rust
88 lines
1.6 KiB
Rust
#[repr(C)]
|
|
#[derive(Eq, Hash, PartialEq, Debug, Clone, Copy, bytemuck::Zeroable)]
|
|
pub struct Id<I = u64>(I);
|
|
|
|
unsafe impl<I: Copy + bytemuck::Zeroable + 'static> bytemuck::Pod for Id<I> {}
|
|
|
|
pub struct IdTracker<I = u64> {
|
|
free: Vec<Id<I>>,
|
|
cur: Id<I>,
|
|
}
|
|
|
|
impl<I: IdNum> IdTracker<I> {
|
|
#[allow(clippy::should_implement_trait)]
|
|
pub fn next(&mut self) -> Id<I> {
|
|
if let Some(id) = self.free.pop() {
|
|
return id;
|
|
}
|
|
let next = self.cur.next();
|
|
std::mem::replace(&mut self.cur, next)
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub fn free(&mut self, id: Id<I>) {
|
|
self.free.push(id);
|
|
}
|
|
}
|
|
|
|
impl<I: IdNum> Id<I> {
|
|
#[allow(dead_code)]
|
|
/// for debug purposes; should this be exposed?
|
|
/// generally you want to use labels with widgets
|
|
pub(crate) fn raw(id: I) -> Self {
|
|
Self(id)
|
|
}
|
|
pub fn idx(&self) -> usize {
|
|
self.0.idx()
|
|
}
|
|
pub fn next(&self) -> Id<I> {
|
|
Self(self.0.next())
|
|
}
|
|
pub const fn preset(value: I) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
|
|
impl<I: IdNum> Default for IdTracker<I> {
|
|
fn default() -> Self {
|
|
Self {
|
|
free: Vec::new(),
|
|
cur: Id(I::first()),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait IdNum {
|
|
fn first() -> Self;
|
|
fn next(&self) -> Self;
|
|
fn idx(&self) -> usize;
|
|
}
|
|
|
|
impl IdNum for u64 {
|
|
fn first() -> Self {
|
|
0
|
|
}
|
|
|
|
fn next(&self) -> Self {
|
|
self + 1
|
|
}
|
|
|
|
fn idx(&self) -> usize {
|
|
*self as usize
|
|
}
|
|
}
|
|
|
|
impl IdNum for u32 {
|
|
fn first() -> Self {
|
|
0
|
|
}
|
|
|
|
fn next(&self) -> Self {
|
|
self + 1
|
|
}
|
|
|
|
fn idx(&self) -> usize {
|
|
*self as usize
|
|
}
|
|
}
|