use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use crate::bias::Bias;
use crate::select::DISABLED;
use crate::set::{Number, Set};
type StaticPoll<Bits, S, O> = fn(&mut Context<'_>, Pin<&mut S>, &mut Set<Bits>, u32) -> Poll<O>;
pub struct StaticSelect<Bits, S, B, O> {
enabled: Set<Bits>,
state: S,
bias: B,
poll: StaticPoll<Bits, S, O>,
}
impl<Bits, S, B, O> StaticSelect<Bits, S, B, O> {
pub(crate) fn new(enabled: Set<Bits>, bias: B, state: S, poll: StaticPoll<Bits, S, O>) -> Self {
Self {
enabled,
state,
bias,
poll,
}
}
}
impl<Bits, S, B, O> StaticSelect<Bits, S, B, O>
where
Bits: Number,
B: Bias<Bits>,
{
pub async fn next(self: Pin<&mut Self>) -> O {
Next { this: self }.await
}
pub fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<O> {
unsafe {
let this = Pin::get_unchecked_mut(self);
let mut state = Pin::new_unchecked(&mut this.state);
for index in this.bias.apply(this.enabled) {
if let Poll::Ready(output) =
(this.poll)(cx, state.as_mut(), &mut this.enabled, index)
{
return Poll::Ready(output);
}
}
if this.enabled.is_empty() {
return (this.poll)(cx, state.as_mut(), &mut this.enabled, DISABLED);
}
Poll::Pending
}
}
}
impl<Bits, S, B, O> Future for StaticSelect<Bits, S, B, O>
where
Bits: Number,
B: Bias<Bits>,
{
type Output = O;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.poll_next(cx)
}
}
struct Next<'a, Bits, S, B, O> {
this: Pin<&'a mut StaticSelect<Bits, S, B, O>>,
}
impl<Bits, S, B, O> Future for Next<'_, Bits, S, B, O>
where
Bits: Number,
B: Bias<Bits>,
{
type Output = O;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unsafe { Pin::get_unchecked_mut(self).this.as_mut().poll_next(cx) }
}
}
impl<Bits, S, B, O> fmt::Debug for StaticSelect<Bits, S, B, O>
where
Bits: Number,
B: fmt::Debug,
S: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StaticSelect")
.field("enabled", &self.enabled)
.field("state", &self.state)
.field("bias", &self.bias)
.finish()
}
}