use ref_cast::RefCast;
use sealed::sealed;
use variadics::{variadic_trait, Variadic};
use super::Handoff;
use crate::scheduled::graph::HandoffData;
use crate::scheduled::port::{Polarity, Port, PortCtx};
use crate::scheduled::{HandoffId, SubgraphId};
#[sealed]
pub trait PortList<S>: Variadic
where
S: Polarity,
{
fn set_graph_meta(
&self,
handoffs: &mut [HandoffData],
out_handoff_ids: &mut Vec<HandoffId>,
sg_id: SubgraphId,
handoffs_are_preds: bool,
);
type Ctx<'a>: Variadic;
fn make_ctx<'a>(&self, handoffs: &'a [HandoffData]) -> Self::Ctx<'a>;
}
#[sealed]
impl<S, Rest, H> PortList<S> for (Port<S, H>, Rest)
where
S: Polarity,
H: Handoff,
Rest: PortList<S>,
{
fn set_graph_meta(
&self,
handoffs: &mut [HandoffData],
out_handoff_ids: &mut Vec<HandoffId>,
sg_id: SubgraphId,
handoffs_are_preds: bool,
) {
let (this, rest) = self;
let this_handoff = &mut handoffs[this.handoff_id.0];
out_handoff_ids.extend(if handoffs_are_preds {
this_handoff.pred_handoffs.iter().copied()
} else {
this_handoff.succ_handoffs.iter().copied()
});
if handoffs_are_preds {
for succ_hoff in this_handoff.succ_handoffs.clone() {
handoffs[succ_hoff.0].succs.push(sg_id);
}
} else {
for pred_hoff in this_handoff.pred_handoffs.clone() {
handoffs[pred_hoff.0].preds.push(sg_id);
}
}
rest.set_graph_meta(handoffs, out_handoff_ids, sg_id, handoffs_are_preds);
}
type Ctx<'a> = (&'a PortCtx<S, H>, Rest::Ctx<'a>);
fn make_ctx<'a>(&self, handoffs: &'a [HandoffData]) -> Self::Ctx<'a> {
let (this, rest) = self;
let handoff = handoffs
.get(this.handoff_id.0)
.unwrap()
.handoff
.any_ref()
.downcast_ref()
.expect("Attempted to cast handoff to wrong type.");
let ctx = RefCast::ref_cast(handoff);
let ctx_rest = rest.make_ctx(handoffs);
(ctx, ctx_rest)
}
}
#[sealed]
impl<S> PortList<S> for ()
where
S: Polarity,
{
fn set_graph_meta(
&self,
_handoffs: &mut [HandoffData],
_out_handoff_ids: &mut Vec<HandoffId>,
_sg_id: SubgraphId,
_handoffs_are_preds: bool,
) {
}
type Ctx<'a> = ();
fn make_ctx<'a>(&self, _handoffs: &'a [HandoffData]) -> Self::Ctx<'a> {}
}
#[sealed]
pub trait PortListSplit<S, A>: PortList<S>
where
S: Polarity,
A: PortList<S>,
{
type Suffix: PortList<S>;
fn split_ctx(ctx: Self::Ctx<'_>) -> (A::Ctx<'_>, <Self::Suffix as PortList<S>>::Ctx<'_>);
}
#[sealed]
impl<S, H, T, U> PortListSplit<S, (Port<S, H>, U)> for (Port<S, H>, T)
where
S: Polarity,
H: Handoff,
T: PortListSplit<S, U>,
U: PortList<S>,
{
type Suffix = T::Suffix;
fn split_ctx(
ctx: Self::Ctx<'_>,
) -> (
<(Port<S, H>, U) as PortList<S>>::Ctx<'_>,
<Self::Suffix as PortList<S>>::Ctx<'_>,
) {
let (x, t) = ctx;
let (u, v) = T::split_ctx(t);
((x, u), v)
}
}
#[sealed]
impl<S, T> PortListSplit<S, ()> for T
where
S: Polarity,
T: PortList<S>,
{
type Suffix = T;
fn split_ctx(ctx: Self::Ctx<'_>) -> ((), T::Ctx<'_>) {
((), ctx)
}
}
variadic_trait! {
#[sealed]
pub variadic<T> HandoffList where T: 'static + Handoff {}
}