blob: 3e1e845981cb281d4045371f72658ee2393f7815 [file] [log] [blame]
//! # Nodes
//!
//! This module contains the three central node types used throughout the petgraph ecosystem:
//! * [`Node`]: Active node in a graph.
//! * [`NodeMut`]: Active (mutable) node in a graph.
//! * [`DetachedNode`]: Detached node from a graph.
//!
//! In application code [`DetachedNode`]s can easily be interchanged with [`Node`]s and vice-versa,
//! as long as all components are [`Clone`]able.
//!
//! You should prefer to use [`Node`]s whenever possible, as they are simply three references into
//! the underlying graph storage and provide convenient access to the node's neighbours and
//! connecting edges.
//!
//! [`NodeMut`]s are only needed when you need mutable access to the node's weight, and should be
//! used sparingly.
mod compat;
use core::{
fmt::{Debug, Display, Formatter},
hash::Hash,
};
use crate::{
edge::{Direction, Edge},
storage::{DirectedGraphStorage, GraphStorage},
};
/// ID of a node in a graph.
///
/// This is guaranteed to be unique within the graph, library authors and library consumers **must**
/// treat this as an opaque value 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 [`NodeId`] directly.
///
/// Accessing a [`GraphStorage`] implementation with a [`NodeId`] 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 NodeId(usize);
impl Display for NodeId {
// 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 {
writeln!(f, "NodeId({})", self.0)
}
}
// TODO: find a better way to gate these functions
impl NodeId {
/// Creates a new [`NodeId`].
///
/// # Note
///
/// Using this outside of the [`GraphStorage`] implementation is considered undefined behavior.
///
/// # Example
///
/// ```
/// use petgraph_core::node::NodeId;
///
/// let id = NodeId::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 [`NodeId`].
///
/// # Note
///
/// Using this outside of the [`GraphStorage`] implementation is considered undefined behavior.
///
/// # Example
///
/// ```
/// use petgraph_core::node::NodeId;
///
/// let id = NodeId::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 node in a graph.
///
/// Node that is part of a graph.
///
/// You can access the node's id and weight, as well as its neighbours and connecting edges.
///
/// # Example
///
/// ```
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(node.id(), &a);
/// assert_eq!(node.weight(), &"A");
/// ```
pub struct Node<'a, S>
where
S: GraphStorage,
{
storage: &'a S,
id: NodeId,
weight: &'a S::NodeWeight,
}
impl<S> PartialEq for Node<'_, S>
where
S: GraphStorage,
S::NodeWeight: PartialEq,
{
fn eq(&self, other: &Node<'_, S>) -> bool {
(self.id, self.weight).eq(&(other.id, other.weight))
}
}
impl<S> Eq for Node<'_, S>
where
S: GraphStorage,
S::NodeWeight: Eq,
{
}
impl<S> PartialOrd for Node<'_, S>
where
S: GraphStorage,
S::NodeWeight: PartialOrd,
{
fn partial_cmp(&self, other: &Node<'_, S>) -> Option<core::cmp::Ordering> {
(self.id, self.weight).partial_cmp(&(other.id, other.weight))
}
}
impl<S> Ord for Node<'_, S>
where
S: GraphStorage,
S::NodeWeight: Ord,
{
fn cmp(&self, other: &Node<'_, S>) -> core::cmp::Ordering {
(self.id, self.weight).cmp(&(other.id, other.weight))
}
}
impl<S> Hash for Node<'_, S>
where
S: GraphStorage,
S::NodeWeight: Hash,
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
(self.id, self.weight).hash(state);
}
}
impl<S> Clone for Node<'_, S>
where
S: GraphStorage,
{
fn clone(&self) -> Self {
*self
}
}
impl<S> Copy for Node<'_, S> where S: GraphStorage {}
impl<S> Debug for Node<'_, S>
where
S: GraphStorage,
S::NodeWeight: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Node")
.field("id", &self.id)
.field("weight", &self.weight)
.finish()
}
}
impl<'a, S> Node<'a, S>
where
S: GraphStorage,
{
/// Creates a new node.
///
/// You should not need to use this directly, instead use [`Graph::node`].
///
/// This is only for implementors of [`GraphStorage`].
///
/// # Contract
///
/// The `id` must be valid for the given `storage` and the `weight` must be valid for the given
/// `id`.
///
/// The contract is not enforced, due to concerns of recursive calls on [`GraphStorage::node`]
/// and [`GraphStorage::contains_node`].
///
/// # Example
///
/// ```
/// use petgraph_core::{edge::Direction, node::Node};
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node(&a).unwrap();
/// let copy = Node::new(graph.storage(), node.id(), node.weight());
/// // ^ exact same as `let copy = *node;`
/// ```
///
/// [`Graph::node`]: crate::graph::Graph::node
pub const fn new(storage: &'a S, id: NodeId, weight: &'a S::NodeWeight) -> Self {
Self {
storage,
id,
weight,
}
}
/// The unique id of the node.
///
/// This is guaranteed to be unique within the graph, the type returned depends on the
/// implementation of [`GraphStorage`].
///
/// # Example
///
/// ```
/// use petgraph_core::{edge::Direction, node::Node};
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(node.id(), &a);
/// ```
#[must_use]
pub const fn id(&self) -> NodeId {
self.id
}
/// The weight of the node.
///
/// # Example
///
/// ```
/// use petgraph_core::{edge::Direction, node::Node};
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(node.weight(), &"A");
/// ```
#[must_use]
pub const fn weight(&self) -> &'a S::NodeWeight {
self.weight
}
}
impl<'a, S> Node<'a, S>
where
S: GraphStorage,
{
/// Returns an iterator over the node's neighbours.
///
/// This will return _all_ neighbours, regardless of direction.
///
/// # 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 c = *graph.insert_node("C").id();
///
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
/// let bc = *graph.insert_edge("B → C", &b, &c).id();
/// let ca = *graph.insert_edge("C → A", &c, &a).id();
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(
/// node.neighbours().map(|node| *node.id()).collect::<Vec<_>>(),
/// vec![b, c]
/// );
/// ```
pub fn neighbours(&self) -> impl Iterator<Item = Node<'a, S>> + 'a {
self.storage.node_neighbours(self.id)
}
/// Returns an iterator over the node's connecting edges.
///
/// This will return _all_ connecting edges, regardless of direction.
///
/// # 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 c = *graph.insert_node("C").id();
///
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
/// let bc = *graph.insert_edge("B → C", &b, &c).id();
/// let ca = *graph.insert_edge("C → A", &c, &a).id();
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(
/// node.connections()
/// .map(|edge| *edge.id())
/// .collect::<Vec<_>>(),
/// vec![ab, ca]
/// );
/// ```
pub fn connections(&self) -> impl Iterator<Item = Edge<'a, S>> + 'a {
self.storage.node_connections(self.id)
}
// TODO: implement degree in petgraph-dino and test
/// Returns the number of edges connected to the node.
///
/// This is also known as the node's degree or valency.
///
/// # 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 c = *graph.insert_node("C").id();
///
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
/// let bc = *graph.insert_edge("B → C", &b, &c).id();
/// let ca = *graph.insert_edge("C → A", &c, &a).id();
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(node.degree(), 2);
/// ```
#[must_use]
pub fn degree(&self) -> usize {
self.storage.node_degree(self.id)
}
/// Change the underlying storage of the node.
///
/// 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) -> Node<'a, T>
where
T: GraphStorage<NodeWeight = S::NodeWeight>,
{
Node {
storage,
id: self.id,
weight: self.weight,
}
}
}
impl<'a, S> Node<'a, S>
where
S: DirectedGraphStorage,
{
/// Returns an iterator over the node's neighbours in the given direction.
///
/// # Example
///
/// ```
/// use petgraph_core::edge::Direction;
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let c = *graph.insert_node("C").id();
///
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
/// let bc = *graph.insert_edge("B → C", &b, &c).id();
/// let ca = *graph.insert_edge("C → A", &c, &a).id();
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(
/// node.directed_connections(Direction::Outgoing)
/// .map(|edge| *edge.id())
/// .collect::<Vec<_>>(),
/// vec![ab]
/// );
///
/// assert_eq!(
/// node.directed_connections(Direction::Incoming)
/// .map(|edge| *edge.id())
/// .collect::<Vec<_>>(),
/// vec![ca]
/// );
/// ```
pub fn directed_connections(
&self,
direction: Direction,
) -> impl Iterator<Item = Edge<'a, S>> + 'a {
self.storage.node_directed_connections(self.id, direction)
}
/// Returns an iterator over the node's neighbours in the given direction.
///
/// # Example
///
/// ```
/// use petgraph_core::edge::Direction;
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// let b = *graph.insert_node("B").id();
/// let c = *graph.insert_node("C").id();
///
/// let ab = *graph.insert_edge("A → B", &a, &b).id();
/// let bc = *graph.insert_edge("B → C", &b, &c).id();
/// let ca = *graph.insert_edge("C → A", &c, &a).id();
///
/// let node = graph.node(&a).unwrap();
///
/// assert_eq!(
/// node.directed_neighbours(Direction::Outgoing)
/// .map(|edge| *edge.id())
/// .collect::<Vec<_>>(),
/// vec![b]
/// );
///
/// assert_eq!(
/// node.directed_neighbours(Direction::Incoming)
/// .map(|edge| *edge.id())
/// .collect::<Vec<_>>(),
/// vec![c]
/// );
/// ```
pub fn directed_neighbours(
&self,
direction: Direction,
) -> impl Iterator<Item = Node<'a, S>> + 'a {
self.storage.node_directed_neighbours(self.id, direction)
}
}
impl<S> Node<'_, S>
where
S: GraphStorage,
S::NodeWeight: Clone,
{
/// Detaches the node 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 [`DetachedNode`], 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;
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node(&a).unwrap().detach();
///
/// assert_eq!(node.id, a);
/// assert_eq!(node.weight, "A");
/// ```
///
/// [`Graph::from_parts`]: crate::graph::Graph::from_parts
#[must_use]
pub fn detach(self) -> DetachedNode<S::NodeWeight> {
DetachedNode::new(self.id, self.weight.clone())
}
}
/// Active (mutable) node in a graph.
///
/// Node that is part of a graph and has exclusive mutable access to the weight of the node.
///
/// To prevent multiple borrows of the same node, 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 mut a = graph.insert_node("A");
///
/// assert_eq!(a.weight(), &"A");
/// assert_eq!(a.weight_mut(), &mut "A");
///
/// # let a = *a.id();
/// # graph.insert_edge("A → A", &a, &a);
/// ```
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeMut<'a, S>
where
S: GraphStorage,
{
id: NodeId,
weight: &'a mut S::NodeWeight,
}
impl<'a, S> NodeMut<'a, S>
where
S: GraphStorage,
{
/// Creates a new node.
///
/// You should not need to use this directly, instead use [`Graph::node_mut`] or
/// [`Graph::insert_node`].
///
/// This is only for implementors of [`GraphStorage`].
///
/// # Contract
///
/// The `id` must be valid for the given `storage` and the `weight` must be valid for the given
/// `id`.
///
///
/// [`Graph::node_mut`]: crate::graph::Graph::node_mut
/// [`Graph::insert_node`]: crate::graph::Graph::insert_node
pub fn new(id: NodeId, weight: &'a mut S::NodeWeight) -> Self {
Self { id, weight }
}
/// The unique id of the node.
///
/// This is guaranteed to be unique within the graph, the type returned depends on the
/// implementation of [`GraphStorage`].
///
/// # Example
///
/// ```
/// use petgraph_core::{edge::Direction, node::Node};
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node_mut(&a).unwrap();
///
/// assert_eq!(node.id(), &a);
/// ```
#[must_use]
pub const fn id(&self) -> NodeId {
self.id
}
/// The weight of the node.
///
/// # Example
///
/// ```
/// use petgraph_core::{edge::Direction, node::Node};
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node_mut(&a).unwrap();
///
/// assert_eq!(node.weight(), &"A");
/// ```
#[must_use]
pub fn weight(&self) -> &S::NodeWeight {
self.weight
}
/// The (mutable) weight of the node.
///
/// # Example
///
/// ```
/// use petgraph_core::{edge::Direction, node::Node};
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let mut node = graph.node_mut(&a).unwrap();
///
/// assert_eq!(node.weight_mut(), &mut "A");
/// ```
pub fn weight_mut(&mut self) -> &mut S::NodeWeight {
self.weight
}
/// Change the underlying storage of the node.
///
/// 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) -> NodeMut<'a, T>
where
T: GraphStorage<NodeWeight = S::NodeWeight>,
{
NodeMut {
id: self.id,
weight: self.weight,
}
}
}
impl<S> NodeMut<'_, S>
where
S: GraphStorage,
S::NodeWeight: Clone,
{
/// Detaches the node 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 [`DetachedNode`], 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;
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node_mut(&a).unwrap().detach();
///
/// assert_eq!(node.id, a);
/// assert_eq!(node.weight, "A");
/// ```
///
/// [`Graph::from_parts`]: crate::graph::Graph::from_parts
#[must_use]
pub fn detach(&self) -> DetachedNode<S::NodeWeight> {
DetachedNode::new(self.id, self.weight.clone())
}
}
/// Detached node from a graph.
///
/// This node is no longer considered to be part of a graph, but can be reattached 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_core::edge::Direction;
/// use petgraph_dino::DiDinoGraph;
///
/// let mut graph = DiDinoGraph::new();
///
/// let a = *graph.insert_node("A").id();
/// # graph.insert_edge("A → A", &a, &a);
///
/// let node = graph.node(&a).unwrap().detach();
///
/// assert_eq!(node.id, a);
/// assert_eq!(node.weight, "A");
/// ```
///
/// [`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 DetachedNode<W> {
/// The unique id of the node.
pub id: NodeId,
/// The weight of the node.
pub weight: W,
}
impl<W> DetachedNode<W> {
/// Creates a new detached node.
///
/// # Example
///
/// ```
/// use petgraph_core::node::DetachedNode;
///
/// let node = DetachedNode::new(0, "A");
/// ```
pub const fn new(id: NodeId, weight: W) -> Self {
Self { id, weight }
}
}