Handling closures and FnMut
⚓ Rust 📅 2025-09-19 👤 surdeus 👁️ 7Hi there,
I thought that it'd be neat if one could combine some functionalities from petgraph with the flexibility of the API in the pathfinding crate.
That is, I am trying to create a Dijkstra struct (to run and store the results of the Dijkstra algorithm), but provide the functionality to run the algorithm using closures or graphs from petgraph as desired. That is, have the flexibility to only provide closures when creating a new dijkstra struct (similar to the Pathfinding APIs) or to provide an entire petgraph graph.
However, I am having problems with getting the types to be "instantiated" correctly, in particular working with the FnMut traits and closures.
This is the basic and easy part of the code / struct:
pub struct Dijkstra<N, C, FN, IN, FG>
where
N: Eq + Hash,
C: Measure + Copy,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = (N, C)>,
FG: FnMut(&N) -> bool,
{
start: N,
neighbors: FN,
goal: FG,
pub distances: HashMap<N, C>,
}
impl<N, C, FN, IN, FG> Dijkstra<N, C, FN, IN, FG>
where
N: Eq + Hash + Copy,
C: Measure + Copy,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = (N, C)>,
FG: FnMut(&N) -> bool,
{
pub fn new_from_closures(
start: N,
neighbors: FN,
goal: FG,
) -> Self {
Self {
start,
neighbors,
goal,
distances: HashMap::new(),
}
}
}
However, now I would want to add another associated function, i.e. a method / factory, to construct a Dijkstra instance from a petgraph graph. That is, something like the following:
pub fn new_from_graph<G, FC, C>(
graph: G,
start: G::NodeId,
goal: G::NodeId,
mut edge_cost: FC,
) -> Dijkstra<
G::NodeId,
C,
impl FnMut(&G::NodeId) -> impl IntoIterator<Item = (G::NodeId, C)>,
impl IntoIterator<Item = (G::NodeId, C)>,
impl FnMut(&G::NodeId) -> bool,
>
where
G: IntoEdges + Visitable,
G::NodeId: Eq + Hash,
FC: FnMut(G::EdgeRef) -> C,
C: Measure + Copy,
{
let neighbors = move |node: &G::NodeId| {
graph
.edges(*node)
.map(|edge: G::EdgeRef| (edge.target(), edge_cost(edge)))
};
let goal_fn = move |node: &G::NodeId| *node == goal;
Dijkstra::new_from_closures(start, neighbors, goal_fn)
}
Technically, the above is not a method, because I wanted to try implementing it as a function first as that seemed easier with all the generics and trait bounds.
However, this fails since impl Trait is not allowed in the return type of Fn trait bounds. More specifically the compiler error message is the following:
error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds
--> src/algo/dijkstra.rs:106:31
|
106 | impl FnMut(&G::NodeId) -> impl IntoIterator<Item = (G::NodeId, C)>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
= note: see issue #99697 <https://github.com/rust-lang/rust/issues/99697> for more information
= help: add `#![feature(impl_trait_in_fn_trait_return)]` to the crate attributes to enable
= note: this compiler was built on 2025-07-26; consider upgrading it if it is out of date
How could I address this without using the feature flag? Could I somehow specify the return type of the FnMut for the instances created from graphs? That is, replace the impl IntoIterator<_> with a specific type and fix the issue that way?
Thanks in advance
1 post - 1 participant
🏷️ Rust_feed