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

fix: be explicit on used generic types and lifetimes #611

Closed
wants to merge 5 commits into from
Closed
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
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 <sam@rfc1149.net>"]
categories = ["algorithms"]
readme = "README.md"
edition = "2021"
rust-version = "1.77.2"
rust-version = "1.82.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
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 @@ -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
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 @@ -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/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
2 changes: 1 addition & 1 deletion src/directed/idastar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ where
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),
Path::Minimum(m) if min.is_none_or(|n| n >= m) => min = Some(m),
_ => (),
}
path.pop();
Expand Down
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 @@ -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.82.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 @@ -531,7 +531,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 @@ -597,7 +597,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 @@ -628,14 +628,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 @@ -232,7 +232,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
40 changes: 20 additions & 20 deletions src/undirected/kruskal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,6 @@ fn find(parents: &mut [usize], mut node: usize) -> usize {
node
}

#[cfg(test)]
mod tests {
use super::find;

#[test]
fn path_halving() {
let mut parents = vec![0, 0, 1, 2, 3, 4, 5, 6];
assert_eq!(find(&mut parents, 7), 0);
assert_eq!(parents, vec![0, 0, 1, 1, 3, 3, 5, 5]);
assert_eq!(find(&mut parents, 7), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 5, 3]);
assert_eq!(find(&mut parents, 7), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 5, 0]);
assert_eq!(find(&mut parents, 6), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 3, 0]);
assert_eq!(find(&mut parents, 6), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 0, 0]);
}
}

fn union(parents: &mut [usize], ranks: &mut [usize], mut a: usize, mut b: usize) {
if ranks[a] < ranks[b] {
mem::swap(&mut a, &mut b);
Expand Down Expand Up @@ -98,3 +78,23 @@ where
))
})
}

#[cfg(test)]
mod tests {
use super::find;

#[test]
fn path_halving() {
let mut parents = vec![0, 0, 1, 2, 3, 4, 5, 6];
assert_eq!(find(&mut parents, 7), 0);
assert_eq!(parents, vec![0, 0, 1, 1, 3, 3, 5, 5]);
assert_eq!(find(&mut parents, 7), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 5, 3]);
assert_eq!(find(&mut parents, 7), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 5, 0]);
assert_eq!(find(&mut parents, 6), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 3, 0]);
assert_eq!(find(&mut parents, 6), 0);
assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 0, 0]);
}
}
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
2 changes: 1 addition & 1 deletion tests/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ fn into_iter_is_fused() {
}

#[test]
#[allow(deprecated)]
#[expect(deprecated)]
fn indices() {
let m = matrix![[0, 1, 2], [2, 1, 0]];
assert_eq!(
Expand Down
4 changes: 2 additions & 2 deletions tests/pathfinding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ mod ex1 {
use lazy_static::lazy_static;
use pathfinding::prelude::*;

#[allow(clippy::trivially_copy_pass_by_ref)]
fn successors(node: &u8) -> impl Iterator<Item = (u8, usize)> {
#[expect(clippy::trivially_copy_pass_by_ref)]
fn successors(node: &u8) -> impl Iterator<Item = (u8, usize)> + use<> {
lazy_static! {
static ref SUCCESSORS: Vec<Vec<(u8, usize)>> = vec![
vec![(1, 7), (2, 7), (3, 6)],
Expand Down
2 changes: 1 addition & 1 deletion tests/strongly_connected_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::collections::hash_map::HashMap;
// Tests in this file use the example at
// https://en.wikipedia.org/wiki/Strongly_connected_component#/media/File:Graph_Condensation.svg

#[allow(clippy::trivially_copy_pass_by_ref)]
#[expect(clippy::trivially_copy_pass_by_ref)]
fn successors(n: &usize) -> Vec<usize> {
match *n {
0 => vec![2],
Expand Down
2 changes: 1 addition & 1 deletion tests/topological_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn complexity() {
// Wrapper around topological_sort_into_groups that sorts each group (since
// topological_sort_into_groups makes no guarantees about node order within
// each group).
#[allow(clippy::type_complexity)]
#[expect(clippy::type_complexity)]
fn tsig(succs: &[&[usize]]) -> Result<Vec<Vec<usize>>, (Vec<Vec<usize>>, Vec<usize>)> {
let nodes: Vec<usize> = (0..succs.len()).collect();
match topological_sort_into_groups(&nodes, |&n| succs[n].iter().copied()) {
Expand Down
Loading