use crate::{pool::Pool, IdAble}; use core::marker::PhantomData; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; pub trait Behavior: Sized { type Id: IdAble; type Return; fn next(pool: &mut Pool) -> Self::Return; } #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq)] pub struct Checked { _p: PhantomData, } #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq)] pub struct UnChecked { _p: PhantomData, } #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq)] pub struct Wrapping { _p: PhantomData, } impl Behavior for Checked { type Id = Id; type Return = Result; /// checked `::next()` method, id is always unique fn next(pool: &mut Pool) -> Self::Return { if pool.buffer.start < pool.buffer.end { let result = pool.buffer.start; pool.buffer.start += pool.one; Ok(result) } else { Err(CheckedError::PoolEmpty) } } } impl Behavior for UnChecked { type Id = Id; type Return = Id; /// unchecked `::next()` method, no checks and gurantees given fn next(pool: &mut Pool) -> Self::Return { let result = pool.buffer.start; pool.buffer.start += pool.one; result } } impl Behavior for Wrapping { type Id = Id; type Return = Id; /// wrapping `::next()` method, when out of range, wrapover to first element /// WARNING: due to optimizations this does not behave correctly on Pools /// which are created with an empty range fn next(pool: &mut Pool) -> Self::Return { if pool.buffer.start < pool.buffer.end { let result = pool.buffer.start; pool.buffer.start += pool.one; result } else { pool.buffer.start = pool.original_range.start + pool.one; pool.original_range.start } } } // ERROR TYPES // ///Error Type returned by Checked #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq)] pub enum CheckedError { PoolEmpty, } impl core::fmt::Display for CheckedError { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { CheckedError::PoolEmpty => write!(f, "pool is empty, all Id's are used up"), } } } #[cfg(feature = "std")] impl std::error::Error for CheckedError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { // Generic error, underlying cause isn't tracked. None } }