use std::borrow::Cow;
use anyhow::Result;
#[cfg(feature = "serde")]
use serde::{ser::Serialize, de::Deserialize};
use crate::{EdgeID, Edges, Error, MutableCompound, MutableForest, MutableGraph, NodeID, Nodes, BlankForest, BlankGraph, VisitableCompound, VisitableForest, VisitableGraph};
pub type BlankCompound = Compound<BlankGraph>;
pub type Compound<InnerGraph> = CompoundBase<InnerGraph, BlankForest>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph,
InnerForest: MutableForest<GData = (), NData = (), EData = ()>,
{
graph: InnerGraph,
forest: InnerForest,
}
impl<InnerGraph, InnerForest> CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Default,
{
pub fn new_with_graph_and_forest(graph: InnerGraph, forest: InnerForest) -> Result<Self> {
if forest.all_nodes() != graph.all_nodes() {
return Err(Error::NotACompound.into());
}
Ok(Self {
graph,
forest
})
}
pub fn new_with_graph(graph: InnerGraph) -> Result<Self> {
Self::new_with_graph_and_forest(graph, InnerForest::default())
}
}
impl<InnerGraph, InnerForest> CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph + Default,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Default,
{
pub fn new() -> Self {
Self::new_with_forest(InnerForest::default()).unwrap()
}
pub fn new_with_forest(forest: InnerForest) -> Result<Self> {
Self::new_with_graph_and_forest(InnerGraph::default(), forest)
}
pub fn graph(&self) -> &InnerGraph {
&self.graph
}
pub fn forest(&self) -> &InnerForest {
&self.forest
}
}
impl<InnerGraph, InnerForest> Default for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph + Default,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Default,
{
fn default() -> Self {
Self::new()
}
}
impl<InnerGraph, InnerForest> VisitableCompound for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph,
InnerForest: MutableForest<GData = (), NData = (), EData = ()>,
{ }
impl<InnerGraph, InnerForest> VisitableGraph for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph,
InnerForest: MutableForest<GData = (), NData = (), EData = ()>,
{
type GData = InnerGraph::GData;
type NData = InnerGraph::NData;
type EData = InnerGraph::EData;
fn data(&self) -> &Self::GData {
self.graph.data()
}
fn node_data(&self, id: impl AsRef<NodeID>) -> Result<Cow<'static, Self::NData>> {
self.graph.node_data(id)
}
fn edge_data(&self, id: impl AsRef<EdgeID>) -> Result<Cow<'static, Self::EData>> {
self.graph.edge_data(id)
}
fn is_empty(&self) -> bool {
self.graph.is_empty()
}
fn node_count(&self) -> usize {
self.graph.node_count()
}
fn edge_count(&self) -> usize {
self.graph.edge_count()
}
fn all_nodes(&self) -> Nodes {
self.graph.all_nodes()
}
fn all_edges(&self) -> Edges {
self.graph.all_edges()
}
fn has_node(&self, id: impl AsRef<NodeID>) -> bool {
self.graph.has_node(id)
}
fn has_edge(&self, id: impl AsRef<EdgeID>) -> bool {
self.graph.has_edge(id)
}
fn has_edge_from_to(&self, source: impl AsRef<NodeID>, target: impl AsRef<NodeID>) -> bool {
self.graph.has_edge_from_to(source, target)
}
fn has_edge_between(&self, a: impl AsRef<NodeID>, b: impl AsRef<NodeID>) -> bool {
self.graph.has_edge_between(a, b)
}
fn source(&self, id: impl AsRef<EdgeID>) -> Result<NodeID> {
self.graph.source(id)
}
fn target(&self, id: impl AsRef<EdgeID>) -> Result<NodeID> {
self.graph.target(id)
}
fn endpoints(&self, id: impl AsRef<EdgeID>) -> Result<(NodeID, NodeID)> {
self.graph.endpoints(id)
}
fn out_edges(&self, id: impl AsRef<NodeID>) -> Result<Edges> {
self.graph.out_edges(id)
}
fn in_edges(&self, id: impl AsRef<NodeID>) -> Result<Edges> {
self.graph.in_edges(id)
}
fn incident_edges(&self, id: impl AsRef<NodeID>) -> Result<Edges> {
self.graph.incident_edges(id)
}
fn out_degree(&self, id: impl AsRef<NodeID>) -> Result<usize> {
self.graph.out_degree(id)
}
fn in_degree(&self, id: impl AsRef<NodeID>) -> Result<usize> {
self.graph.in_degree(id)
}
fn degree(&self, id: impl AsRef<NodeID>) -> Result<usize> {
self.graph.degree(id)
}
fn successors(&self, id: impl AsRef<NodeID>) -> Result<Nodes> {
self.graph.successors(id)
}
fn predecessors(&self, id: impl AsRef<NodeID>) -> Result<Nodes> {
self.graph.predecessors(id)
}
fn neighbors(&self, id: impl AsRef<NodeID>) -> Result<Nodes> {
self.graph.neighbors(id)
}
fn has_successors(&self, id: impl AsRef<NodeID>) -> Result<bool> {
self.graph.has_successors(id)
}
fn has_predecessors(&self, id: impl AsRef<NodeID>) -> Result<bool> {
self.graph.has_predecessors(id)
}
fn has_neighbors(&self, id: impl AsRef<NodeID>) -> Result<bool> {
self.graph.has_neighbors(id)
}
fn all_roots(&self) -> Nodes {
self.graph.all_roots()
}
fn all_leaves(&self) -> Nodes {
self.graph.all_leaves()
}
fn non_roots(&self) -> Nodes {
self.graph.non_roots()
}
fn non_leaves(&self) -> Nodes {
self.graph.non_leaves()
}
fn all_internals(&self) -> Nodes {
self.graph.all_internals()
}
fn is_leaf(&self, id: impl AsRef<NodeID>) -> Result<bool> {
self.graph.is_leaf(id)
}
fn is_root(&self, id: impl AsRef<NodeID>) -> Result<bool> {
self.graph.is_root(id)
}
fn is_internal(&self, id: impl AsRef<NodeID>) -> Result<bool> {
self.graph.is_internal(id)
}
}
impl<InnerGraph, InnerForest> VisitableForest for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph,
InnerForest: MutableForest<GData = (), NData = (), EData = ()>,
{
fn in_edge(&self, node: impl AsRef<NodeID>) -> Result<Option<EdgeID>> {
self.forest.in_edge(node)
}
fn in_edge_with_root(&self, node: impl AsRef<NodeID>) -> Result<Option<EdgeID>> {
self.forest.in_edge_with_root(node)
}
fn parent(&self, node: impl AsRef<NodeID>) -> Result<Option<NodeID>> {
self.forest.parent(node)
}
fn children(&self, node: Option<impl AsRef<NodeID>>) -> Result<Nodes> {
self.forest.children(node)
}
fn has_children(&self, node: impl AsRef<NodeID>) -> Result<bool> {
self.forest.has_children(node)
}
fn child_count(&self, node: impl AsRef<NodeID>) -> Result<usize> {
self.forest.child_count(node)
}
}
impl<InnerGraph, InnerForest> MutableCompound for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph,
InnerForest: MutableForest<GData = (), NData = (), EData = ()>,
{
fn add_node_with_data(&mut self, node: impl AsRef<NodeID>, parent: Option<impl AsRef<NodeID>>, edge: impl AsRef<EdgeID>, node_data: InnerGraph::NData) -> Result<()> {
let node = node.as_ref();
self.graph.add_node_with_data(node, node_data)?;
self.forest.add_node(node, parent, edge)?;
Ok(())
}
fn remove_node_ungrouping(&mut self, id: impl AsRef<NodeID>) -> Result<()> {
let id = id.as_ref();
self.graph.remove_node(id)?;
self.forest.remove_node_ungrouping(id)?;
Ok(())
}
fn remove_node_and_children(&mut self, id: impl AsRef<NodeID>) -> Result<Nodes> {
let removed = self.forest.remove_node_and_children(id)?;
for node in removed.iter() {
self.graph.remove_node(node)?;
}
Ok(removed)
}
fn remove_children(&mut self, id: impl AsRef<NodeID>) -> Result<Nodes> {
let removed = self.forest.remove_children(id)?;
for node in removed.iter() {
self.graph.remove_node(node)?;
}
Ok(removed)
}
fn add_edge_with_data(&mut self, edge: impl AsRef<EdgeID>, source: impl AsRef<NodeID>, target: impl AsRef<NodeID>, edge_data: InnerGraph::EData) -> Result<()> {
self.graph.add_edge_with_data(edge, source, target, edge_data)?;
Ok(())
}
fn remove_edge(&mut self, id: impl AsRef<EdgeID>) -> Result<()> {
self.graph.remove_edge(id)?;
Ok(())
}
fn clear_edges(&mut self, id: impl AsRef<NodeID>) -> Result<()> {
self.graph.clear_edges(id)?;
Ok(())
}
fn move_node(&mut self, id: impl AsRef<NodeID>, new_parent: Option<impl AsRef<NodeID>>) -> Result<()> {
self.forest.move_node(id, new_parent)?;
Ok(())
}
fn move_edge(&mut self, id: impl AsRef<EdgeID>, new_source: impl AsRef<NodeID>, new_target: impl AsRef<NodeID>) -> Result<()> {
self.graph.move_edge(id, new_source, new_target)?;
Ok(())
}
fn set_data(&mut self, data: InnerGraph::GData) {
self.graph.set_data(data);
}
fn with_data(&mut self, transform: &dyn Fn(&mut InnerGraph::GData)) {
self.graph.with_data(transform);
}
fn set_node_data(&mut self, id: impl AsRef<NodeID>, data: InnerGraph::NData) -> Result<()> {
self.graph.set_node_data(id, data)
}
fn with_node_data(&mut self, id: impl AsRef<NodeID>, transform: &dyn Fn(&mut InnerGraph::NData)) -> Result<()> {
self.graph.with_node_data(id, transform)
}
fn set_edge_data(&mut self, id: impl AsRef<EdgeID>, data: InnerGraph::EData) -> Result<()> {
self.graph.set_edge_data(id, data)
}
fn with_edge_data(&mut self, id: impl AsRef<EdgeID>, transform: &dyn Fn(&mut InnerGraph::EData)) -> Result<()> {
self.graph.with_edge_data(id, transform)
}
}
#[cfg(feature = "serde")]
impl<InnerGraph, InnerForest> Serialize for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph + Serialize,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(&self.graph, &self.forest).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, InnerGraph, InnerForest> Deserialize<'de> for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph + Deserialize<'de>,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Deserialize<'de> + Default,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let (graph, tree) = <(InnerGraph, InnerForest)>::deserialize(deserializer)?;
CompoundBase::new_with_graph_and_forest(graph, tree).map_err(serde::de::Error::custom)
}
}
#[cfg(all(feature = "serde", feature = "serde_json"))]
impl<InnerGraph, InnerForest> CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph + Serialize,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Serialize,
{
pub fn to_json(&self) -> String {
serde_json::to_string(self).unwrap()
}
}
#[cfg(all(feature = "serde", feature = "serde_json"))]
impl<'de, InnerGraph, InnerForest> CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph + Deserialize<'de>,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Deserialize<'de> + Default,
{
pub fn from_json(json: &'de str) -> Result<Self, serde_json::Error> {
serde_json::from_str(json)
}
}
#[cfg(all(feature = "serde", feature = "serde_json"))]
impl<InnerGraph, InnerForest> std::fmt::Display for CompoundBase<InnerGraph, InnerForest>
where
InnerGraph: MutableGraph + Serialize,
InnerForest: MutableForest<GData = (), NData = (), EData = ()> + Serialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.to_json())
}
}