use std::collections::BTreeMap;
use std::ops::Index;
use super::error::{Error, Result};
use super::topology::Topology;
use super::Graph;
#[derive(Clone, Debug)]
pub struct Builder<T, W = ()> {
nodes: Vec<T>,
edges: Vec<Edge<W>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Edge<W = ()> {
pub source: usize,
pub target: usize,
pub weight: W,
}
impl<T, W> Builder<T, W> {
#[must_use]
pub fn new() -> Self {
Self {
nodes: Vec::new(),
edges: Vec::new(),
}
}
pub fn add_node(&mut self, node: T) -> usize {
self.nodes.push(node);
self.nodes.len() - 1
}
pub fn add_edge(
&mut self, source: usize, target: usize, weight: W,
) -> Result {
if source >= self.nodes.len() {
return Err(Error::NotFound(source));
}
if target >= self.nodes.len() {
return Err(Error::NotFound(target));
}
self.edges.push(Edge { source, target, weight });
Ok(())
}
#[must_use]
pub fn to_edge_graph(&self) -> Builder<Edge<W>>
where
W: Clone,
{
let mut targets: BTreeMap<usize, Vec<usize>> = BTreeMap::new();
for (source, edge) in self.edges.iter().enumerate() {
targets.entry(edge.target).or_default().push(source);
}
let mut edges = Vec::with_capacity(targets.len());
for (target, edge) in self.edges.iter().enumerate() {
if let Some(sources) = targets.get(&edge.source) {
for &source in sources {
edges.push(Edge { source, target, weight: () });
}
}
}
Builder {
nodes: self.edges.clone(),
edges,
}
}
#[must_use]
pub fn build(self) -> Graph<T>
where
W: Clone,
{
Graph {
topology: Topology::new(&self),
data: self.nodes,
}
}
}
#[allow(clippy::must_use_candidate)]
impl<T, W> Builder<T, W> {
#[inline]
pub fn nodes(&self) -> &[T] {
&self.nodes
}
#[inline]
pub fn edges(&self) -> &[Edge<W>] {
&self.edges
}
#[inline]
pub fn len(&self) -> usize {
self.nodes.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
}
impl<T, W> Index<usize> for Builder<T, W> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.nodes[index]
}
}
impl<T, W> Default for Builder<T, W>
where
W: Clone,
{
#[inline]
fn default() -> Self {
Self::new()
}
}