chore(rust): clear the clippy backlog and finish the poison-tolerant lock sweep
`cargo clippy --all-targets` went from 51 warnings (23 in the lib) to zero. Most were mechanical — needless borrows, `assert_eq!` against a bool literal, `vec!` where an array does, `or_insert_with(Vec::new)`, a loop index used only to index — and were applied with `clippy --fix`, then reviewed line by line. That review caught one auto-fix that was *not* semantically neutral: dropping the redundant `use hostname;` left its `#[cfg(target_os = "linux")]` orphaned directly above `SERVICE_NAME`, which would have silently cfg'd the constant out of every non-Linux build. Removed the stray attribute with the import. Where a lint asked for a risky change rather than a better one, it is suppressed with a comment saying why: - `too_many_arguments` on five `#[tauri::command]` handlers and `ThumbnailCache::save_thumbnail` — most of the arity is `State<'_, _>` injection, and a parameter struct would change the IPC contract and the generated TypeScript for no readability gain. - `large_enum_variant` on `PlayerStatusEvent` and `AutoplayDecision` — both are serde + specta wire types emitted a handful of times a second, never bulk allocated; boxing would have to stay invisible to the generated bindings while every match arm gained a deref. - `await_holding_lock` on the `hybrid`/`offline` test modules — the guard is a test-only serialisation lock for the process-global `INCLUDE_CATALOG_BROWSE` flag, and the await it spans *is* the critical section. Each `#[tokio::test]` gets its own single-threaded runtime, so this is not the production deadlock class the lint targets; restructuring would reintroduce the flag race. Real fixes elsewhere: `JellyfinItem::to_media_item` takes `self` by value, so it is now `into_media_item`; the five-tuple episode row in the download commands has a named `EpisodeRow` alias; the mpv `PropertyChange` arm matches `name: "pause"` instead of guarding on it. Also converted the last 27 raw `.lock().unwrap()` call sites to `lock_safe()`, completing the `MutexSafe`/`RwLockSafe` convention. All of them turned out to be in test modules — production code was already clean — so this is consistency rather than a fix. The two raw locks in `utils/lock.rs` stay raw on purpose: those tests deliberately poison a mutex to prove the helpers recover from it. Pure refactoring: all 698 tests still pass.
This commit is contained in:
@@ -1480,6 +1480,10 @@ pub async fn player_seek_video(
|
||||
/// Note: Frontend should handle saving series preferences after this command succeeds
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
// Two of the eight arguments are Tauri `State<'_, _>` injections, not caller
|
||||
// input. Folding the rest into a struct would change the IPC contract and the
|
||||
// generated TypeScript for no readability gain.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn player_switch_audio_track(
|
||||
player: State<'_, PlayerStateWrapper>,
|
||||
repository_manager: State<'_, super::repository::RepositoryManagerWrapper>,
|
||||
@@ -1559,6 +1563,10 @@ pub async fn player_switch_audio_track(
|
||||
/// TRACES: UR-074 | DR-162
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
// Three of the nine arguments are Tauri `State<'_, _>` injections, not caller
|
||||
// input. Folding the rest into a struct would change the IPC contract and the
|
||||
// generated TypeScript for no readability gain.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn player_set_stream_quality(
|
||||
player: State<'_, PlayerStateWrapper>,
|
||||
repository_manager: State<'_, super::repository::RepositoryManagerWrapper>,
|
||||
@@ -1784,7 +1792,7 @@ pub async fn player_get_status(
|
||||
let local_media = {
|
||||
let queue_arc = controller.queue();
|
||||
let queue = queue_arc.lock().map_err(|e| e.to_string())?;
|
||||
queue.current().map(|item| MergedMediaItem::from(item))
|
||||
queue.current().map(MergedMediaItem::from)
|
||||
};
|
||||
|
||||
let local_is_playing = status.state.is_playing();
|
||||
@@ -1808,10 +1816,7 @@ pub async fn player_get_status(
|
||||
log::info!("[PlayerCommands] Merging remote session state");
|
||||
|
||||
// Merge media item
|
||||
status.merged_media = session
|
||||
.now_playing_item
|
||||
.as_ref()
|
||||
.map(|item| MergedMediaItem::from(item));
|
||||
status.merged_media = session.now_playing_item.as_ref().map(MergedMediaItem::from);
|
||||
|
||||
// Merge isPlaying (NOT isPaused!)
|
||||
status.merged_is_playing = session
|
||||
@@ -2741,6 +2746,8 @@ pub async fn player_disable_jellyfin(player: State<'_, PlayerStateWrapper>) -> R
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::utils::lock::MutexSafe;
|
||||
|
||||
/// The subtitle list the frontend resolved must survive the IPC hop and end
|
||||
/// up on the `MediaItem` the native backend loads.
|
||||
///
|
||||
@@ -3063,7 +3070,7 @@ mod tests {
|
||||
let database = Database::open_in_memory().unwrap();
|
||||
{
|
||||
let conn = database.connection();
|
||||
let conn = conn.lock().unwrap();
|
||||
let conn = conn.lock_safe();
|
||||
conn.execute_batch(&format!(
|
||||
r#"
|
||||
INSERT INTO servers (id, name, url) VALUES ('srv', 'Test', 'http://test');
|
||||
@@ -3119,7 +3126,7 @@ mod tests {
|
||||
assert_eq!(switched, 1, "only the download whose file exists switches");
|
||||
|
||||
let queue = controller.queue();
|
||||
let queue_lock = queue.lock().unwrap();
|
||||
let queue_lock = queue.lock_safe();
|
||||
match &queue_lock.items()[0].source {
|
||||
MediaSource::Local {
|
||||
file_path,
|
||||
@@ -3148,7 +3155,7 @@ mod tests {
|
||||
index_number: Option<i32>,
|
||||
}
|
||||
|
||||
let mut tracks = vec![
|
||||
let mut tracks = [
|
||||
MockTrack {
|
||||
id: "track1".to_string(),
|
||||
name: "Song 1".to_string(),
|
||||
@@ -3241,7 +3248,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// Create tracks in random order (not sorted)
|
||||
let mut tracks = vec![
|
||||
let mut tracks = [
|
||||
MockTrack {
|
||||
id: "id5".to_string(),
|
||||
name: "Track 5".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user