use std::marker::PhantomData;
use dope_core::driver::schedule::clock;
use o3::base::cell::region;
use crate::service::{self, health};
pub enum Reason {
Startup,
Failure(health::Cause),
}
pub enum Action<'d, I, A, M, E, const N: usize> {
Pending {
poll_at: Option<clock::Deadline<'d>>,
},
Published {
snapshot: service::Snapshot<service::Endpoint<I, A>, N>,
metadata: M,
poll_at: Option<clock::Deadline<'d>>,
},
Stale {
revision: service::Revision,
poll_at: Option<clock::Deadline<'d>>,
},
Expired {
revision: service::Revision,
poll_at: Option<clock::Deadline<'d>>,
},
Failed {
error: E,
poll_at: Option<clock::Deadline<'d>>,
},
}
pub trait Output {
type Metadata<'d>;
type Error;
}
pub trait Demand<'d> {
type Endpoint;
fn is_needed(&self, token: ®ion::Token<region::Identity<'d, 1>>) -> bool;
fn is_eligible(
&self,
endpoint: &Self::Endpoint,
token: ®ion::Token<region::Identity<'d, 1>>,
) -> bool;
fn is_retained(&self, _: &Self::Endpoint, _: ®ion::Token<region::Identity<'d, 1>>) -> bool {
true
}
}
pub trait RefreshAt<'d> {
fn refresh_at(&mut self, now: clock::Moment<'d>, reason: Reason);
}
pub trait PollAt<'d, I, A, const N: usize>: Output {
fn is_ready(&self, _: ®ion::Token<region::Identity<'d, 1>>) -> bool {
false
}
fn poll_at(
&mut self,
token: &mut region::Token<region::Identity<'d, 1>>,
now: clock::Moment<'d>,
) -> Action<'d, I, A, Self::Metadata<'d>, Self::Error, N>;
}
pub struct Silent;
pub struct Notify {
pub(crate) cause: Option<health::Cause>,
}
pub struct Gate<D> {
enabled: bool,
source: D,
}
pub struct Watched<D>(PhantomData<fn() -> D>);
pub struct Refreshing<'d, D> {
source: D,
poll_at: Option<clock::Deadline<'d>>,
}
pub trait Driver<'d> {
type Feedback: Access;
}
pub trait Access {
fn is_enabled(&self) -> bool;
}
pub(crate) trait Eligibility<'d, I>: Access {
const WATCHED: bool;
fn is_eligible(&self, endpoint: &I, token: ®ion::Token<region::Identity<'d, 1>>) -> bool;
fn is_retained(&self, _: &I, _: ®ion::Token<region::Identity<'d, 1>>) -> bool {
self.is_enabled()
}
}
pub(crate) trait Feedback: Access {
fn cause_mut(&mut self) -> Option<&mut Option<health::Cause>>;
}
impl Notify {
pub(crate) const fn new() -> Self {
Self { cause: None }
}
pub(crate) fn take(&mut self) -> Option<health::Cause> {
self.cause.take()
}
pub(crate) const fn is_ready(&self) -> bool {
self.cause.is_some()
}
}
impl<D> Gate<D> {
pub(crate) const fn new(source: D) -> Self {
Self {
enabled: false,
source,
}
}
pub(crate) fn source(&self) -> &D {
&self.source
}
pub(crate) fn set(&mut self, enabled: bool) {
self.enabled = enabled;
}
}
impl<D> Watched<D> {
pub(crate) const fn new() -> Self {
Self(PhantomData)
}
}
impl<'d, D: RefreshAt<'d>> Refreshing<'d, D> {
pub(crate) fn new(mut source: D, now: clock::Moment<'d>) -> Self {
source.refresh_at(now, Reason::Startup);
Self {
source,
poll_at: Some(now.into()),
}
}
}
impl<'d, D: Demand<'d>> Driver<'d> for Watched<D> {
type Feedback = Gate<D>;
}
impl<'d, D: Output> Driver<'d> for Refreshing<'d, D> {
type Feedback = Notify;
}
impl<'d, D> Refreshing<'d, D> {
pub(crate) fn source(&self) -> &D {
&self.source
}
pub(crate) fn source_mut(&mut self) -> &mut D {
&mut self.source
}
pub(crate) fn poll_at(&self) -> Option<clock::Deadline<'d>> {
self.poll_at
}
pub(crate) fn schedule(&mut self, next: Option<clock::Deadline<'d>>) {
self.poll_at = next;
}
}
impl Access for Silent {
fn is_enabled(&self) -> bool {
true
}
}
impl Feedback for Silent {
fn cause_mut(&mut self) -> Option<&mut Option<health::Cause>> {
None
}
}
impl Feedback for Notify {
fn cause_mut(&mut self) -> Option<&mut Option<health::Cause>> {
Some(&mut self.cause)
}
}
impl Access for Notify {
fn is_enabled(&self) -> bool {
true
}
}
impl<D> Access for Gate<D> {
fn is_enabled(&self) -> bool {
self.enabled
}
}
impl<D> Feedback for Gate<D> {
fn cause_mut(&mut self) -> Option<&mut Option<health::Cause>> {
None
}
}
impl<'d, I> Eligibility<'d, I> for Silent {
const WATCHED: bool = false;
fn is_eligible(&self, _: &I, _: ®ion::Token<region::Identity<'d, 1>>) -> bool {
true
}
}
impl<'d, I> Eligibility<'d, I> for Notify {
const WATCHED: bool = false;
fn is_eligible(&self, _: &I, _: ®ion::Token<region::Identity<'d, 1>>) -> bool {
true
}
}
impl<'d, I, D: Demand<'d, Endpoint = I>> Eligibility<'d, I> for Gate<D> {
const WATCHED: bool = true;
fn is_eligible(&self, endpoint: &I, token: ®ion::Token<region::Identity<'d, 1>>) -> bool {
self.source.is_eligible(endpoint, token)
}
fn is_retained(&self, endpoint: &I, token: ®ion::Token<region::Identity<'d, 1>>) -> bool {
self.source.is_needed(token) && self.source.is_retained(endpoint, token)
}
}