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.83 #636

Merged
merged 7 commits into from
Mar 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ authors = ["Samuel Tardieu <[email protected]>"]
categories = ["algorithms"]
readme = "README.md"
edition = "2021"
rust-version = "1.80.0"
rust-version = "1.83.0"

[package.metadata.release]
sign-commit = true
Expand Down Expand Up @@ -46,7 +46,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
4 changes: 2 additions & 2 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 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
4 changes: 2 additions & 2 deletions benches/movingai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ 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 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 @@ -92,7 +92,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
4 changes: 2 additions & 2 deletions src/directed/dijkstra.rs
Original file line number Diff line number Diff line change
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 @@ -283,7 +283,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/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
2 changes: 1 addition & 1 deletion src/grid.rs
Original file line number Diff line number Diff line change
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/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,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.80.0.
//! The minimum supported Rust version (MSRV) is Rust 1.83.0.
//!
//! [A*]: https://en.wikipedia.org/wiki/A*_search_algorithm
//! [BFS]: https://en.wikipedia.org/wiki/Breadth-first_search
Expand Down
8 changes: 4 additions & 4 deletions src/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ impl<C> Matrix<C> {
&self,
(r, c): (usize, usize),
diagonals: bool,
) -> impl Iterator<Item = (usize, usize)> {
) -> impl Iterator<Item = (usize, usize)> + use<C> {
let (row_range, col_range) = if r < self.rows && c < self.columns {
(
r.saturating_sub(1)..(self.rows).min(r + 2),
Expand Down Expand Up @@ -596,7 +596,7 @@ impl<C> Matrix<C> {
&self,
start: (usize, usize),
direction: (isize, isize),
) -> impl Iterator<Item = (usize, usize)> {
) -> impl Iterator<Item = (usize, usize)> + use<C> {
in_direction(start, direction, (self.rows, self.columns))
}

Expand Down Expand Up @@ -627,14 +627,14 @@ impl<C> Matrix<C> {
since = "4.1.0",
remove = "> 4.x"
)]
pub fn indices(&self) -> impl Iterator<Item = (usize, usize)> {
pub fn indices(&self) -> impl Iterator<Item = (usize, usize)> + use<C> {
self.keys()
}

/// Return an iterator on the Matrix indices, first row first. The values are
/// computed when this method is called and will not change even if new rows are
/// added before the iterator is consumed.
pub fn keys(&self) -> impl Iterator<Item = (usize, usize)> {
pub fn keys(&self) -> impl Iterator<Item = (usize, usize)> + use<C> {
let columns = self.columns;
(0..self.rows).flat_map(move |r| (0..columns).map(move |c| (r, c)))
}
Expand Down
2 changes: 1 addition & 1 deletion src/undirected/connected_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ where
/// This function returns a map between every vertex and the index of
/// the set it belongs to in the `components` list.
#[must_use]
#[allow(clippy::implicit_hasher)]
#[expect(clippy::implicit_hasher)]
pub fn component_index<N>(components: &[HashSet<N>]) -> HashMap<N, usize>
where
N: Clone + Hash + Eq,
Expand Down
4 changes: 2 additions & 2 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ where
/// assert_eq!(move_in_direction((1, 1), (-1, -2), board), None);
/// ```
#[must_use]
#[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
#[expect(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
pub fn move_in_direction(
start: (usize, usize),
direction: (isize, isize),
Expand Down Expand Up @@ -90,7 +90,7 @@ pub fn in_direction(
/// assert_eq!(constrain(-30, 7), 5);
/// ```
#[must_use]
#[allow(clippy::cast_sign_loss)]
#[expect(clippy::cast_sign_loss)]
pub const fn constrain(value: isize, upper: usize) -> usize {
if value > 0 {
value as usize % upper
Expand Down
4 changes: 2 additions & 2 deletions tests/codejam-2017-a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::io::{self, Cursor};
use std::num::ParseIntError;

#[derive(Debug)]
#[allow(dead_code)]
#[expect(dead_code)]
enum Error {
Io(io::Error),
Parse(ParseIntError),
Expand Down Expand Up @@ -99,7 +99,7 @@ fn test<EK: EdmondsKarp<i32>>(n: usize, file: &mut dyn BufRead) -> Result<String
loop {
let (_, n, _) = ek.augment();
debug_assert!(n >= 0);
#[allow(clippy::cast_sign_loss)]
#[expect(clippy::cast_sign_loss)]
let n = n as usize;
if n > max {
max = n;
Expand Down
2 changes: 1 addition & 1 deletion tests/edmondskarp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn wikipedia_example_sparse() {
wikipedia_example::<SparseCapacity<_>>();
}

#[allow(clippy::cast_possible_truncation)]
#[expect(clippy::cast_possible_truncation)]
fn wikipedia_progressive_example<EK: EdmondsKarp<i32>>() {
let successors = successors_wikipedia();
let size = successors.len();
Expand Down
2 changes: 1 addition & 1 deletion tests/gps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl Coords {
self.1.to_radians()
}

#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
#[expect(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn distance_in_meters(&self, other: &Self) -> u64 {
let x =
(other.lon_rad() - self.lon_rad()) * ((other.lat_rad() + self.lat_rad()) / 2.0).cos();
Expand Down
Loading
Loading