use alloc::rc::Rc;
use core::fmt::{Debug, Formatter};
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use crate::utils::{TimerClock, TimingGroup};
use crate::round::Ucw;
pub struct LoadBalance<F: Future, C: TimerClock> {
record: Registered<C>,
future: F,
}
struct Registered<C: TimerClock> {
index: usize,
group: Rc<(Ucw<TimingGroup<C::Duration>>, C)>, }
impl<C: TimerClock> Registered<C> {
#[inline(always)]
fn do_unregister(&self){ self.group.0.borrow_mut().remove(self.index); }
#[inline]
fn unregister_and_get(self) -> Rc<(Ucw<TimingGroup<C::Duration>>, C)> {
self.do_unregister();
unsafe {
let rc = core::ptr::read(&self.group as *const _); core::mem::forget(self); rc
}
}
}
impl<C: TimerClock> Drop for Registered<C> {
fn drop(&mut self) {
self.do_unregister();
}
}
impl<F: Future, C: TimerClock> LoadBalance<F, C> {
pub fn with(clock: C, prop: u16, future: F) -> Self {
let mut group = TimingGroup::new();
let key = group.insert(prop);
Self {
record: Registered {
index: key,
group: Rc::new((Ucw::new(group), clock)),
},
future,
}
}
pub fn insert<G>(&self, prop: u16, future: G) -> LoadBalance<G, C> where G: Future {
let index = self.record.group.0.borrow_mut().insert(prop);
LoadBalance {
record: Registered {
index,
group: self.record.group.clone(), },
future,
}
}
pub fn count(&self) -> usize { self.record.group.0.borrow().count() }
pub fn remove(self) -> Option<C> {
let group = self.record.unregister_and_get();
Rc::try_unwrap(group).ok().map(|p| p.1)
}
}
impl<F: Future, C: TimerClock> Future for LoadBalance<F, C> {
type Output = F::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
if !self.record.group.0.borrow().can_execute(self.record.index) {
cx.waker().wake_by_ref();
return Poll::Pending;
}
let start = self.record.group.1.start();
let future = unsafe{ self.as_mut().map_unchecked_mut(|v|&mut v.future) };
let res = future.poll(cx);
let dur = self.record.group.1.stop(start); self.record.group.0.borrow_mut().update_duration(self.record.index, dur);
return res;
}
}
impl<F: Future + Debug, C: TimerClock + Debug> Debug for LoadBalance<F, C> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LoadBalance").field("future", &self.future) .field("slots", &self.record.group.0.borrow().get_slot_count(self.record.index).unwrap())
.field("clock", &self.record.group.1).finish()
}
}