Skip to content

Commit 8e12c93

Browse files
committed
refactor: harden Rust release hygiene
- Promote missing documentation and dead code lints to deny-level checks. - Forbid unsafe code explicitly across Rust modules and benchmark targets. - Document the LU/LDLT empty-matrix convention for D=0. - Move exact benchmark input generation into typed helpers and consolidate exact benchmark operation dispatch.
1 parent 57809b2 commit 8e12c93

20 files changed

Lines changed: 404 additions & 269 deletions

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ features = [ "exact" ]
6262

6363
[lints.rust]
6464
unsafe_code = "forbid"
65-
missing_docs = "warn"
66-
dead_code = "warn"
65+
missing_docs = "deny"
66+
dead_code = "deny"
6767

6868
[lints.rustdoc]
6969
broken_intra_doc_links = "deny"

benches/common/exact.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#![forbid(unsafe_code)]
2+
3+
//! Shared helpers for exact-arithmetic benchmark input generation and tests.
4+
5+
use std::fmt::{self, Display};
6+
use std::num::NonZeroU64;
7+
8+
/// Configuration errors for exact-arithmetic benchmark input generation.
9+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10+
pub enum ExactBenchConfigError {
11+
/// The random input corpus length was zero.
12+
EmptyCorpus,
13+
/// An ordered inclusive range produced an invalid non-zero sampling width.
14+
InvalidRangeWidth {
15+
/// Inclusive lower bound.
16+
min: i16,
17+
/// Inclusive upper bound.
18+
max: i16,
19+
/// Computed inclusive width before conversion to the cached sampling width.
20+
width: i32,
21+
},
22+
/// The inclusive lower bound was greater than the inclusive upper bound.
23+
UnorderedRange {
24+
/// Inclusive lower bound.
25+
min: i16,
26+
/// Inclusive upper bound.
27+
max: i16,
28+
},
29+
}
30+
31+
impl Display for ExactBenchConfigError {
32+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33+
match *self {
34+
Self::EmptyCorpus => f.write_str("random input corpus must be nonempty"),
35+
Self::InvalidRangeWidth { min, max, width } => {
36+
write!(
37+
f,
38+
"random integer range {min}..={max} produced invalid sampling width {width}"
39+
)
40+
}
41+
Self::UnorderedRange { min, max } => {
42+
write!(f, "random integer range must be ordered: {min}..={max}")
43+
}
44+
}
45+
}
46+
}
47+
48+
impl std::error::Error for ExactBenchConfigError {}
49+
50+
/// Inclusive integer range used by the fixed-seed exact benchmark generator.
51+
#[derive(Clone, Copy)]
52+
#[must_use]
53+
pub struct I16Range {
54+
min: i16,
55+
width: NonZeroU64,
56+
}
57+
58+
impl I16Range {
59+
/// Validate an inclusive `i16` range and cache its sampling width.
60+
///
61+
/// # Errors
62+
///
63+
/// Returns [`ExactBenchConfigError::UnorderedRange`] when `min > max`, or
64+
/// [`ExactBenchConfigError::InvalidRangeWidth`] if the inclusive range width
65+
/// cannot be represented as a non-zero sampling width.
66+
pub fn new(min: i16, max: i16) -> Result<Self, ExactBenchConfigError> {
67+
if min > max {
68+
return Err(ExactBenchConfigError::UnorderedRange { min, max });
69+
}
70+
71+
let raw_width = i32::from(max) - i32::from(min) + 1;
72+
let width =
73+
u64::try_from(raw_width).map_err(|_| ExactBenchConfigError::InvalidRangeWidth {
74+
min,
75+
max,
76+
width: raw_width,
77+
})?;
78+
let width = NonZeroU64::new(width).ok_or(ExactBenchConfigError::InvalidRangeWidth {
79+
min,
80+
max,
81+
width: raw_width,
82+
})?;
83+
Ok(Self { min, width })
84+
}
85+
}
86+
87+
/// Deterministic `SplitMix64` generator for reproducible benchmark corpora.
88+
#[must_use]
89+
pub struct SplitMix64 {
90+
state: u64,
91+
}
92+
93+
impl SplitMix64 {
94+
/// Initialize the generator with a fixed state.
95+
pub const fn new(state: u64) -> Self {
96+
Self { state }
97+
}
98+
99+
/// Advance the generator and return the next 64 random bits.
100+
const fn next_u64(&mut self) -> u64 {
101+
self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
102+
let mut z = self.state;
103+
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
104+
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
105+
z ^ (z >> 31)
106+
}
107+
108+
#[allow(clippy::cast_possible_truncation)]
109+
/// Draw a random `i16` inside a validated inclusive range.
110+
#[must_use]
111+
pub fn next_i16(&mut self, range: I16Range) -> i16 {
112+
let offset = (self.next_u64() % range.width.get()) as i32;
113+
let value = i32::from(range.min) + offset;
114+
value as i16
115+
}
116+
}

benches/common/vs_linalg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![forbid(unsafe_code)]
2+
13
//! Shared helpers for the `vs_linalg` benchmark and its smoke tests.
24
35
use faer::linalg::solvers::{Ldlt as FaerLdlt, PartialPivLu};

0 commit comments

Comments
 (0)