use std::fmt::Debug;
use std::iter::{Enumerate, FusedIterator};
use std::ops::Range;
use super::{MultiPortGraph, SubportIndex};
use crate::portgraph::{self, NodePorts};
use crate::{Direction, LinkView, NodeIndex, PortIndex, PortOffset, PortView};
impl MultiPortGraph {
#[inline]
pub(crate) fn _get_connections(&self, from: NodeIndex, to: NodeIndex) -> NodeConnections {
NodeConnections::new(self, to, self._output_links(from))
}
#[inline]
pub(crate) fn _port_links(&self, port: PortIndex) -> PortLinks {
PortLinks::new(self, port)
}
#[inline]
pub(crate) fn _links(&self, node: NodeIndex, direction: Direction) -> NodeLinks {
NodeLinks::new(self, self.graph._ports(node, direction), 0..0)
}
#[inline]
pub(crate) fn _all_links(&self, node: NodeIndex) -> NodeLinks {
let output_ports = self.graph.node_outgoing_ports(node);
NodeLinks::new(self, self.graph._all_ports(node), output_ports)
}
#[must_use]
#[inline]
pub(crate) fn _output_links(&self, node: NodeIndex) -> NodeLinks {
self._links(node, Direction::Outgoing)
}
#[inline]
pub(crate) fn _neighbours(&self, node: NodeIndex, direction: Direction) -> Neighbours {
Neighbours::new(self, self._subports(node, direction), node, false)
}
#[inline]
pub(crate) fn _all_neighbours(&self, node: NodeIndex) -> Neighbours {
Neighbours::new(self, self._all_subports(node), node, true)
}
#[inline]
pub(crate) fn _subports(&self, node: NodeIndex, direction: Direction) -> NodeSubports {
NodeSubports::new(self, self.graph._ports(node, direction))
}
#[inline]
pub(crate) fn _all_subports(&self, node: NodeIndex) -> NodeSubports {
NodeSubports::new(self, self.graph._all_ports(node))
}
}
#[derive(Clone)]
pub struct Nodes<'a> {
pub(super) multigraph: &'a MultiPortGraph,
pub(super) iter: portgraph::Nodes<'a>,
pub(super) len: usize,
}
impl Iterator for Nodes<'_> {
type Item = NodeIndex;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let next = self
.iter
.find(|node| !self.multigraph.is_copy_node(*node))?;
self.len -= 1;
Some(next)
}
#[inline]
fn count(self) -> usize {
self.len
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl ExactSizeIterator for Nodes<'_> {
fn len(&self) -> usize {
self.len
}
}
impl DoubleEndedIterator for Nodes<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
let node = self.iter.next_back()?;
if !self.multigraph.is_copy_node(node) {
self.len -= 1;
return Some(node);
}
}
}
}
impl FusedIterator for Nodes<'_> {}
#[derive(Debug, Clone)]
pub struct NodeSubports<'a> {
multigraph: &'a MultiPortGraph,
ports: portgraph::NodePorts,
current_port: Option<PortIndex>,
current_subports: Range<usize>,
}
impl<'a> NodeSubports<'a> {
pub(super) fn new(multigraph: &'a MultiPortGraph, ports: portgraph::NodePorts) -> Self {
Self {
multigraph,
ports,
current_port: None,
current_subports: 0..0,
}
}
}
impl Iterator for NodeSubports<'_> {
type Item = SubportIndex;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(offset) = self.current_subports.next() {
let current_port = self
.current_port
.expect("NodeSubports set an invalid current_port value.");
return Some(SubportIndex::new_multi(current_port, offset));
}
let port = self.ports.next()?;
self.current_port = Some(port);
if self.multigraph.is_multiport(port) {
let dir = self.multigraph.graph.port_direction(port).unwrap();
let copy_node = self
.multigraph
.get_copy_node(port)
.expect("A port was marked as multiport, but no copy node was found.");
self.current_subports = self
.multigraph
.graph
._port_offsets(copy_node, dir)
.as_range(dir);
} else {
return Some(SubportIndex::new_unique(port));
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.ports.len() + self.current_subports.len(), None)
}
}
impl FusedIterator for NodeSubports<'_> {}
#[derive(Debug, Clone)]
pub struct Neighbours<'a> {
multigraph: &'a MultiPortGraph,
subports: NodeSubports<'a>,
current_copy_node: Option<NodeIndex>,
node: NodeIndex,
ignore_dupped_self_loops: bool,
}
impl<'a> Neighbours<'a> {
pub(super) fn new(
multigraph: &'a MultiPortGraph,
subports: NodeSubports<'a>,
node: NodeIndex,
ignore_dupped_self_loops: bool,
) -> Self {
Self {
multigraph,
subports,
current_copy_node: None,
node,
ignore_dupped_self_loops,
}
}
}
impl Iterator for Neighbours<'_> {
type Item = NodeIndex;
fn next(&mut self) -> Option<Self::Item> {
loop {
let link = self.subports.find_map(|subport| {
let port_index = subport.port();
if !self.multigraph.is_multiport(port_index) {
self.multigraph.graph.port_link(port_index)
} else {
if subport.offset() == 0 {
self.current_copy_node = self.multigraph.get_copy_node(port_index);
}
let copy_node = self
.current_copy_node
.expect("Copy node not connected to a multiport.");
let dir = self.multigraph.graph.port_direction(port_index).unwrap();
let offset = PortOffset::new(dir, subport.offset());
let subport_index =
self.multigraph.graph.port_index(copy_node, offset).unwrap();
self.multigraph.graph.port_link(subport_index)
}
})?;
let link_subport = self.multigraph.get_subport_from_index(link).unwrap();
let node = self
.multigraph
.graph
.port_node(link_subport.port())
.unwrap();
if self.ignore_dupped_self_loops
&& node == self.node
&& self.multigraph.port_direction(link_subport.port()).unwrap()
== Direction::Outgoing
{
continue;
}
return Some(node);
}
}
}
impl FusedIterator for Neighbours<'_> {}
#[derive(Debug, Clone)]
pub struct NodeLinks<'a> {
multigraph: &'a MultiPortGraph,
ports: NodePorts,
current_links: Option<PortLinks<'a>>,
ignore_target_ports: Range<usize>,
}
impl<'a> NodeLinks<'a> {
pub(super) fn new(
multigraph: &'a MultiPortGraph,
ports: NodePorts,
ignore_target_ports: Range<usize>,
) -> Self {
Self {
multigraph,
ports,
current_links: None,
ignore_target_ports,
}
}
}
impl Iterator for NodeLinks<'_> {
type Item = (SubportIndex, SubportIndex);
fn next(&mut self) -> Option<Self::Item> {
loop {
let Some(links) = &mut self.current_links else {
let port = self.ports.next()?;
self.current_links = Some(PortLinks::new(self.multigraph, port));
continue;
};
let Some((from, to)) = links.next() else {
self.current_links = None;
continue;
};
if self.ignore_target_ports.contains(&to.port().index()) {
continue;
}
return Some((from, to));
}
}
}
impl FusedIterator for NodeLinks<'_> {}
#[derive(Debug, Clone)]
pub struct NodeConnections<'a> {
multigraph: &'a MultiPortGraph,
target: NodeIndex,
links: NodeLinks<'a>,
}
impl<'a> NodeConnections<'a> {
pub(super) fn new(
multigraph: &'a MultiPortGraph,
target: NodeIndex,
links: NodeLinks<'a>,
) -> Self {
Self {
multigraph,
target,
links,
}
}
}
impl Iterator for NodeConnections<'_> {
type Item = (SubportIndex, SubportIndex);
fn next(&mut self) -> Option<Self::Item> {
loop {
let (source, target) = self.links.next()?;
let target_node = self.multigraph.graph.port_node(target.port())?;
if target_node == self.target {
return Some((source, target));
}
}
}
}
impl FusedIterator for NodeConnections<'_> {}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum PortLinks<'a> {
SinglePort {
multigraph: &'a MultiPortGraph,
port: PortIndex,
empty: bool,
},
Multiport {
multigraph: &'a MultiPortGraph,
port: PortIndex,
subports: Enumerate<portgraph::NodePorts>,
},
}
impl<'a> PortLinks<'a> {
pub(super) fn new(multigraph: &'a MultiPortGraph, port: PortIndex) -> Self {
if multigraph.is_multiport(port) {
let copy_node = multigraph.get_copy_node(port).unwrap();
let dir = multigraph.graph.port_direction(port).unwrap();
let subports = multigraph.graph._ports(copy_node, dir).enumerate();
Self::Multiport {
multigraph,
port,
subports,
}
} else {
Self::SinglePort {
multigraph,
port,
empty: false,
}
}
}
}
#[inline(always)]
fn port_links_single(
multigraph: &MultiPortGraph,
port: PortIndex,
) -> Option<(SubportIndex, SubportIndex)> {
let link = multigraph.graph.port_link(port)?;
let link = multigraph.get_subport_from_index(link)?;
Some((SubportIndex::new_unique(port), link))
}
#[inline(always)]
fn port_links_multiport(
multigraph: &MultiPortGraph,
port: PortIndex,
subport_offset: usize,
copy_port_index: PortIndex,
) -> Option<(SubportIndex, SubportIndex)> {
let link = multigraph.graph.port_link(copy_port_index)?;
let link = multigraph.get_subport_from_index(link)?;
Some((SubportIndex::new_multi(port, subport_offset), link))
}
impl Iterator for PortLinks<'_> {
type Item = (SubportIndex, SubportIndex);
fn next(&mut self) -> Option<Self::Item> {
match self {
PortLinks::SinglePort {
multigraph,
port,
empty,
} if !*empty => {
*empty = true;
port_links_single(multigraph, *port)
}
PortLinks::SinglePort { .. } => None,
PortLinks::Multiport {
multigraph,
port,
subports,
..
} => subports
.find_map(|(offset, index)| port_links_multiport(multigraph, *port, offset, index)),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
PortLinks::SinglePort { empty, .. } => {
if *empty {
(0, Some(0))
} else {
(1, Some(1))
}
}
PortLinks::Multiport { subports, .. } => (0, Some(subports.len())),
}
}
}
impl DoubleEndedIterator for PortLinks<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
PortLinks::SinglePort {
multigraph,
port,
empty,
} if !*empty => {
*empty = true;
port_links_single(multigraph, *port)
}
PortLinks::SinglePort { .. } => None,
PortLinks::Multiport {
multigraph,
port,
subports,
..
} => loop {
let (offset, index) = subports.next_back()?;
if let Some(res) = port_links_multiport(multigraph, *port, offset, index) {
return Some(res);
}
},
}
}
}
impl FusedIterator for PortLinks<'_> {}
#[derive(Clone)]
pub struct Ports<'a> {
multigraph: &'a MultiPortGraph,
ports: portgraph::Ports<'a>,
}
impl<'a> Ports<'a> {
pub(super) fn new(multigraph: &'a MultiPortGraph, ports: portgraph::Ports<'a>) -> Self {
Self { multigraph, ports }
}
}
impl Iterator for Ports<'_> {
type Item = PortIndex;
fn next(&mut self) -> Option<Self::Item> {
self.ports.find(|&port| {
let node = self.multigraph.port_node(port).unwrap();
!self.multigraph.is_copy_node(node)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.ports.size_hint().1)
}
}
impl DoubleEndedIterator for Ports<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
let port = self.ports.next_back()?;
let node = self.multigraph.port_node(port).unwrap();
if !self.multigraph.is_copy_node(node) {
return Some(port);
}
}
}
}
impl FusedIterator for Ports<'_> {}