1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
//! Module for variadic handoff port lists, [`PortList`].
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 trait for variadic lists of ports.
///
/// See the [`variadics`] crate for the strategy we use to implement variadics in Rust.
#[sealed]
pub trait PortList<S>: Variadic
where
S: Polarity,
{
/// Iteratively/recursively set the graph metadata for each port in this list.
///
/// Specifically sets:
/// - `HandoffData::preds` and `HandoffData::succs` in the `handoffs` slice for the
/// handoffs in this [`PortList`] (using `pred` and/or `succ`).
/// - `out_handoff_ids` will be extended with all the handoff IDs in this [`PortList`].
///
/// `handoffs_are_preds`:
/// - `true`: Handoffs are predecessors (inputs) to subgraph `sg_id`.
/// - `false`: Handoffs are successors (outputs) from subgraph `sg_id`.
fn set_graph_meta(
&self,
handoffs: &mut [HandoffData],
out_handoff_ids: &mut Vec<HandoffId>,
sg_id: SubgraphId,
handoffs_are_preds: bool,
);
/// The [`Variadic`] return type of [`Self::make_ctx`].
type Ctx<'a>: Variadic;
/// Iteratively/recursively construct a `Ctx` variadic list.
///
/// (Note that unlike [`Self::set_graph_meta`], this does not mess with pred/succ handoffs for
/// teeing).
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];
// Set subgraph's info (`out_handoff_ids`) about neighbor handoffs.
// Use the "representative" handoff (pred or succ) for teeing handoffs, for the subgraph metadata.
// For regular Vec handoffs, `pred_handoffs` and `succ_handoffs` will just be the handoff itself.
out_handoff_ids.extend(if handoffs_are_preds {
this_handoff.pred_handoffs.iter().copied()
} else {
this_handoff.succ_handoffs.iter().copied()
});
// Set handoff's info (`preds`/`succs`) about neighbor subgraph (`sg_id`).
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> {}
}
/// Trait for splitting a list of ports into two.
#[sealed]
pub trait PortListSplit<S, A>: PortList<S>
where
S: Polarity,
A: PortList<S>,
{
/// The suffix, second half of the split.
type Suffix: PortList<S>;
/// Split the port list, returning the prefix and [`Self::Suffix`] as the two halves.
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! {
/// A variadic list of Handoff types, represented using a lisp-style tuple structure.
///
/// This trait is sealed and not meant to be implemented or used directly. Instead tuple lists (which already implement this trait) should be used, for example:
/// ```ignore
/// type MyHandoffList = (VecHandoff<usize>, (VecHandoff<String>, (TeeingHandoff<u32>, ())));
/// ```
/// The [`var_expr!`](crate::var) macro simplifies usage of this kind:
/// ```ignore
/// type MyHandoffList = var_expr!(VecHandoff<usize>, VecHandoff<String>, TeeingHandoff<u32>);
/// ```
#[sealed]
pub variadic<T> HandoffList where T: 'static + Handoff {}
}