use core::marker::PhantomData;
#[cfg(feature = "tracing")]
use tracing::instrument;
use crate::{
generator::{Poll, Result, UlidGenerator},
id::UlidId,
rand::RandSource,
time::TimeSource,
};
pub struct BasicUlidGenerator<ID, T, R>
where
ID: UlidId,
T: TimeSource<ID::Ty>,
R: RandSource<ID::Ty>,
{
time: T,
rng: R,
_id: PhantomData<ID>,
}
impl<ID, T, R> BasicUlidGenerator<ID, T, R>
where
ID: UlidId,
T: TimeSource<ID::Ty>,
R: RandSource<ID::Ty>,
{
pub const fn new(time: T, rng: R) -> Self {
Self {
time,
rng,
_id: PhantomData,
}
}
#[cfg_attr(feature = "tracing", instrument(level = "trace", skip(self, f)))]
pub fn next_id(&self, mut f: impl FnMut(ID::Ty)) -> ID {
loop {
match self.poll_id() {
Poll::Ready { id } => break id,
Poll::Pending { yield_for } => f(yield_for),
}
}
}
#[cfg_attr(feature = "tracing", instrument(level = "trace", skip(self)))]
pub fn poll_id(&self) -> Poll<ID> {
Poll::Ready {
id: ID::from_components(self.time.current_millis(), self.rng.rand()),
}
}
}
impl<ID, T, R> UlidGenerator<ID, T, R> for BasicUlidGenerator<ID, T, R>
where
ID: UlidId,
T: TimeSource<ID::Ty>,
R: RandSource<ID::Ty>,
{
type Err = core::convert::Infallible;
fn new(time: T, rng: R) -> Self {
Self::new(time, rng)
}
fn next_id(&self, f: impl FnMut(ID::Ty)) -> ID {
self.next_id(f)
}
fn try_next_id(&self, f: impl FnMut(ID::Ty)) -> Result<ID, Self::Err> {
Ok(self.next_id(f))
}
fn poll_id(&self) -> Poll<ID> {
self.poll_id()
}
fn try_poll_id(&self) -> Result<Poll<ID>, Self::Err> {
Ok(self.poll_id())
}
}