fuchsia / third_party / github.com / petgraph / petgraph / 5c8ab669a8618059f20989660e8423e97ac905af / . / crates / core / src / graph / insert.rs

#[cfg(feature = "alloc")] | |

use alloc::{vec, vec::Vec}; | |

use error_stack::{Result, ResultExt}; | |

use crate::{ | |

edge::{EdgeId, EdgeMut}, | |

graph::Graph, | |

node::{NodeId, NodeMut}, | |

storage::GraphStorage, | |

Error, | |

}; | |

impl<S> Graph<S> | |

where | |

S: GraphStorage, | |

{ | |

/// Try to insert a node with the given attributes. | |

/// | |

/// This is the fallible version of [`Self::insert_node`]. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::DiDinoGraph; | |

/// | |

/// // we need to explicitly state the type of the edge weights, as we do insert any edges and | |

/// // therefore cannot infer them. | |

/// let mut graph = DiDinoGraph::<_, ()>::new(); | |

/// let node = graph.try_insert_node(()).expect("unable to insert node"); | |

/// ``` | |

/// | |

/// # Errors | |

/// | |

/// If any of the constraints that are required for the graph storage to be valid are violated. | |

/// This may include things like parallel edges or self loops depending on implementation. | |

/// | |

/// Refer to the documentation of the underlying storage for more information. | |

pub fn try_insert_node(&mut self, weight: S::NodeWeight) -> Result<NodeMut<S>, Error> { | |

let id = self.storage.next_node_id(); | |

self.storage.insert_node(id, weight).change_context(Error) | |

} | |

/// Insert a node with the given attributes. | |

/// | |

/// Depending on the storage type, or if your code is generic over the storage type, you might | |

/// want to consider using [`Self::try_insert_node`] instead. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::DiDinoGraph; | |

/// | |

/// // we need to explicitly state the type of the edge weights, as we do insert any edges and | |

/// // therefore cannot infer them. | |

/// let mut graph = DiDinoGraph::<_, ()>::new(); | |

/// let node = graph.insert_node(()); | |

/// ``` | |

/// | |

/// # Rationale | |

/// | |

/// There are two functions for inserting a node (actually four). | |

/// [`Self::insert_node`] and [`Self::try_insert_node`]. | |

/// | |

/// Why is that the case? | |

/// | |

/// The reason is that some storage types might not be able to guarantee that the node can be | |

/// inserted, but we still want to provide a convenient way to insert a node. | |

/// Another reason is that this mirrors the API of other libraries and the std, such as the | |

/// standard library (through [`Vec::push`], or | |

/// [`std::collections::HashMap::insert`]). | |

/// These may also panic and do not return a result. | |

/// But(!) it is important to note that the constraints and reason why they may panic are quite | |

/// different from the ones of a Graph, as the ones of a Graph can be considered a superset. | |

/// Not only do they potentially fail on allocation failures, but certain constraints exist such | |

/// as parallel edges or self loops, which may allow for panics more often than other | |

/// libraries would. | |

/// This is why we provide both functions, and you (the user) should decide which one to use. | |

/// | |

/// # Panics | |

/// | |

/// If any of the constraints that are required for the graph storage to be valid are violated. | |

/// This may include things like parallel edges or self loops depending on implementation. | |

/// | |

/// Refer to the documentation of the underlying storage for more information. | |

pub fn insert_node(&mut self, weight: S::NodeWeight) -> NodeMut<S> { | |

self.try_insert_node(weight) | |

.expect("Constraint violation. Try using `try_insert_node` instead.") | |

} | |

} | |

impl<S> Graph<S> | |

where | |

S: GraphStorage, | |

{ | |

/// Insert a node, where the weight is dependent on the id. | |

/// | |

/// This is similar to [`Self::try_insert_node`], but instead of providing the weight as a | |

/// parameter, it can take into account the future id. | |

/// | |

/// This is the fallible version of [`Self::insert_node_with`]. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::{DiDinoGraph, NodeId}; | |

/// | |

/// struct Node { | |

/// id: NodeId, | |

/// } | |

/// | |

/// // we need to explicitly state the type of the edge weights, as we do insert | |

/// // any edges and therefore cannot infer them. | |

/// let mut graph = DiDinoGraph::<_, ()>::new(); | |

/// let node_id = *graph | |

/// .try_insert_node_with(|id| Node { id: *id }) | |

/// .expect("unable to insert node") | |

/// .id(); | |

/// | |

/// let node = graph.node(&node_id).expect("node must exist"); | |

/// | |

/// assert_eq!(node.weight().id, node_id); | |

/// ``` | |

/// | |

/// # Errors | |

/// | |

/// If any of the constraints that are required for the graph storage to be valid are violated. | |

/// This may include things like parallel edges or self loops depending on implementation. | |

/// | |

/// Refer to the documentation of the underlying storage for more information. | |

pub fn try_insert_node_with( | |

&mut self, | |

weight: impl FnOnce(NodeId) -> S::NodeWeight, | |

) -> Result<NodeMut<S>, Error> { | |

let id = self.storage.next_node_id(); | |

let weight = weight(id); | |

self.storage.insert_node(id, weight).change_context(Error) | |

} | |

/// Insert a node, where the weight is dependent on the id. | |

/// | |

/// This is similar to [`Self::insert_node`], but instead of providing the weight as a | |

/// parameter, it can take into account the future id. | |

/// | |

/// This is the infallible version of [`Self::try_insert_node_with`], which will panic instead. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::{DiDinoGraph, NodeId}; | |

/// | |

/// struct Node { | |

/// id: NodeId, | |

/// } | |

/// | |

/// // we need to explicitly state the type of the edge weights, as we do insert any edges and | |

/// // therefore cannot infer them. | |

/// let mut graph = DiDinoGraph::<_, ()>::new(); | |

/// let node_id = *graph.insert_node_with(|id| Node { id: *id }).id(); | |

/// | |

/// let node = graph.node(&node_id).expect("node must exist"); | |

/// | |

/// assert_eq!(node.weight().id, node_id); | |

/// ``` | |

/// | |

/// # Panics | |

/// | |

/// If any of the constraints that are required for the graph storage to be valid are violated. | |

/// This may include things like parallel edges or self loops depending on implementation. | |

/// | |

/// Refer to the documentation of the underlying storage for more information. | |

pub fn insert_node_with(&mut self, weight: impl FnOnce(NodeId) -> S::NodeWeight) -> NodeMut<S> { | |

self.try_insert_node_with(weight) | |

.expect("Constraint violation. Try using `try_insert_node_with` instead.") | |

} | |

} | |

impl<S> Graph<S> | |

where | |

S: GraphStorage, | |

{ | |

/// Try to insert an edge with the given attributes. | |

/// | |

/// This is the fallible version of [`Self::insert_edge`]. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::DiDinoGraph; | |

/// | |

/// let mut graph = DiDinoGraph::new(); | |

/// let a = *graph.insert_node(()).id(); | |

/// let b = *graph.insert_node(()).id(); | |

/// | |

/// let edge = graph | |

/// .try_insert_edge((), &a, &b) | |

/// .expect("unable to insert edge"); | |

/// ``` | |

/// | |

/// # Errors | |

/// | |

/// If any of the constraints that are required for the graph storage to be valid are violated. | |

/// This may include things like parallel edges or self loops depending on implementation. | |

/// | |

/// Refer to the documentation of the underlying storage for more information. | |

pub fn try_insert_edge( | |

&mut self, | |

weight: S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> Result<EdgeMut<S>, Error> { | |

let id = self.storage.next_edge_id(); | |

self.storage | |

.insert_edge(id, weight, source, target) | |

.change_context(Error) | |

} | |

/// Insert an edge with the given attributes. | |

/// | |

/// Depending on the storage type, or if your code is generic over the storage type, you might | |

/// want to consider using [`Self::try_insert_edge`] instead. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::DiDinoGraph; | |

/// | |

/// let mut graph = DiDinoGraph::new(); | |

/// let a = *graph.insert_node(()).id(); | |

/// let b = *graph.insert_node(()).id(); | |

/// | |

/// let edge = graph.insert_edge((), &a, &b); | |

/// ``` | |

/// | |

/// # Rationale | |

/// | |

/// For the rationale behind splitting this into [`Self::insert_edge`] and | |

/// [`Self::try_insert_edge`], see the documentation of [`Self::insert_node`]. | |

/// | |

/// # Panics | |

/// | |

/// If any of the constraints that are required for the graph storage to be valid are violated. | |

/// This may include things like parallel edges or self loops depending on implementation. | |

pub fn insert_edge( | |

&mut self, | |

weight: S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> EdgeMut<S> { | |

self.try_insert_edge(weight, source, target) | |

.expect("Constraint violation. Try using `try_insert_edge` instead.") | |

} | |

} | |

impl<S> Graph<S> | |

where | |

S: GraphStorage, | |

{ | |

/// Insert an edge, where the weight is dependent on the id. | |

/// | |

/// This is similar to [`Self::try_insert_edge`], but instead of providing the weight as a | |

/// parameter, it will take into account the future id, by calling the given closure with the | |

/// id. | |

/// | |

/// This is the fallible version of [`Self::insert_edge_with`]. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::{DiDinoGraph, EdgeId}; | |

/// | |

/// struct Edge { | |

/// id: EdgeId, | |

/// } | |

/// | |

/// let mut graph = DiDinoGraph::new(); | |

/// let a = *graph.insert_node(()).id(); | |

/// let b = *graph.insert_node(()).id(); | |

/// | |

/// let edge_id = *graph | |

/// .try_insert_edge_with(|id| Edge { id: *id }, &a, &b) | |

/// .expect("unable to insert edge") | |

/// .id(); | |

/// | |

/// let edge = graph.edge(&edge_id).expect("edge must exist"); | |

/// | |

/// assert_eq!(edge.weight().id, edge_id); | |

/// ``` | |

/// | |

/// # Errors | |

/// | |

/// The same errors as [`Self::try_insert_edge`] may occur. | |

pub fn try_insert_edge_with( | |

&mut self, | |

weight: impl FnOnce(EdgeId) -> S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> Result<EdgeMut<S>, Error> { | |

let id = self.storage.next_edge_id(); | |

let weight = weight(id); | |

self.storage | |

.insert_edge(id, weight, source, target) | |

.change_context(Error) | |

} | |

/// Insert an edge, where the weight is dependent on the id. | |

/// | |

/// This is similar to [`Self::insert_edge`], but instead of providing the weight as a | |

/// parameter, it will take into account the future id, by calling the given closure with the | |

/// id. | |

/// | |

/// This is the infallible version of [`Self::try_insert_edge_with`], which will panic instead. | |

/// | |

/// # Example | |

/// | |

/// ``` | |

/// use petgraph_dino::{DiDinoGraph, EdgeId}; | |

/// | |

/// struct Edge { | |

/// id: EdgeId, | |

/// } | |

/// | |

/// let mut graph = DiDinoGraph::new(); | |

/// let a = *graph.insert_node(()).id(); | |

/// let b = *graph.insert_node(()).id(); | |

/// | |

/// let edge_id = *graph.insert_edge_with(|id| Edge { id: *id }, &a, &b).id(); | |

/// | |

/// let edge = graph.edge(&edge_id).expect("edge must exist"); | |

/// | |

/// assert_eq!(edge.weight().id, edge_id); | |

/// ``` | |

/// | |

/// # Panics | |

/// | |

/// The same panics as [`Self::insert_edge`] may occur. | |

pub fn insert_edge_with( | |

&mut self, | |

weight: impl FnOnce(EdgeId) -> S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> EdgeMut<S> { | |

self.try_insert_edge_with(weight, source, target) | |

.expect("Constraint violation. Try using `try_insert_edge_with` instead.") | |

} | |

} | |

#[cfg(feature = "alloc")] | |

impl<S> Graph<S> | |

where | |

S: GraphStorage, | |

S::EdgeWeight: Clone, | |

{ | |

/// Insert an edge, or update the weight of an existing edge, if it exists. | |

/// | |

/// If multiple edges exist between the given nodes, all of them will be updated with the given | |

/// | |

/// Edges are treated as undirected, so the order of the nodes does not matter. | |

/// | |

/// Unlike [`Self::try_upsert_edge`], this will not return the edge, and instead return a list | |

/// containing all affected edge identifiers. | |

/// | |

/// This is the fallible version of [`Self::upsert_edge`]. | |

// TODO: Example | |

/// | |

/// # Errors | |

/// | |

/// The same errors as [`Self::try_insert_edge`] may occur. | |

pub fn try_upsert_edge( | |

&mut self, | |

weight: S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> Result<Vec<EdgeId>, Error> { | |

let mut affected = vec![]; | |

for mut edge in self.storage.edges_between_mut(source, target) { | |

*edge.weight_mut() = weight.clone(); | |

affected.push(edge.id()); | |

} | |

if !affected.is_empty() { | |

return Ok(affected); | |

} | |

self.try_insert_edge(weight, source, target) | |

.map(|edge| vec![edge.id()]) | |

} | |

/// Insert an edge, or update the weight of an existing edge, if it exists. | |

/// | |

/// If multiple edges exist between the given nodes, all of them will be updated with the given | |

/// value. | |

/// | |

/// This is the infallible version of [`Self::try_upsert_edge`], which will panic instead. | |

/// | |

/// # Panics | |

/// | |

/// The same panics as [`Self::try_upsert_edge`] may occur, as well as the ones from | |

/// [`Self::insert_edge`]. | |

pub fn upsert_edge( | |

&mut self, | |

weight: S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> Vec<EdgeId> { | |

self.try_upsert_edge(weight, source, target) | |

.expect("Constraint violation. Try using `try_upsert_edge` instead.") | |

} | |

/// Insert an edge, or update the weight of an existing edge, if it exists. | |

/// | |

/// If multiple edges exist between the given nodes, all of them will invoke the given closure | |

/// with the edge. | |

/// | |

/// Unlike [`Self::try_upsert_edge_with`], this will not return the edge, and instead return a | |

/// list containing all affected edge identifiers. | |

/// | |

/// This is the fallible version of [`Self::upsert_edge_with`]. | |

/// | |

/// # Errors | |

/// | |

/// The same errors as [`Self::try_insert_edge`] may occur. | |

pub fn try_upsert_edge_with( | |

&mut self, | |

mut on_update: impl FnMut(&mut EdgeMut<S>) -> S::EdgeWeight, | |

on_insert: impl FnOnce(EdgeId) -> S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> Result<Vec<EdgeId>, Error> { | |

let mut affected = vec![]; | |

for mut edge in self.storage.edges_between_mut(source, target) { | |

*edge.weight_mut() = on_update(&mut edge); | |

affected.push(edge.id()); | |

} | |

if !affected.is_empty() { | |

return Ok(affected); | |

} | |

self.try_insert_edge_with(on_insert, source, target) | |

.map(|edge| vec![edge.id()]) | |

} | |

/// Insert an edge, or update the weight of an existing edge, if it exists. | |

/// | |

/// If multiple edges exist between the given nodes, all of them will invoke the given closure | |

/// with the edge. | |

/// | |

/// This is the infallible version of [`Self::try_upsert_edge_with`], which will panic instead. | |

/// | |

/// # Panics | |

/// | |

/// The same panics as [`Self::try_upsert_edge_with`] may occur, as well as the ones from | |

/// [`Self::insert_edge_with`]. | |

pub fn upsert_edge_with( | |

&mut self, | |

on_update: impl FnMut(&mut EdgeMut<S>) -> S::EdgeWeight, | |

on_insert: impl FnOnce(EdgeId) -> S::EdgeWeight, | |

source: NodeId, | |

target: NodeId, | |

) -> Vec<EdgeId> { | |

self.try_upsert_edge_with(on_update, on_insert, source, target) | |

.expect("Constraint violation. Try using `try_upsert_edge_with` instead.") | |

} | |

} |