use std::collections::HashMap;
use crate::attributes::{COMPOUND, LABEL};
use crate::builder::RootBuilder;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Kind {
Node,
Edge,
Cluster,
Subgraph,
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub struct Entity {
pub(crate) kind: Kind,
pub(crate) id: Id,
}
pub type Attributes = HashMap<&'static str, String>;
pub type Defaults = HashMap<Kind, Attributes>;
#[derive(Debug)]
pub struct Graph {
pub(crate) attributes: HashMap<Entity, Attributes>,
pub(crate) subgraphs: HashMap<Entity, SubgraphInfo>,
pub(crate) edges: HashMap<Entity, EdgeInfo>,
pub(crate) latest: Id,
}
impl Graph {
#[must_use]
pub fn new_builder() -> RootBuilder {
RootBuilder::new()
}
}
type Id = u32;
pub(crate) const ROOT: Entity = Entity {
kind: Kind::Subgraph,
id: 0,
};
impl Graph {
pub(crate) fn register(&mut self, kind: Kind, defaults: &Defaults) -> Entity {
self.latest += 1;
let entity = Entity {
kind,
id: self.latest,
};
self.attributes
.insert(entity, defaults.get(&kind).cloned().unwrap_or_default());
entity
}
fn locate(&self, entity: Entity) -> Option<Entity> {
let info = self.subgraphs.get(&entity)?;
info.nodes
.first()
.copied()
.or_else(|| info.subgraphs.iter().find_map(|&e| self.locate(e)))
}
fn resolve<F>(&mut self, entity: Entity, func: F) -> (Entity, Option<Entity>)
where
F: FnOnce(&EdgeInfo) -> (Entity, Option<Entity>),
{
match entity.kind {
Kind::Node => (entity, None),
Kind::Edge => func(&self.edges[&entity]),
Kind::Cluster | Kind::Subgraph => {
self.attributes
.get_mut(&ROOT)
.unwrap()
.insert(COMPOUND, "true".to_string());
(self.locate(entity).unwrap_or(entity), Some(entity))
}
}
}
pub(crate) fn new_node<S: Into<String>>(&mut self, label: S, defaults: &Defaults) -> Entity {
let entity = self.register(Kind::Node, defaults);
self.attributes_mut(entity).insert(LABEL, label.into());
entity
}
pub(crate) fn new_edge(&mut self, head: Entity, tail: Entity, defaults: &Defaults) -> Entity {
let (head_node, head_subgraph) = self.resolve(head, |i| (i.tail_node, i.tail_subgraph));
let (tail_node, tail_subgraph) = self.resolve(tail, |i| (i.head_node, i.head_subgraph));
let info = EdgeInfo {
head_node,
tail_node,
head_subgraph,
tail_subgraph,
};
let entity = self.register(Kind::Edge, defaults);
self.edges.insert(entity, info);
entity
}
pub(crate) fn attributes(&self, entity: Entity) -> &Attributes {
self.attributes.get(&entity).unwrap()
}
pub(crate) fn attributes_mut(&mut self, entity: Entity) -> &mut Attributes {
self.attributes.get_mut(&entity).unwrap()
}
}
#[derive(Debug)]
pub(crate) struct EdgeInfo {
pub(crate) head_node: Entity,
pub(crate) tail_node: Entity,
pub(crate) head_subgraph: Option<Entity>,
pub(crate) tail_subgraph: Option<Entity>,
}
#[derive(Debug, Default)]
pub(crate) struct SubgraphInfo {
pub(crate) nodes: Vec<Entity>,
pub(crate) edges: Vec<Entity>,
pub(crate) subgraphs: Vec<Entity>,
}