style: crank clippy to pedantic+nursery and fix all lints
Enable the full clippy all + pedantic + nursery groups as workspace warnings, with a small documented allow-list for the pedantic/nursery lints this project intentionally does not follow (rustdoc-style requirements, deliberate numeric casts in the protocol/UI layers, and a few noisy nursery lints). Also enable the rust unused_lifetimes and unsafe_op_in_unsafe_fn lints. Fixed every resulting warning (527 -> 0) mechanically per clippy's suggestions: inline format args, const fns, item ordering, let-else, redundant clones, map_or, cast_lossless, Eq derives, associated-fn conversions for methods that never used self, and removing unnecessary Result wrappers whose call sites could never propagate an error. No runtime behavior changed; cargo fmt applied. cargo clippy --workspace --all-targets: 0 warnings. All tests pass.
This commit is contained in:
@@ -32,12 +32,10 @@ pub fn init() {
|
||||
unsafe {
|
||||
LOG_LEVEL = match level.as_str() {
|
||||
"ERROR" => LogLevel::Error,
|
||||
"WARN" => LogLevel::Warn,
|
||||
"INFO" => LogLevel::Info,
|
||||
"DEBUG" => LogLevel::Debug,
|
||||
"DEBUG" | "VERBOSE" => LogLevel::Debug, // Map VERBOSE to DEBUG
|
||||
"TRACE" => LogLevel::Trace,
|
||||
"VERBOSE" => LogLevel::Debug, // Map VERBOSE to DEBUG
|
||||
_ => LogLevel::Warn, // Default to WARN
|
||||
_ => LogLevel::Warn, // "WARN" or default
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,10 +52,7 @@ pub fn init() {
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to open log file '{}': {}",
|
||||
log_file_path, e
|
||||
);
|
||||
eprintln!("Failed to open log file '{log_file_path}': {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +69,7 @@ enum LogSink {
|
||||
Stderr,
|
||||
}
|
||||
|
||||
fn choose_sink(buffering: bool, has_file: bool) -> LogSink {
|
||||
const fn choose_sink(buffering: bool, has_file: bool) -> LogSink {
|
||||
match (buffering, has_file) {
|
||||
// A configured file always takes the line directly and bypasses
|
||||
// buffering, so the flush step never re-writes it.
|
||||
@@ -86,7 +81,7 @@ fn choose_sink(buffering: bool, has_file: bool) -> LogSink {
|
||||
}
|
||||
|
||||
fn has_log_file() -> bool {
|
||||
LOG_FILE.lock().map(|f| f.is_some()).unwrap_or(false)
|
||||
LOG_FILE.lock().is_ok_and(|f| f.is_some())
|
||||
}
|
||||
|
||||
pub fn log(level: LogLevel, message: &str) {
|
||||
@@ -161,29 +156,11 @@ pub fn log(level: LogLevel, message: &str) {
|
||||
};
|
||||
|
||||
let formatted_message = format!(
|
||||
"[{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}] [{}] {}",
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
subsec_millis,
|
||||
level_str,
|
||||
message
|
||||
"[{year:04}-{month:02}-{day:02} {hours:02}:{minutes:02}:{seconds:02}.{subsec_millis:03}] [{level_str}] {message}"
|
||||
);
|
||||
|
||||
let formatted_message_plain = format!(
|
||||
"[{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}] [{}] {}",
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
subsec_millis,
|
||||
level_str_plain,
|
||||
message
|
||||
"[{year:04}-{month:02}-{day:02} {hours:02}:{minutes:02}:{seconds:02}.{subsec_millis:03}] [{level_str_plain}] {message}"
|
||||
);
|
||||
|
||||
match choose_sink(BUFFERING.load(Ordering::Relaxed), has_log_file())
|
||||
@@ -192,18 +169,17 @@ pub fn log(level: LogLevel, message: &str) {
|
||||
if let Ok(mut log_file) = LOG_FILE.lock()
|
||||
&& let Some(file) = log_file.as_mut()
|
||||
{
|
||||
let _ =
|
||||
writeln!(file, "{}", formatted_message_plain);
|
||||
let _ = writeln!(file, "{formatted_message_plain}");
|
||||
let _ = file.flush();
|
||||
}
|
||||
}
|
||||
LogSink::Buffer => {
|
||||
if let Ok(mut buffer) = BUFFER.lock() {
|
||||
buffer.push(formatted_message.clone());
|
||||
buffer.push(formatted_message);
|
||||
}
|
||||
}
|
||||
LogSink::Stderr => {
|
||||
eprintln!("{}", formatted_message);
|
||||
eprintln!("{formatted_message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,18 +204,18 @@ pub fn flush_buffered_logs() {
|
||||
for message in buffer.iter() {
|
||||
// Strip ANSI codes for file output
|
||||
let plain_message = strip_ansi_codes(message);
|
||||
let _ = writeln!(file, "{}", plain_message);
|
||||
let _ = writeln!(file, "{plain_message}");
|
||||
}
|
||||
let _ = file.flush();
|
||||
} else {
|
||||
for message in buffer.iter() {
|
||||
eprintln!("{}", message);
|
||||
eprintln!("{message}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If lock fails, fall back to stderr
|
||||
for message in buffer.iter() {
|
||||
eprintln!("{}", message);
|
||||
eprintln!("{message}");
|
||||
}
|
||||
}
|
||||
buffer.clear();
|
||||
@@ -270,26 +246,6 @@ fn strip_ansi_codes(s: &str) -> String {
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{LogSink, choose_sink};
|
||||
|
||||
#[test]
|
||||
fn a_configured_file_bypasses_buffering_so_lines_are_not_duplicated() {
|
||||
// With a file configured, the line goes straight to the file whether or
|
||||
// not buffering is on, so it is never also queued for a flush that would
|
||||
// write it a second time.
|
||||
assert_eq!(choose_sink(true, true), LogSink::File);
|
||||
assert_eq!(choose_sink(false, true), LogSink::File);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn without_a_file_buffering_routes_to_the_buffer_else_stderr() {
|
||||
assert_eq!(choose_sink(true, false), LogSink::Buffer);
|
||||
assert_eq!(choose_sink(false, false), LogSink::Stderr);
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => {
|
||||
@@ -324,3 +280,23 @@ macro_rules! trace {
|
||||
$crate::utils::logger::log($crate::utils::logger::LogLevel::Trace, &format!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{LogSink, choose_sink};
|
||||
|
||||
#[test]
|
||||
fn a_configured_file_bypasses_buffering_so_lines_are_not_duplicated() {
|
||||
// With a file configured, the line goes straight to the file whether or
|
||||
// not buffering is on, so it is never also queued for a flush that would
|
||||
// write it a second time.
|
||||
assert_eq!(choose_sink(true, true), LogSink::File);
|
||||
assert_eq!(choose_sink(false, true), LogSink::File);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn without_a_file_buffering_routes_to_the_buffer_else_stderr() {
|
||||
assert_eq!(choose_sink(true, false), LogSink::Buffer);
|
||||
assert_eq!(choose_sink(false, false), LogSink::Stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ use std::convert::TryInto;
|
||||
* K[i] = floor(2^32 * abs(sin(i+1)))
|
||||
*/
|
||||
fn table_construction_function(i: u32) -> u32 {
|
||||
let x: f64 = i as f64;
|
||||
let x: f64 = f64::from(i);
|
||||
let sin_eval = x.sin().abs();
|
||||
// note: 4294967296 == 2^32
|
||||
(4294967296.0 * sin_eval) as u32
|
||||
@@ -36,19 +36,19 @@ fn table_construction_function(i: u32) -> u32 {
|
||||
* algorithm, and they are performed a number of times to end
|
||||
* up with our final result.
|
||||
*/
|
||||
fn f(x: u32, y: u32, z: u32) -> u32 {
|
||||
const fn f(x: u32, y: u32, z: u32) -> u32 {
|
||||
x & y | !x & z
|
||||
}
|
||||
|
||||
fn g(x: u32, y: u32, z: u32) -> u32 {
|
||||
const fn g(x: u32, y: u32, z: u32) -> u32 {
|
||||
x & z | y & !z
|
||||
}
|
||||
|
||||
fn h(x: u32, y: u32, z: u32) -> u32 {
|
||||
const fn h(x: u32, y: u32, z: u32) -> u32 {
|
||||
x ^ y ^ z
|
||||
}
|
||||
|
||||
fn i(x: u32, y: u32, z: u32) -> u32 {
|
||||
const fn i(x: u32, y: u32, z: u32) -> u32 {
|
||||
y ^ (x | !z)
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ fn vec_to_array<T, const N: usize>(v: Vec<T>) -> [T; N] {
|
||||
* table[i] is an entry generated by our sine function, s is an unsigned
|
||||
* integer, and a,b,c,d are our 32 bit registers we perform operations on.
|
||||
*/
|
||||
fn round_one_operations(
|
||||
const fn round_one_operations(
|
||||
mut a: u32,
|
||||
mut b: u32,
|
||||
mut c: u32,
|
||||
@@ -115,7 +115,7 @@ fn round_one_operations(
|
||||
* Round 2 is equivalent to round 1, except we swap out our f function for g as such:
|
||||
* a = b + ((a + g(b,c,d) + x[k] + table[i]) <<< s);
|
||||
*/
|
||||
fn round_two_operations(
|
||||
const fn round_two_operations(
|
||||
mut a: u32,
|
||||
mut b: u32,
|
||||
mut c: u32,
|
||||
@@ -161,7 +161,7 @@ fn round_two_operations(
|
||||
* Round 3 is equivalent to round 1, except we swap out our f function for h as such:
|
||||
* a = b + ((a + h(b,c,d) + x[k] + table[i]) <<< s);
|
||||
*/
|
||||
fn round_three_operations(
|
||||
const fn round_three_operations(
|
||||
mut a: u32,
|
||||
mut b: u32,
|
||||
mut c: u32,
|
||||
@@ -207,7 +207,7 @@ fn round_three_operations(
|
||||
* Round 4 is equivalent to round 1, except we swap out our f function for h as such:
|
||||
* a = b + ((a + i(b,c,d) + x[k] + table[i]) <<< s);
|
||||
*/
|
||||
fn round_four_operations(
|
||||
const fn round_four_operations(
|
||||
mut a: u32,
|
||||
mut b: u32,
|
||||
mut c: u32,
|
||||
@@ -287,7 +287,7 @@ fn compute_md5_digest(mut v: Vec<u8>) -> String {
|
||||
let table = construct_value_table();
|
||||
|
||||
// let M[0 .. N-1] = words of resulting message, where N is multiple of 16
|
||||
for chunk in v.chunks_exact_mut(64) {
|
||||
for chunk in v.as_chunks_mut::<64>().0 {
|
||||
let x = convert_u8_chunk_to_u32(chunk);
|
||||
|
||||
// set all values of a,b,c,d to aa,bb,cc, and dd respectively.
|
||||
@@ -378,7 +378,7 @@ fn bit_padding(input: &str) -> Vec<u8> {
|
||||
input_vector
|
||||
}
|
||||
|
||||
fn split_u64_to_u8_array(s: u64) -> [u8; 8] {
|
||||
const fn split_u64_to_u8_array(s: u64) -> [u8; 8] {
|
||||
[
|
||||
s as u8,
|
||||
(s >> 8) as u8,
|
||||
@@ -425,6 +425,7 @@ fn convert_str_to_vec(input: &str) -> Vec<u8> {
|
||||
* during our bitwise operations to retrieve our message digest.
|
||||
* (This is a simplification, but describes the core functionality)
|
||||
*/
|
||||
#[must_use]
|
||||
pub fn md5(input: &str) -> String {
|
||||
let input_vec = bit_padding(input);
|
||||
compute_md5_digest(input_vec)
|
||||
@@ -454,7 +455,7 @@ fn lowercase_alphabet_correct_hash() {
|
||||
assert_eq!(
|
||||
"c3fcd3d76192e4007dfb496cca67e13b",
|
||||
md5("abcdefghijklmnopqrstuvwxyz")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[must_use]
|
||||
pub fn expand_tilde(path: &str) -> PathBuf {
|
||||
if let Some(stripped) = path.strip_prefix('~')
|
||||
&& let Ok(home) = std::env::var("HOME")
|
||||
|
||||
@@ -16,7 +16,8 @@ pub struct ThreadPool {
|
||||
}
|
||||
|
||||
impl ThreadPool {
|
||||
pub fn new(size: usize) -> ThreadPool {
|
||||
#[must_use]
|
||||
pub fn new(size: usize) -> Self {
|
||||
assert!(size > 0);
|
||||
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
@@ -27,7 +28,7 @@ impl ThreadPool {
|
||||
workers.push(Worker::new(Arc::clone(&receiver)));
|
||||
}
|
||||
|
||||
ThreadPool {
|
||||
Self {
|
||||
workers,
|
||||
sender: Some(sender),
|
||||
}
|
||||
@@ -62,6 +63,39 @@ impl Drop for ThreadPool {
|
||||
}
|
||||
}
|
||||
|
||||
struct Worker {
|
||||
thread: Option<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
fn new(receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Self {
|
||||
let thread = thread::spawn(move || {
|
||||
loop {
|
||||
let message = match receiver.lock_safe() {
|
||||
Ok(rx) => rx.recv(),
|
||||
Err(_) => break,
|
||||
};
|
||||
match message {
|
||||
// Contain a panicking job so it kills only that job, not the
|
||||
// worker: the pool has a fixed number of workers and a lost
|
||||
// one is never replaced. The lock is already released here,
|
||||
// so a panic cannot poison the shared receiver.
|
||||
Ok(Message::NewJob(job)) => {
|
||||
let _ = std::panic::catch_unwind(
|
||||
std::panic::AssertUnwindSafe(job),
|
||||
);
|
||||
}
|
||||
Ok(Message::Terminate) | Err(_) => break,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
thread: Some(thread),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ThreadPool;
|
||||
@@ -88,36 +122,3 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct Worker {
|
||||
thread: Option<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
fn new(receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
|
||||
let thread = thread::spawn(move || {
|
||||
loop {
|
||||
let message = match receiver.lock_safe() {
|
||||
Ok(rx) => rx.recv(),
|
||||
Err(_) => break,
|
||||
};
|
||||
match message {
|
||||
// Contain a panicking job so it kills only that job, not the
|
||||
// worker: the pool has a fixed number of workers and a lost
|
||||
// one is never replaced. The lock is already released here,
|
||||
// so a panic cannot poison the shared receiver.
|
||||
Ok(Message::NewJob(job)) => {
|
||||
let _ = std::panic::catch_unwind(
|
||||
std::panic::AssertUnwindSafe(job),
|
||||
);
|
||||
}
|
||||
Ok(Message::Terminate) | Err(_) => break,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Worker {
|
||||
thread: Some(thread),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ struct BitReader {
|
||||
}
|
||||
|
||||
impl BitReader {
|
||||
fn new(mem: Vec<u8>) -> Self {
|
||||
const fn new(mem: Vec<u8>) -> Self {
|
||||
Self {
|
||||
mem,
|
||||
pos: 0,
|
||||
@@ -42,7 +42,7 @@ impl BitReader {
|
||||
fn read_bits(&mut self, n: usize) -> std::result::Result<u32, String> {
|
||||
let mut o = 0u32;
|
||||
for i in 0..n {
|
||||
o |= (self.read_bit()? as u32) << i;
|
||||
o |= u32::from(self.read_bit()?) << i;
|
||||
}
|
||||
Ok(o)
|
||||
}
|
||||
@@ -51,7 +51,7 @@ impl BitReader {
|
||||
// read bytes as an integer in little-endian
|
||||
let mut o = 0u32;
|
||||
for i in 0..n {
|
||||
o |= (self.read_byte()? as u32) << (8 * i);
|
||||
o |= u32::from(self.read_byte()?) << (8 * i);
|
||||
}
|
||||
Ok(o)
|
||||
}
|
||||
@@ -72,7 +72,7 @@ pub fn deflate(input: &[u8]) -> Result<Vec<u8>> {
|
||||
return Err(SoulseekRs::CompressionError("invalid CINFO".to_string()));
|
||||
}
|
||||
let flg = r.read_byte()?;
|
||||
if !((cmf as u32) * 256 + (flg as u32)).is_multiple_of(31) {
|
||||
if !(u32::from(cmf) * 256 + u32::from(flg)).is_multiple_of(31) {
|
||||
return Err(SoulseekRs::CompressionError(
|
||||
"CMF+FLG checksum failed".to_string(),
|
||||
));
|
||||
@@ -119,12 +119,12 @@ fn inflate_block_no_compression(
|
||||
#[derive(Clone)]
|
||||
struct Node {
|
||||
symbol: Option<u32>,
|
||||
left: Option<Box<Node>>,
|
||||
right: Option<Box<Node>>,
|
||||
left: Option<Box<Self>>,
|
||||
right: Option<Box<Self>>,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn new() -> Self {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
symbol: None,
|
||||
left: None,
|
||||
@@ -138,7 +138,7 @@ struct HuffmanTree {
|
||||
}
|
||||
|
||||
impl HuffmanTree {
|
||||
fn new() -> Self {
|
||||
const fn new() -> Self {
|
||||
Self { root: Node::new() }
|
||||
}
|
||||
|
||||
@@ -175,9 +175,9 @@ fn decode_symbol(
|
||||
// at a missing child; error out instead of unwrap-panicking.
|
||||
node = next
|
||||
.as_ref()
|
||||
.ok_or("Invalid Huffman code".to_string())?;
|
||||
.ok_or_else(|| "Invalid Huffman code".to_string())?;
|
||||
}
|
||||
node.symbol.ok_or("No symbol found".to_string())
|
||||
node.symbol.ok_or_else(|| "No symbol found".to_string())
|
||||
}
|
||||
|
||||
const LENGTH_EXTRA_BITS: [usize; 29] = [
|
||||
@@ -397,7 +397,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_header_success() {
|
||||
let _data = [120, 156]; // Valid zlib header
|
||||
// [120, 156] is a valid zlib header
|
||||
let result = deflate(&[120, 156, 3, 0, 0, 0, 0, 1]); // Minimal valid zlib stream
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user