use std::collections::BTreeMap;
use std::ops::{Index, Range};
use super::error::{Error, Result};
use super::topology::Topology;
use super::Graph;
#[derive(Clone, Debug)]
pub struct Builder<T> {
nodes: Vec<T>,
edges: Vec<Edge>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Edge {
pub source: usize,
pub target: usize,
}
impl<T> Graph<T> {
#[inline]
#[must_use]
pub fn builder() -> Builder<T> {
Builder::default()
}
}
impl<T> Builder<T> {
pub fn add_node(&mut self, data: T) -> usize {
self.nodes.push(data);
self.nodes.len() - 1
}
pub fn add_edge(&mut self, source: usize, target: usize) -> 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 });
Ok(())
}
#[deprecated(
since = "0.0.6",
note = "Edge graphs are no longer needed for action graphs"
)]
#[must_use]
pub fn to_edge_graph(&self) -> Builder<Edge> {
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 });
}
}
}
Builder {
nodes: self.edges.clone(),
edges,
}
}
#[inline]
#[must_use]
pub fn iter(&self) -> Range<usize> {
0..self.nodes.len()
}
#[must_use]
pub fn build(self) -> Graph<T> {
let topology = Topology::new(self.nodes.len(), &self.edges);
Graph { data: self.nodes, topology }
}
}
#[allow(clippy::must_use_candidate)]
impl<T> Builder<T> {
#[inline]
pub fn nodes(&self) -> &[T] {
&self.nodes
}
#[inline]
pub fn edges(&self) -> &[Edge] {
&self.edges
}
#[inline]
pub fn len(&self) -> usize {
self.nodes.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
}
impl<T> Index<usize> for Builder<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.nodes[index]
}
}
impl<T> IntoIterator for &Builder<T> {
type Item = usize;
type IntoIter = Range<usize>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T> Default for Builder<T> {
#[inline]
fn default() -> Self {
Builder {
nodes: Vec::default(),
edges: Vec::default(),
}
}
}