Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to be merged with MSRV 1.85 #628

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,4 @@ jobs:
rustup install --profile default nightly
rustup default nightly
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-targets
- run: cargo clippy --all-targets -- -D warnings
8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ version = "4.13.0"
authors = ["Samuel Tardieu <[email protected]>"]
categories = ["algorithms"]
readme = "README.md"
edition = "2021"
rust-version = "1.77.2"
edition = "2024"
rust-version = "1.85.0"

[package.metadata.release]
sign-commit = true
Expand Down Expand Up @@ -47,7 +47,9 @@ version_check = "0.9.5"
[lints.clippy]
module_name_repetitions = { level = "allow", priority = 1 }
too_long_first_doc_paragraph = { level = "allow", priority = 1 } # Temporary
pedantic = { level = "deny", priority = 0 }
pedantic = "deny"
# Do not activate until Clippy issue #13356 is fixed
#allow_attributes = "deny"

[[bench]]
name = "algos"
Expand Down
2 changes: 1 addition & 1 deletion benches/algos-fill.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// This version uses a filler in the Pt structure to increase
// the cost of cloning a node.

use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
use codspeed_criterion_compat::{Criterion, criterion_group, criterion_main};
use pathfinding::prelude::{astar, bfs, dfs, dijkstra, fringe, idastar, iddfs};

#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
Expand Down
2 changes: 1 addition & 1 deletion benches/algos.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
use codspeed_criterion_compat::{Criterion, criterion_group, criterion_main};
use itertools::Itertools;
use pathfinding::prelude::{
astar, bfs, dfs, dijkstra, fringe, idastar, iddfs, separate_components,
Expand Down
4 changes: 2 additions & 2 deletions benches/edmondskarp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
use codspeed_criterion_compat::{Criterion, criterion_group, criterion_main};
use pathfinding::directed::edmonds_karp::{
edmonds_karp, DenseCapacity, EKFlows, EdmondsKarp, SparseCapacity,
DenseCapacity, EKFlows, EdmondsKarp, SparseCapacity, edmonds_karp,
};
use std::collections::HashMap;

Expand Down
4 changes: 2 additions & 2 deletions benches/kuhn_munkres.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use codspeed_criterion_compat::{criterion_group, criterion_main, BenchmarkId, Criterion};
use pathfinding::prelude::{kuhn_munkres, Matrix};
use codspeed_criterion_compat::{BenchmarkId, Criterion, criterion_group, criterion_main};
use pathfinding::prelude::{Matrix, kuhn_munkres};
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;

Expand Down
6 changes: 3 additions & 3 deletions benches/matrices.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
use codspeed_criterion_compat::{Criterion, criterion_group, criterion_main};
use pathfinding::matrix::Matrix;

#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn transpose_benchmark(c: &mut Criterion) {
// Generate a 100 x 100 square matrix with entries from 1 to 100^2
let data: Vec<i32> = (0..100 * 100).collect();
Expand All @@ -10,7 +10,7 @@ pub fn transpose_benchmark(c: &mut Criterion) {
c.bench_function("transpose", |b| b.iter(|| m.transpose()));
}

#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn transpose_non_square_benchmark(c: &mut Criterion) {
// Generate a 1000 x 10 square matrix with entries from 1 to 100^2
let data: Vec<i32> = (0..100 * 100).collect();
Expand Down
6 changes: 3 additions & 3 deletions benches/movingai.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Test with files from https://movingai.com/benchmarks/

use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
use codspeed_criterion_compat::{Criterion, criterion_group, criterion_main};
use movingai::parser::{parse_map_file, parse_scen_file};
use movingai::{Coords2D, Map2D};
use noisy_float::prelude::*;
use pathfinding::directed::astar::astar;
use std::path::Path;

#[allow(clippy::cast_precision_loss)]
#[expect(clippy::cast_precision_loss)]
fn distance(a: &Coords2D, b: &Coords2D) -> R64 {
r64((a.0 as f64 - b.0 as f64).hypot(a.1 as f64 - b.1 as f64))
}

#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn arena(c: &mut Criterion) {
c.bench_function("arena", |b| {
b.iter(|| {
Expand Down
4 changes: 2 additions & 2 deletions benches/separate_components.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
use codspeed_criterion_compat::{Criterion, criterion_group, criterion_main};
use itertools::Itertools;
use pathfinding::prelude::separate_components;
use rand::{prelude::SliceRandom, Rng, RngCore, SeedableRng};
use rand::{Rng, RngCore, SeedableRng, prelude::SliceRandom};
use rand_xorshift::XorShiftRng;
use std::collections::HashSet;

Expand Down
4 changes: 2 additions & 2 deletions examples/sliding-puzzle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const SIDE: u8 = 3;
const SIDE: u8 = 4;
const LIMIT: usize = (SIDE * SIDE) as usize;

#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Clone, Debug, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)] // expect doesn't work, clippy issue #13356
struct Game {
positions: [u8; LIMIT], // Correct position of piece at every index
hole_idx: u8, // Current index of the hole
Expand Down Expand Up @@ -95,7 +95,7 @@ impl Game {
// However, since the successors are the current board with the hole moved one
// position, we need to build a clone of the current board that will be reused in
// this iterator.
fn successors(&self) -> impl Iterator<Item = (Self, u8)> {
fn successors(&self) -> impl Iterator<Item = (Self, u8)> + use<> {
let game = self.clone();
SUCCESSORS[self.hole_idx as usize]
.iter()
Expand Down
4 changes: 2 additions & 2 deletions src/directed/astar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use crate::FxIndexMap;
/// |&p| p == GOAL);
/// assert_eq!(result.expect("no path found").1, 4);
/// ```
#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn astar<N, C, FN, IN, FH, FS>(
start: &N,
mut successors: FN,
Expand Down Expand Up @@ -169,7 +169,7 @@ where
///
/// Each path comprises both the start and an end node. Note that while every path shares the same
/// start node, different paths may have different end nodes.
#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn astar_bag<N, C, FN, IN, FH, FS>(
start: &N,
mut successors: FN,
Expand Down
6 changes: 3 additions & 3 deletions src/directed/dijkstra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ where
reached.map(|target| {
(
reverse_path(&parents, |&(p, _)| p, target),
parents.get_index(target).unwrap().1 .1,
parents.get_index(target).unwrap().1.1,
)
})
}
Expand Down Expand Up @@ -168,7 +168,7 @@ where
///
/// The [`build_path`] function can be used to build a full path from the starting point to one
/// of the reachable targets.
#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn dijkstra_partial<N, C, FN, IN, FS>(
start: &N,
mut successors: FN,
Expand Down Expand Up @@ -277,7 +277,7 @@ where
/// assert_eq!(vec![1], build_path(&1, &parents));
/// assert_eq!(vec![101], build_path(&101, &parents));
/// ```
#[allow(clippy::implicit_hasher)]
#[expect(clippy::implicit_hasher)]
pub fn build_path<N, C>(target: &N, parents: &HashMap<N, (N, C)>) -> Vec<N>
where
N: Eq + Hash + Clone,
Expand Down
2 changes: 1 addition & 1 deletion src/directed/edmonds_karp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! edges.

use super::bfs::bfs;
use crate::{matrix::Matrix, FxIndexSet};
use crate::{FxIndexSet, matrix::Matrix};
use num_traits::{Bounded, Signed, Zero};
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::hash::Hash;
Expand Down
2 changes: 1 addition & 1 deletion src/directed/fringe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use std::mem;
/// |&p| p == GOAL);
/// assert_eq!(result.expect("no path found").1, 4);
/// ```
#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn fringe<N, C, FN, IN, FH, FS>(
start: &N,
mut successors: FN,
Expand Down
70 changes: 31 additions & 39 deletions src/directed/idastar.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Compute a shortest path using the [IDA* search
//! algorithm](https://en.wikipedia.org/wiki/Iterative_deepening_A*).

use indexmap::IndexSet;
use num_traits::Zero;
use std::{hash::Hash, ops::ControlFlow};

/// Compute a shortest path using the [IDA* search
/// algorithm](https://en.wikipedia.org/wiki/Iterative_deepening_A*).
Expand Down Expand Up @@ -76,52 +78,43 @@ pub fn idastar<N, C, FN, IN, FH, FS>(
mut success: FS,
) -> Option<(Vec<N>, C)>
where
N: Eq + Clone,
N: Eq + Clone + Hash,
C: Zero + Ord + Copy,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = (N, C)>,
FH: FnMut(&N) -> C,
FS: FnMut(&N) -> bool,
{
let mut bound = heuristic(start);
let mut path = vec![start.clone()];
loop {
match search(
&mut path,
Zero::zero(),
bound,
&mut successors,
&mut heuristic,
&mut success,
) {
Path::Found(path, cost) => return Some((path, cost)),
Path::Minimum(min) => {
if bound == min {
return None;
}
bound = min;
}
Path::Impossible => return None,
}
}
}
let mut path = IndexSet::from([start.clone()]);

enum Path<N, C> {
Found(Vec<N>, C),
Minimum(C),
Impossible,
std::iter::repeat(())
.try_fold(heuristic(start), |bound, ()| {
search(
&mut path,
Zero::zero(),
bound,
&mut successors,
&mut heuristic,
&mut success,
)
.map_break(Some)?
// .filter(|min| *min > bound)
.map_or(ControlFlow::Break(None), ControlFlow::Continue)
})
.break_value()
.unwrap_or_default() // To avoid a missing panics section, as this always break
}

fn search<N, C, FN, IN, FH, FS>(
path: &mut Vec<N>,
path: &mut IndexSet<N>,
cost: C,
bound: C,
successors: &mut FN,
heuristic: &mut FH,
success: &mut FS,
) -> Path<N, C>
) -> ControlFlow<(Vec<N>, C), Option<C>>
where
N: Eq + Clone,
N: Eq + Clone + Hash,
C: Zero + Ord + Copy,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = (N, C)>,
Expand All @@ -132,12 +125,12 @@ where
let start = &path[path.len() - 1];
let f = cost + heuristic(start);
if f > bound {
return Path::Minimum(f);
return ControlFlow::Continue(Some(f));
}
if success(start) {
return Path::Found(path.clone(), f);
return ControlFlow::Break((path.iter().cloned().collect(), f));
}
let mut neighbs = successors(start)
let mut neighbs: Vec<(N, C, C)> = successors(start)
.into_iter()
.filter_map(|(n, c)| {
(!path.contains(&n)).then(|| {
Expand All @@ -151,13 +144,12 @@ where
};
let mut min = None;
for (node, extra, _) in neighbs {
path.push(node);
match search(path, cost + extra, bound, successors, heuristic, success) {
found_path @ Path::Found(_, _) => return found_path,
Path::Minimum(m) if !min.is_some_and(|n| n < m) => min = Some(m),
let (idx, _) = path.insert_full(node);
match search(path, cost + extra, bound, successors, heuristic, success)? {
Some(m) if min.is_none_or(|n| n >= m) => min = Some(m),
_ => (),
}
path.pop();
path.swap_remove_index(idx);
}
min.map_or(Path::Impossible, Path::Minimum)
ControlFlow::Continue(min)
}
2 changes: 1 addition & 1 deletion src/directed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub mod strongly_connected_components;
pub mod topological_sort;
pub mod yen;

#[allow(clippy::needless_collect)]
#[expect(clippy::needless_collect)]
fn reverse_path<N, V, F>(parents: &FxIndexMap<N, V>, mut parent: F, start: usize) -> Vec<N>
where
N: Eq + Hash + Clone,
Expand Down
2 changes: 1 addition & 1 deletion src/directed/strongly_connected_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ where
///
/// The function returns the strongly connected component containing the node,
/// which is guaranteed to contain at least `node`.
#[allow(clippy::missing_panics_doc)]
#[expect(clippy::missing_panics_doc)]
pub fn strongly_connected_component<N, FN, IN>(node: &N, successors: FN) -> Vec<N>
where
N: Clone + Hash + Eq,
Expand Down
4 changes: 2 additions & 2 deletions src/directed/topological_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ where
/// In this case, the strongly connected set(s) can then be found using the
/// [`strongly_connected_components`](super::strongly_connected_components::strongly_connected_components)
/// function on the list of remaining nodes.
#[allow(clippy::type_complexity)]
#[allow(clippy::missing_panics_doc)]
#[expect(clippy::type_complexity)]
#[expect(clippy::missing_panics_doc)]
pub fn topological_sort_into_groups<N, FN, IN>(
nodes: &[N],
mut successors: FN,
Expand Down
4 changes: 2 additions & 2 deletions src/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
//! without diagonal links.

use super::matrix::Matrix;
use crate::FxIndexSet;
use crate::directed::bfs::bfs_reach;
use crate::directed::dfs::dfs_reach;
use crate::utils::constrain;
use crate::FxIndexSet;
use num_traits::ToPrimitive;
use std::collections::BTreeSet;
use std::fmt;
Expand Down Expand Up @@ -214,7 +214,7 @@ impl Grid {

/// Return an iterator over the border vertices. The grid must not have
/// a zero width or height.
fn borders(&self) -> impl Iterator<Item = (usize, usize)> {
fn borders(&self) -> impl Iterator<Item = (usize, usize)> + use<> {
let width = self.width;
let height = self.height;
(0..width)
Expand Down
2 changes: 1 addition & 1 deletion src/kuhn_munkres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! [Kuhn-Munkres algorithm](https://en.wikipedia.org/wiki/Hungarian_algorithm)
//! (also known as Hungarian algorithm).

use crate::{matrix::Matrix, FxIndexSet};
use crate::{FxIndexSet, matrix::Matrix};
use num_traits::{Bounded, Signed, Zero};
use std::iter::Sum;

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
//! in this context, you can wrap them into compliant types using the
//! [ordered-float](https://crates.io/crates/ordered-float) crate.
//!
//! The minimum supported Rust version (MSRV) is Rust 1.77.2.
//! The minimum supported Rust version (MSRV) is Rust 1.85.0.
//!
//! [A*]: https://en.wikipedia.org/wiki/A*_search_algorithm
//! [BFS]: https://en.wikipedia.org/wiki/Breadth-first_search
Expand Down
Loading
Loading