blob: 14156124e6383cdff8f903acb5e128ecfdd79ee8 [file] [log] [blame]
//! # Edges
//!
//! This module contains the three edge types used by the graph, an edge is a connection between two
//! nodes, that may or may not be directed and has a weight.
//!
//! The three edge types are:
//! * [`Edge`]: An immutable edge, that borrows the graph.
//! * [`EdgeMut`]: A mutable edge, that borrows the graph.
//! * [`DetachedEdge`]: An edge that is not attached to the graph.
//!
//! In application code [`DetachedEdge`]s can easily be interchanged with [`Edge`]s and vice-versa,
//! as long as all components are [`Clone`]able.
//!
//! You should prefer to use [`Edge`]s and [`EdgeMut`]s over [`DetachedEdge`]s, as they are more
//! efficient, as these are simply (mutable) reference into the underlying graph (storage).
//!
//! [`EdgeMut`]s are only needed when you want to mutate the weight of an edge, otherwise you should
//! use [`Edge`]s.
mod compat;
mod direction;
pub mod marker;
use core::fmt::{Debug, Display, Formatter};
pub use self::{direction::Direction, marker::GraphDirectionality};
use crate::{
node::{Node, NodeId},
storage::GraphStorage,
DirectedGraphStorage,
};
type DetachedStorageEdge<S> = DetachedEdge<<S as GraphStorage>::EdgeWeight>;
/// ID of an edge in a graph.
///
/// This is guaranteed to be unique within the graph, library authors and library consumers **must**
/// treat this as an opaque type akin to [`TypeId`].
///
/// The layout of the type is semver stable, but not part of the public API.
///
/// [`GraphStorage`] implementations may uphold additional invariants on the inner value and
/// code outside of the [`GraphStorage`] should **never** construct a [`EdgeId`] directly.
///
/// Accessing a [`GraphStorage`] implementation with a [`EdgeId`] not returned by an instance itself
/// is considered undefined behavior.
///
/// [`TypeId`]: core::any::TypeId
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EdgeId(usize);
impl Display for EdgeId {
// we could also utilize a VTable here instead, that would allow for custom formatting
// but that would be an additional pointer added to the type that must be carried around
// that's about ~8 bytes on 64-bit systems
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "EdgeId({})", self.0)
}
}
// TODO: find a better way to gate these functions
impl EdgeId {
/// Creates a new [`EdgeId`].
///
/// # Note
///
/// Using this outside of the [`GraphStorage`] implementation is considered undefined behavior.
///
/// # Example
///
/// ```
/// use petgraph_core::edge::EdgeId;
///
/// let id = EdgeId::new(0);
/// ```
// Hidden so that non-GraphStorage implementors are not tempted to use this.
#[doc(hidden)]
#[must_use]
pub const fn new(id: usize) -> Self {
Self(id)
}
/// Returns the inner value of the [`EdgeId`].
///
/// # Note
///
/// Using this outside of the [`GraphStorage`] implementation is considered undefined behavior.
///
/// # Example
///
/// ```
/// use petgraph_core::edge::EdgeId;
///
/// let id = EdgeId::new(0);
///
/// assert_eq!(id.into_inner(), 0);
/// ```
// Hidden so that non-GraphStorage implementors are not tempted to use this.
#[doc(hidden)]
#[must_use]
pub const fn into_inner(self) -> usize {
self.0
}
}
/// Active edge in the graph.
///
/// Edge that is part of the graph, it borrows the graph and can be used to access the endpoints.
///
/// Undirected graph implementations have no notion of a source and target, therefore endpoints can
/// only be accessed through [`Self::endpoint_ids`] and [`Self::endpoints`].
/// If the storage implementation is directed (implements [`DirectedGraphStorage`]), one can access
/// the source and target through [`Self::source_id`], [`Self::source`], [`Self::target_id`] and
/// [`Self::target`].
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let aa = *graph.insert_edge("A → A", &a, &a).id();
///
/// let edge = graph.edge(&aa).unwrap();
///
/// assert_eq!(edge.id(), &aa);
/// assert_eq!(edge.weight(), &"A → A");
/// ```
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Edge<'a, S>
where
S: GraphStorage,
{
storage: &'a S,
id: EdgeId,
u: NodeId,
v: NodeId,
weight: &'a S::EdgeWeight,
}
impl<S> Clone for Edge<'_, S>
where
S: GraphStorage,
{
fn clone(&self) -> Self {
*self
}
}
impl<S> Copy for Edge<'_, S> where S: GraphStorage {}
impl<S> Debug for Edge<'_, S>
where
S: GraphStorage,
S::EdgeWeight: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Edge")
.field("id", &self.id)
.field("u", &self.u)
.field("v", &self.v)
.field("weight", &self.weight)
.finish()
}
}
impl<'a, S> Edge<'a, S>
where
S: GraphStorage,
{
/// Create a new edge.
///
/// You should not need to use this directly, instead use [`Graph::edge`].
///
/// This is only for implementors of [`GraphStorage`].
///
/// In an undirected graph `u` and `v` are interchangeable, but in a directed graph (implements
/// [`DirectedGraphStorage`]) `u` is the source and `v` is the target.
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let aa = *graph.insert_edge("A → A", &a, &a).id();
///
/// let edge = graph.edge(&aa).unwrap();
/// let copy = Edge::new(
/// graph.storage(),
/// edge.id(),
/// edge.weight(),
/// edge.source_id(),
/// edge.target_id(),
/// );
/// // ^ exact same as `let copy = *edge;`
/// ```
///
/// # Contract
///
/// The `id`, `source_id` and `target_id` must be valid in the given `storage`, and
/// [`storage.node(source_id)`](GraphStorage::node) and
/// [`storage.node(target_id)`](GraphStorage::node) must return `Some(_)`.
/// The `weight` must be valid in the given `storage` for the specified `id`.
///
/// The contract on `id` is not enforced, to avoid recursive calls to [`GraphStorage::edge`] and
/// [`GraphStorage::contains_edge`].
/// The contract on `source_id` and `target_id` is checked in debug builds.
///
/// [`Graph::edge`]: crate::graph::Graph::edge
pub fn new(
storage: &'a S,
id: EdgeId,
weight: &'a S::EdgeWeight,
u: NodeId,
v: NodeId,
) -> Self {
debug_assert!(storage.contains_node(u));
debug_assert!(storage.contains_node(v));
Self {
storage,
id,
u,
v,
weight,
}
}
/// The unique id of the edge.
///
/// This is guaranteed to be unique within the graph, the type returned depends on the
/// implementation of [`GraphStorage`].
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let aa = *graph.insert_edge("A → A", &a, &a).id();
///
/// let edge = graph.edge(&aa).unwrap();
/// assert_eq!(edge.id(), &aa);
/// ```
#[must_use]
pub const fn id(&self) -> EdgeId {
self.id
}
/// Get the ids of the endpoints of this edge.
///
/// While [`Self::source_id`] and [`Self::target_id`] are only available for directed graphs,
/// this method is available for both directed and undirected graphs.
///
/// The order of the ids is not guaranteed for undirected graphs, but corresponds to `(source,
/// target)` for directed graph, this should be considered an implementation detail and one
/// **should not** rely on the order.
///
/// You should use [`Self::source_id`] and [`Self::target_id`] directly if you need the source
/// and target.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
///
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap();
///
/// let (u, v) = edge.endpoint_ids(); // <- the order is not guaranteed for undirected graphs
///
/// assert!((u, v) == (&a, &b) || (u, v) == (&b, &a));
/// ```
#[must_use]
pub const fn endpoint_ids(&self) -> (NodeId, NodeId) {
(self.u, self.v)
}
/// Get the endpoints of this edge.
///
/// While [`Self::source`] and [`Self::target`] are only available for directed graphs, this
/// method is available for both directed and undirected graphs
///
/// The order of the endpoints is not guaranteed for undirected graphs, but corresponds to
/// `(source, target)` for directed graph, this should be considered an implementation
/// detail and one **should not** rely on the order.
///
/// You should use [`Self::source`] and [`Self::target`] directly if you need the source and
/// target.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
///
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap();
///
/// let (u, v) = edge.endpoints(); // <- the order is not guaranteed for undirected graphs
///
/// assert!((u.id(), v.id()) == (&a, &b) || (u.id(), v.id()) == (&b, &a));
/// ```
///
/// # Panics
///
/// Panics if the endpoints are not active in the same storage as this edge.
///
/// This error will only occur if the storage has been corrupted or if the contract on
/// [`Edge::new`] is violated.
#[must_use]
pub fn endpoints(&self) -> (Node<'a, S>, Node<'a, S>) {
(
self.storage.node(self.u).expect(
"corrupted storage or violated contract upon creation of this edge; the endpoint \
node must be active in the same storage as this edge",
),
self.storage.node(self.v).expect(
"corrupted storage or violated contract upon creation of this edge; the endpoint \
node must be active in the same storage as this edge",
),
)
}
/// Get the weight of this edge.
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap();
/// assert_eq!(edge.weight(), &"A → B");
/// ```
#[must_use]
pub const fn weight(&self) -> &'a S::EdgeWeight {
self.weight
}
/// Change the underlying storage of this edge.
///
/// Should only be used when layering multiple [`GraphStorage`] implementations on top of each
/// other.
///
/// # Note
///
/// This should not lead to any undefined behaviour, but might have unintended consequences if
/// the storage does not recognize the inner id as valid.
/// You should only use this if you know what you are doing.
#[must_use]
pub const fn change_storage_unchecked<T>(self, storage: &'a T) -> Edge<'a, T>
where
T: GraphStorage<EdgeWeight = S::EdgeWeight>,
{
Edge {
storage,
id: self.id,
u: self.u,
v: self.v,
weight: self.weight,
}
}
}
impl<'a, S> Edge<'a, S>
where
S: DirectedGraphStorage,
{
/// Get the source node id of this edge.
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap();
/// assert_eq!(edge.source_id(), &a);
/// ```
#[must_use]
pub const fn source_id(&self) -> NodeId {
self.u
}
/// Get the source node of this edge.
///
/// This is a shortcut for [`self.storage.node(self.source_id())`](GraphStorage::node).
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap();
///
/// let source = edge.source();
/// assert_eq!(source.id(), &a);
/// ```
///
///
/// # Panics
///
/// Panics if the source node is not active in the same storage as this edge.
///
/// This error will only occur if the storage has been corrupted or if the contract on
/// [`Edge::new`] is violated.
#[must_use]
pub fn source(&self) -> Node<'a, S> {
self.storage.node(self.u).expect(
"corrupted storage or violated contract upon creation of this edge; the source node \
must be active in the same storage as this edge",
)
}
#[must_use]
/// Get the target node id of this edge.
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap();
/// assert_eq!(edge.target_id(), &b);
/// ```
pub const fn target_id(&self) -> NodeId {
self.v
}
/// Get the target node of this edge.
///
/// This is a shortcut for [`self.storage.node(self.target_id())`](GraphStorage::node).
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap();
///
/// let target = edge.target();
/// assert_eq!(target.id(), &b);
/// ```
///
///
/// # Panics
///
/// Panics if the target node is not active in the same storage as this edge.
///
/// This error will only occur if the storage has been corrupted or if the contract on
/// [`Edge::new`] is violated.
#[must_use]
pub fn target(&self) -> Node<'a, S> {
self.storage.node(self.v).expect(
"corrupted storage or violated contract upon creation of this edge; the target node \
must be active in the same storage as this edge",
)
}
}
impl<S> Edge<'_, S>
where
S: GraphStorage,
S::EdgeWeight: Clone,
{
/// Detach this edge from the graph.
///
/// > **Note:** This will _not_ remove the node from the graph, it will only detach the this
/// > instance of the node removing the lifetime dependency on the graph.
///
/// This will return a [`DetachedEdge`], which can be reattached to the graph using
/// [`Graph::from_parts`].
///
/// This is especially useful in use-cases where you want direct (mutable access) to both the
/// weight and id or do not want to bother with the graph's lifetime.
///
/// # Example
///
/// ```
/// use petgraph_core::{
/// edge::{Direction, Edge},
/// node::Node,
/// };
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge(&ab).unwrap().detach();
///
/// assert_eq!(edge.id, ab);
/// assert_eq!(edge.weight, "A → B");
/// ```
///
/// [`Graph::from_parts`]: crate::graph::Graph::from_parts
#[must_use]
pub fn detach(self) -> DetachedStorageEdge<S> {
DetachedEdge::new(self.id, self.weight.clone(), self.u, self.v)
}
}
/// Active (mutable) edge in the graph.
///
/// Edge that is part of the graph, it borrows the graph and can be used to mutably access the
/// weight of an edge. The source and node are not available mutably, as changing those might
/// violate some internal constraints of the [`GraphStorage`] they are part of.
///
/// To prevent multiple borrows of the same edge, while still allowing for multiple borrows into the
/// same storage, this type does not carry a reference to the storage itself.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let mut ab = graph.insert_edge("A → B", &a, &b);
///
/// assert_eq!(ab.weight(), &"A → B");
/// assert_eq!(ab.weight_mut(), &mut "A → B");
/// ```
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EdgeMut<'a, S>
where
S: GraphStorage,
{
id: EdgeId,
weight: &'a mut S::EdgeWeight,
u: NodeId,
v: NodeId,
}
impl<'a, S> EdgeMut<'a, S>
where
S: GraphStorage,
{
/// Create a new edge.
///
/// You should not need to use this directly, instead use [`Graph::edge_mut`] or
/// [`Graph::insert_edge`].
///
/// This is only for implementors of [`GraphStorage`].
///
/// In an undirected graph `u` and `v` are interchangeable, but in a directed graph (implements
/// [`DirectedGraphStorage`]) `u` is the source and `v` is the target.
///
/// # Contract
///
/// The `id`, `source_id` and `target_id` must be valid in the given `storage`, and the `weight`
/// must be valid in the given `storage` for the specified `id`.
///
/// [`Graph::edge_mut`]: crate::graph::Graph::edge_mut
/// [`Graph::insert_edge`]: crate::graph::Graph::insert_edge
pub fn new(id: EdgeId, weight: &'a mut S::EdgeWeight, u: NodeId, v: NodeId) -> Self {
Self { id, weight, u, v }
}
/// The unique id of the edge.
///
/// This is guaranteed to be unique within the graph, the type returned depends on the
/// implementation of [`GraphStorage`].
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge_mut(&ab).unwrap();
///
/// assert_eq!(edge.id(), &ab);
/// ```
#[must_use]
pub const fn id(&self) -> EdgeId {
self.id
}
/// The ids of the endpoints of the edge.
///
/// While [`Self::source_id`] and [`Self::target_id`] are only available for directed graphs,
/// this method is available for both directed and undirected graphs.
///
/// The order of the ids is not guaranteed for undirected graphs, but corresponds to `(source,
/// target)` for directed graph, this should be considered an implementation detail and one
/// **should not** rely on the order.
///
/// You should use [`Self::source_id`] and [`Self::target_id`] directly if you need the source
/// and target.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
///
/// let ab = graph.insert_edge("A → B", &a, &b);
///
/// let (u, v) = ab.endpoint_ids(); // <- the order is not guaranteed for undirected graphs
///
/// assert!((u, v) == (&a, &b) || (u, v) == (&b, &a));
/// ```
#[must_use]
pub const fn endpoint_ids(&self) -> (NodeId, NodeId) {
(self.u, self.v)
}
/// The weight of the edge.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge_mut(&ab).unwrap();
///
/// assert_eq!(edge.weight(), &"A → B");
/// ```
#[must_use]
pub fn weight(&self) -> &S::EdgeWeight {
self.weight
}
/// The (mutable) weight of the edge.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let mut edge = graph.edge_mut(&ab).unwrap();
///
/// assert_eq!(edge.weight_mut(), &mut "A → B");
/// ```
pub fn weight_mut(&mut self) -> &mut S::EdgeWeight {
self.weight
}
/// Change the underlying storage of this edge.
///
/// Should only be used when layering multiple [`GraphStorage`] implementations on top of each
/// other.
///
/// # Note
///
/// This should not lead to any undefined behaviour, but might have unintended consequences if
/// the storage does not recognize the inner id as valid.
/// You should only use this if you know what you are doing.
#[must_use]
pub fn change_storage_unchecked<T>(self) -> EdgeMut<'a, T>
where
T: GraphStorage<EdgeWeight = S::EdgeWeight>,
{
EdgeMut {
id: self.id,
weight: self.weight,
u: self.u,
v: self.v,
}
}
}
impl<'a, S> EdgeMut<'a, S>
where
S: DirectedGraphStorage,
{
/// The source node id of the edge.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge_mut(&ab).unwrap();
///
/// assert_eq!(edge.source_id(), &a);
/// ```
#[must_use]
pub const fn source_id(&self) -> NodeId {
self.u
}
/// The target node id of the edge.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let edge = graph.edge_mut(&ab).unwrap();
///
/// assert_eq!(edge.target_id(), &b);
/// ```
#[must_use]
pub const fn target_id(&self) -> NodeId {
self.v
}
}
impl<S> EdgeMut<'_, S>
where
S: GraphStorage,
S::EdgeWeight: Clone,
{
/// Detaches the edge from the graph.
///
/// > **Note:** This will _not_ remove the node from the graph, it will only detach the this
/// > instance of the node removing the lifetime dependency on the graph.
///
///
/// This will return an [`DetachedEdge`], which can be reattached to the graph using
/// [`Graph::from_parts`].
///
/// This is especially useful in use-cases where you want direct (mutable access) to both the
/// weight and id or do not want to bother with the graph's lifetime.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let mut edge = graph.edge_mut(&ab).unwrap().detach();
///
/// assert_eq!(edge.id, ab);
/// assert_eq!(edge.weight, "A → B");
/// ```
///
/// [`Graph::from_parts`]: crate::graph::Graph::from_parts
#[must_use]
pub fn detach(self) -> DetachedStorageEdge<S> {
DetachedEdge::new(self.id, self.weight.clone(), self.u, self.v)
}
}
/// Detached edge from a graph.
///
/// This edge is no longer considered to be, but can be reattached to the graph using
/// [`Graph::from_parts`].
///
/// Especially useful in cases of decomposition ([`Graph::into_parts`]) or if one does not want to
/// deal with the graph's lifetime or needs a node to outlive the graph.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
///
/// let mut edge = graph.edge_mut(&ab).unwrap().detach();
///
/// assert_eq!(edge.id, ab);
/// assert_eq!(edge.weight, "A → B");
/// ```
///
/// [`Graph::into_parts`]: crate::graph::Graph::into_parts
/// [`Graph::from_parts`]: crate::graph::Graph::from_parts
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DetachedEdge<W> {
/// The unique id of the edge.
pub id: EdgeId,
/// The `u` endpoint of the `(u, v)` pair of endpoints.
pub u: NodeId,
/// The `v` endpoint of the `(u, v)` pair of endpoints.
pub v: NodeId,
/// The weight of the edge.
pub weight: W,
}
impl<W> DetachedEdge<W> {
/// Create a new detached edge.
///
/// In an undirected graph `u` and `v` are interchangeable, but in a directed graph (implements
/// [`DirectedGraphStorage`]) `u` is the source and `v` is the target.
///
/// # Example
///
/// ```
/// use petgraph_core::edge::DetachedEdge;
///
/// let edge = DetachedEdge::new(0, "A → B", 1, 2);
/// ```
pub const fn new(id: EdgeId, weight: W, u: NodeId, v: NodeId) -> Self {
Self { id, u, v, weight }
}
}