use std::path::PathBuf;
use crate::pack::PackManifest;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EdgeKind {
Child,
DependsOn,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct PackNode {
pub id: usize,
pub name: String,
pub path: PathBuf,
pub source_url: Option<String>,
pub manifest: PackManifest,
pub parent: Option<usize>,
pub commit_sha: Option<String>,
pub synthetic: bool,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct PackEdge {
pub from: usize,
pub to: usize,
pub kind: EdgeKind,
}
#[derive(Debug)]
pub struct PackGraph {
nodes: Vec<PackNode>,
edges: Vec<PackEdge>,
}
impl PackGraph {
#[must_use]
pub(crate) fn new(nodes: Vec<PackNode>, edges: Vec<PackEdge>) -> Self {
assert!(!nodes.is_empty(), "PackGraph must contain at least the root node");
Self { nodes, edges }
}
#[must_use]
pub fn root(&self) -> &PackNode {
&self.nodes[0]
}
#[must_use]
pub fn nodes(&self) -> &[PackNode] {
&self.nodes
}
#[must_use]
pub fn edges(&self) -> &[PackEdge] {
&self.edges
}
pub fn children_of(&self, id: usize) -> impl Iterator<Item = &PackNode> {
self.neighbours(id, EdgeKind::Child)
}
pub fn depends_on_of(&self, id: usize) -> impl Iterator<Item = &PackNode> {
self.neighbours(id, EdgeKind::DependsOn)
}
#[must_use]
pub fn find_by_name(&self, name: &str) -> Option<&PackNode> {
self.nodes.iter().find(|n| n.name == name)
}
#[must_use]
pub fn node(&self, id: usize) -> Option<&PackNode> {
self.nodes.get(id)
}
fn neighbours(&self, id: usize, kind: EdgeKind) -> impl Iterator<Item = &PackNode> {
self.edges
.iter()
.filter(move |e| e.from == id && e.kind == kind)
.filter_map(|e| self.nodes.get(e.to))
}
}