use petgraph::visit as pv;
use portgraph::{LinkView, NodeIndex as NIdx, PortOffset};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MaybeSynEdge<T> {
Original(T),
NonLocalOrderingConstraint,
}
#[derive(Clone, Debug)]
pub(super) struct SynEdgeWrapper<T: LinkView> {
pub(super) region_view: T,
#[allow(clippy::type_complexity)]
pub(super) syn_edges: Vec<(NIdx<T::NodeIndexBase>, NIdx<T::NodeIndexBase>)>,
}
impl<T: LinkView> pv::GraphBase for SynEdgeWrapper<T> {
type NodeId = NIdx<T::NodeIndexBase>;
type EdgeId = (
NIdx<T::NodeIndexBase>,
NIdx<T::NodeIndexBase>,
MaybeSynEdge<(PortOffset<T::PortOffsetBase>, PortOffset<T::PortOffsetBase>)>,
);
}
impl<T: LinkView> pv::GraphProp for SynEdgeWrapper<T> {
type EdgeType = petgraph::Directed;
}
impl<T: LinkView> pv::NodeCount for SynEdgeWrapper<T> {
fn node_count(&self) -> usize {
self.region_view.node_count()
}
}
impl<T: LinkView> pv::NodeIndexable for SynEdgeWrapper<T> {
fn node_bound(&self) -> usize {
self.region_view.node_capacity()
}
fn to_index(&self, ix: Self::NodeId) -> usize {
ix.index()
}
fn from_index(&self, ix: usize) -> Self::NodeId {
NIdx::new(ix)
}
}
impl<T: LinkView> pv::EdgeCount for SynEdgeWrapper<T> {
fn edge_count(&self) -> usize {
self.region_view.link_count() + self.syn_edges.len()
}
}
impl<T: LinkView> pv::Data for SynEdgeWrapper<T> {
type NodeWeight = ();
type EdgeWeight = MaybeSynEdge<(PortOffset<T::PortOffsetBase>, PortOffset<T::PortOffsetBase>)>;
}
impl<'a, T: LinkView> pv::IntoNodeReferences for &'a SynEdgeWrapper<T> {
type NodeRef = NIdx<T::NodeIndexBase>;
type NodeReferences = Box<dyn Iterator<Item = NIdx<T::NodeIndexBase>> + 'a>;
fn node_references(self) -> Self::NodeReferences {
Box::new(self.region_view.nodes_iter())
}
}
impl<'a, T: LinkView> pv::IntoNodeIdentifiers for &'a SynEdgeWrapper<T> {
type NodeIdentifiers = Box<dyn Iterator<Item = Self::NodeId> + 'a>;
fn node_identifiers(self) -> Self::NodeIdentifiers {
pv::IntoNodeReferences::node_references(self)
}
}
impl<'a, T: LinkView> pv::IntoNeighbors for &'a SynEdgeWrapper<T> {
type Neighbors = Box<dyn Iterator<Item = NIdx<T::NodeIndexBase>> + 'a>;
fn neighbors(self, n: Self::NodeId) -> Self::Neighbors {
Box::new(
self.region_view.output_neighbours(n).chain(
self.syn_edges
.iter()
.filter_map(move |(src, dst)| (*src == n).then_some(*dst)),
),
)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct EdgeRef<NId, PId> {
src: NId,
tgt: NId,
weight: MaybeSynEdge<(PId, PId)>,
}
impl<NId: Copy, PId: Copy> pv::EdgeRef for EdgeRef<NId, PId> {
type NodeId = NId;
type EdgeId = (NId, NId, MaybeSynEdge<(PId, PId)>);
type Weight = MaybeSynEdge<(PId, PId)>;
fn source(&self) -> Self::NodeId {
self.src
}
fn target(&self) -> Self::NodeId {
self.tgt
}
fn weight(&self) -> &Self::Weight {
&self.weight
}
fn id(&self) -> Self::EdgeId {
(self.src, self.tgt, self.weight)
}
}
impl<'a, T: LinkView> pv::IntoEdgeReferences for &'a SynEdgeWrapper<T> {
type EdgeRef = EdgeRef<NIdx<T::NodeIndexBase>, PortOffset<T::PortOffsetBase>>;
type EdgeReferences = Box<dyn Iterator<Item = Self::EdgeRef> + 'a>;
fn edge_references(self) -> Self::EdgeReferences {
Box::new(
self.region_view
.nodes_iter()
.flat_map(|n| {
self.region_view
.links(n, portgraph::Direction::Outgoing)
.map(|(src, tgt)| {
let er: Self::EdgeRef = EdgeRef {
src: self.region_view.port_node(src).unwrap(),
tgt: self.region_view.port_node(tgt).unwrap(),
weight: MaybeSynEdge::Original((
self.region_view.port_offset(src).unwrap(),
self.region_view.port_offset(tgt).unwrap(),
)),
};
er
})
})
.chain(self.syn_edges.iter().map(|(src, tgt)| EdgeRef {
src: *src,
tgt: *tgt,
weight: MaybeSynEdge::NonLocalOrderingConstraint,
})),
)
}
}
impl<'a, T: LinkView> pv::IntoNeighborsDirected for &'a SynEdgeWrapper<T> {
type NeighborsDirected = Box<dyn Iterator<Item = NIdx<T::NodeIndexBase>> + 'a>;
fn neighbors_directed(
self,
n: Self::NodeId,
d: petgraph::Direction,
) -> Self::NeighborsDirected {
Box::new(
self.region_view
.neighbours(n, d.into())
.chain(self.syn_edges.iter().filter_map(move |(src, dst)| match d {
petgraph::Direction::Outgoing if *src == n => Some(*dst),
petgraph::Direction::Incoming if *dst == n => Some(*src),
_ => None,
})),
)
}
}
impl<T: LinkView + pv::Visitable<Map: pv::VisitMap<NIdx<T::NodeIndexBase>>>> pv::Visitable
for SynEdgeWrapper<T>
{
type Map = T::Map;
fn visit_map(&self) -> Self::Map {
self.region_view.visit_map()
}
fn reset_map(&self, map: &mut Self::Map) {
self.region_view.reset_map(map);
}
}