diff --git a/src/models.rs b/src/models.rs index 0834a4a..3c55fbd 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,5 +1,8 @@ //! Concrete graph topology models. +use crate::maps::ElementMap; +use crate::traits::{GraphTopology, GraphTopologyAddition}; + pub mod append_graph; pub mod frozen_graph; pub mod graph; @@ -11,3 +14,35 @@ pub use frozen_graph::{ FrozenGraph, FrozenGraphEdgeMap, FrozenGraphIncidence, FrozenGraphVertexMap, }; pub use graph::{Graph, GraphEdgeMap, GraphIncidence, GraphVertexMap}; + +/// Builds a new graph isomorphic to `source`. +/// +/// The resulting graph type `G` must implement [`GraphTopologyAddition`] which is used to add +/// vertices and edges. `on_edge` is called for each edge in `source` together with the +/// corresponding new edge of the new graph, which callers can use to construct an edge mapping. +/// +/// Used by the [`GraphTopologyAddition`] models' `From<&H>` and [`FromGraph`] implementations. +/// +/// [`FromGraph`]: crate::traits::FromGraph +pub(crate) fn build_from_topology( + source: &H, + vertex_default: G::Vertex, + mut on_edge: impl FnMut(H::Edge, G::Edge), +) -> (G, ElementMap) { + let mut result = G::default(); + result.reserve_vertices(source.vertex_count()); + result.reserve_edges(source.edge_count()); + + let mut vertex_map = source.vertex_map(vertex_default); + for v in source.vertices() { + vertex_map[v] = result.add_vertex(); + } + + for e in source.edges() { + let (u, v) = source.incident_vertices(e); + let new_edge = result.add_edge(vertex_map[u], vertex_map[v]); + on_edge(e, new_edge); + } + + (result, vertex_map) +} diff --git a/src/models/append_graph.rs b/src/models/append_graph.rs index dae6622..58b7c2f 100644 --- a/src/models/append_graph.rs +++ b/src/models/append_graph.rs @@ -3,7 +3,8 @@ use std::num::NonZeroUsize; use crate::maps::ElementMap; -use crate::traits::{GraphTopology, GraphTopologyAddition, Incidence, IncidenceCursor}; +use crate::models; +use crate::traits::{FromGraph, GraphTopology, GraphTopologyAddition, Incidence, IncidenceCursor}; /// An opaque handle identifying a vertex in an [`AppendGraph`]. /// @@ -259,14 +260,38 @@ impl GraphTopologyAddition for AppendGraph { } } +impl From<&H> for AppendGraph { + fn from(source: &H) -> Self { + models::build_from_topology::(source, Vertex(usize::MAX), |_, _| {}).0 + } +} + +impl FromGraph for AppendGraph { + fn from_graph( + source: &H, + ) -> ( + Self, + ElementMap, + ElementMap, + ) { + let mut edge_map = source.edge_map(Edge(NonZeroUsize::MAX)); + let (result, vertex_map) = + models::build_from_topology(source, Vertex(usize::MAX), |e, new_e| edge_map[e] = new_e); + (result, vertex_map, edge_map) + } +} + #[cfg(test)] mod trait_tests { use super::AppendGraph; + use crate::models::Graph; crate::graph_topology_tests!(AppendGraph); crate::graph_topology_addition_tests!(AppendGraph); crate::graph_topology_clone_tests!(AppendGraph); crate::graph_topology_addition_clone_tests!(AppendGraph); + crate::graph_topology_from_graph_tests!(AppendGraph, Graph); + crate::graph_topology_addition_from_graph_tests!(AppendGraph, Graph); } #[cfg(test)] diff --git a/src/models/graph.rs b/src/models/graph.rs index ebfdfe1..eb96813 100644 --- a/src/models/graph.rs +++ b/src/models/graph.rs @@ -4,8 +4,10 @@ use std::num::NonZeroUsize; use typed_generational_arena::{Arena, Index}; use crate::maps::ElementMap; +use crate::models; use crate::traits::{ - GraphTopology, GraphTopologyAddition, GraphTopologyDeletion, Incidence, IncidenceCursor, + FromGraph, GraphTopology, GraphTopologyAddition, GraphTopologyDeletion, Incidence, + IncidenceCursor, }; /// An opaque handle identifying a vertex in a [`Graph`]. @@ -398,9 +400,38 @@ impl GraphTopologyDeletion for Graph { } } +impl From<&H> for Graph { + fn from(source: &H) -> Self { + models::build_from_topology::( + source, + Vertex::new(usize::MAX, usize::MAX), + |_, _| {}, + ) + .0 + } +} + +impl FromGraph for Graph { + fn from_graph( + source: &H, + ) -> ( + Self, + ElementMap, + ElementMap, + ) { + let mut edge_map = source.edge_map(Edge::new(usize::MAX, usize::MAX)); + let (result, vertex_map) = + models::build_from_topology(source, Vertex::new(usize::MAX, usize::MAX), |e, new_e| { + edge_map[e] = new_e + }); + (result, vertex_map, edge_map) + } +} + #[cfg(test)] mod trait_tests { use super::Graph; + use crate::models::AppendGraph; crate::graph_topology_tests!(Graph); crate::graph_topology_addition_tests!(Graph); @@ -408,6 +439,8 @@ mod trait_tests { crate::graph_topology_addition_deletion_tests!(Graph); crate::graph_topology_clone_tests!(Graph); crate::graph_topology_addition_clone_tests!(Graph); + crate::graph_topology_from_graph_tests!(Graph, AppendGraph); + crate::graph_topology_addition_from_graph_tests!(Graph, AppendGraph); } #[cfg(test)]