use std::{
collections::{hash_map::Iter as MapIter, hash_set::Iter as SetIter, HashMap, HashSet},
error::Error,
iter::FusedIterator,
};
use serde::{Deserialize, Serialize};
use super::{LinkWeight, OspfArea};
use crate::types::RouterId;
#[derive(Debug, Default)]
#[allow(clippy::type_complexity)]
pub struct InternalEdges<'a> {
pub(super) outer: Vec<MapIter<'a, RouterId, HashMap<RouterId, (LinkWeight, OspfArea)>>>,
pub(super) inner: Option<(RouterId, MapIter<'a, RouterId, (LinkWeight, OspfArea)>)>,
}
impl Iterator for InternalEdges<'_> {
type Item = InternalEdge;
fn next(&mut self) -> Option<Self::Item> {
'main_loop: loop {
if let Some((src, inner)) = self.inner.as_mut() {
if let Some((dst, (weight, area))) = inner.next() {
return Some(InternalEdge {
src: *src,
dst: *dst,
weight: *weight,
area: *area,
});
}
let _ = self.inner.take();
}
while let Some(mut outer) = self.outer.pop() {
if let Some((src, inner)) = outer.next() {
self.outer.push(outer);
self.inner = Some((*src, inner.iter()));
continue 'main_loop;
}
}
return None;
}
}
}
impl FusedIterator for InternalEdges<'_> {}
#[derive(Debug, Default)]
pub struct ExternalEdges<'a> {
pub(super) outer: Vec<MapIter<'a, RouterId, HashSet<RouterId>>>,
pub(super) inner: Option<(RouterId, SetIter<'a, RouterId>)>,
}
impl Iterator for ExternalEdges<'_> {
type Item = ExternalEdge;
fn next(&mut self) -> Option<Self::Item> {
'main_loop: loop {
if let Some((int, inner)) = self.inner.as_mut() {
if let Some(ext) = inner.next() {
return Some(ExternalEdge {
int: *int,
ext: *ext,
int_to_ext: true,
});
}
let _ = self.inner.take();
}
while let Some(mut outer) = self.outer.pop() {
if let Some((src, inner)) = outer.next() {
self.outer.push(outer);
self.inner = Some((*src, inner.iter()));
continue 'main_loop;
}
}
return None;
}
}
}
impl FusedIterator for ExternalEdges<'_> {}
#[derive(Debug, Default)]
pub struct Edges<'a> {
pub(super) int: InternalEdges<'a>,
pub(super) ext: ExternalEdges<'a>,
}
impl Iterator for Edges<'_> {
type Item = Edge;
fn next(&mut self) -> Option<Self::Item> {
self.int
.next()
.map(Edge::Internal)
.or_else(|| self.ext.next().map(Edge::External))
}
}
impl FusedIterator for Edges<'_> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ExternalEdge {
pub int: RouterId,
pub ext: RouterId,
int_to_ext: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct InternalEdge {
pub src: RouterId,
pub dst: RouterId,
pub weight: LinkWeight,
pub area: OspfArea,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
pub enum Edge {
External(ExternalEdge),
Internal(InternalEdge),
}
impl Edge {
pub fn src(&self) -> RouterId {
match self {
Edge::External(ExternalEdge {
int,
ext,
int_to_ext,
}) => {
if *int_to_ext {
*int
} else {
*ext
}
}
Edge::Internal(InternalEdge { src, .. }) => *src,
}
}
pub fn dst(&self) -> RouterId {
match self {
Edge::External(ExternalEdge {
int,
ext,
int_to_ext,
}) => {
if *int_to_ext {
*ext
} else {
*int
}
}
Edge::Internal(InternalEdge { dst, .. }) => *dst,
}
}
pub fn is_internal(&self) -> bool {
match self {
Edge::External(_) => false,
Edge::Internal(_) => true,
}
}
pub fn is_external(&self) -> bool {
match self {
Edge::External(_) => true,
Edge::Internal(_) => false,
}
}
pub fn internal(self) -> Option<InternalEdge> {
match self {
Edge::External(_) => None,
Edge::Internal(e) => Some(e),
}
}
pub fn external(self) -> Option<ExternalEdge> {
match self {
Edge::External(e) => Some(e),
Edge::Internal(_) => None,
}
}
pub fn internal_or<E: Error>(self, e: E) -> Result<InternalEdge, E> {
match self {
Edge::External(_) => Err(e),
Edge::Internal(e) => Ok(e),
}
}
pub fn external_or<E: Error>(self, e: E) -> Result<ExternalEdge, E> {
match self {
Edge::External(e) => Ok(e),
Edge::Internal(_) => Err(e),
}
}
}