style(backend): apply rustfmt across the backend

Mechanical cargo fmt pass so the CI rustfmt gate starts green; no semantic
changes (verified token-level + cargo check).
This commit is contained in:
2026-06-12 18:36:31 +01:00
parent 69e53ed62a
commit 1d782a6d57
6 changed files with 242 additions and 131 deletions
+157 -91
View File
@@ -445,7 +445,7 @@ pub async fn find_similar_images(
offset,
limit + 1,
)
.map_err(|e| e.to_string())?;
.map_err(|e| e.to_string())?;
let has_more = matches.len() > limit;
let image_ids = matches
.into_iter()
@@ -499,8 +499,9 @@ pub async fn find_similar_by_region(
None => {
// Fetch one extra candidate to compensate for the source image that
// will be removed, so has_more is accurate and results span multiple pages.
let mut ids = vector::search_image_ids_by_embedding(&conn, &embedding, offset + limit + 2)
.map_err(|e| e.to_string())?;
let mut ids =
vector::search_image_ids_by_embedding(&conn, &embedding, offset + limit + 2)
.map_err(|e| e.to_string())?;
ids.retain(|&id| id != params.image_id);
ids
}
@@ -639,7 +640,12 @@ pub async fn search_images_by_tag(
offset,
)
.map_err(|e| e.to_string())?;
Ok(TagSearchPage { images, total, offset, limit })
Ok(TagSearchPage {
images,
total,
offset,
limit,
})
}
#[tauri::command]
@@ -835,7 +841,6 @@ pub struct TagCloudEntry {
pub image_ids: Vec<i64>,
}
/// Clusters the library's image embeddings with k-means and returns one representative
/// image per cluster — the member whose embedding is closest to its cluster centroid.
/// Results are cached in SQLite keyed by a hash of the embedded image IDs, so repeated
@@ -957,7 +962,8 @@ pub async fn get_explore_tags(
params: GetExploreTagsParams,
) -> Result<Vec<ExploreTagEntry>, String> {
let conn = db.get().map_err(|e| e.to_string())?;
db::get_explore_tags(&conn, params.folder_id, params.limit.unwrap_or(48)).map_err(|e| e.to_string())
db::get_explore_tags(&conn, params.folder_id, params.limit.unwrap_or(48))
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -969,8 +975,13 @@ pub async fn search_tags_autocomplete(
return Ok(vec![]);
}
let conn = db.get().map_err(|e| e.to_string())?;
db::search_tags_autocomplete(&conn, &params.query, params.folder_id, params.limit.unwrap_or(10))
.map_err(|e| e.to_string())
db::search_tags_autocomplete(
&conn,
&params.query,
params.folder_id,
params.limit.unwrap_or(10),
)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -985,12 +996,15 @@ pub async fn find_duplicates(
};
let total = records.len();
let _ = app.emit("duplicate_scan_progress", DuplicateScanProgress {
phase: "checking".to_string(),
processed: 0,
total,
skipped: 0,
});
let _ = app.emit(
"duplicate_scan_progress",
DuplicateScanProgress {
phase: "checking".to_string(),
processed: 0,
total,
skipped: 0,
},
);
// Three-phase detection.
//
@@ -1007,8 +1021,11 @@ pub async fn find_duplicates(
// For sample-hash groups that contain files > 64 KB, compute a full-file
// hash to confirm the match before presenting them as deletable duplicates.
let app_hash = app.clone();
let (pairs, skipped_before_confirm, candidate_total):
(Vec<(u64, u64, i64, String)>, usize, usize) = tokio::task::spawn_blocking(move || {
let (pairs, skipped_before_confirm, candidate_total): (
Vec<(u64, u64, i64, String)>,
usize,
usize,
) = tokio::task::spawn_blocking(move || {
use memmap2::Mmap;
use rayon::prelude::*;
use std::collections::HashMap;
@@ -1016,7 +1033,7 @@ pub async fn find_duplicates(
use xxhash_rust::xxh3::{xxh3_64, Xxh3};
const WINDOW: usize = 16 * 1024; // 16 KB per sample window
const N: usize = 4; // windows at 0%, 33%, 66%, 100%
const N: usize = 4; // windows at 0%, 33%, 66%, 100%
const COVERED: usize = WINDOW * N; // 64 KB total; also full-coverage threshold
// Hash four evenly-spaced 16 KB windows. For files ≤ 64 KB this is
@@ -1048,12 +1065,15 @@ pub async fn find_duplicates(
};
let done = stat_counter.fetch_add(1, Ordering::Relaxed) + 1;
if done % 100 == 0 || done == total {
let _ = app_hash.emit("duplicate_scan_progress", DuplicateScanProgress {
phase: "checking".to_string(),
processed: done,
total,
skipped: stat_skipped.load(Ordering::Relaxed),
});
let _ = app_hash.emit(
"duplicate_scan_progress",
DuplicateScanProgress {
phase: "checking".to_string(),
processed: done,
total,
skipped: stat_skipped.load(Ordering::Relaxed),
},
);
}
result
})
@@ -1076,12 +1096,15 @@ pub async fn find_duplicates(
// ── Phase 2: sample hash ──────────────────────────────────────────
let c_total = candidates.len();
let _ = app_hash.emit("duplicate_scan_progress", DuplicateScanProgress {
phase: "hashing".to_string(),
processed: 0,
total: c_total,
skipped: stat_skipped,
});
let _ = app_hash.emit(
"duplicate_scan_progress",
DuplicateScanProgress {
phase: "hashing".to_string(),
processed: 0,
total: c_total,
skipped: stat_skipped,
},
);
let counter = AtomicUsize::new(0);
let hash_skipped = AtomicUsize::new(0);
@@ -1103,12 +1126,15 @@ pub async fn find_duplicates(
}
let done = counter.fetch_add(1, Ordering::Relaxed) + 1;
if done % 100 == 0 || done == c_total {
let _ = app_hash.emit("duplicate_scan_progress", DuplicateScanProgress {
phase: "hashing".to_string(),
processed: done,
total: c_total,
skipped: stat_skipped + hash_skipped.load(Ordering::Relaxed),
});
let _ = app_hash.emit(
"duplicate_scan_progress",
DuplicateScanProgress {
phase: "hashing".to_string(),
processed: done,
total: c_total,
skipped: stat_skipped + hash_skipped.load(Ordering::Relaxed),
},
);
}
result
})
@@ -1126,7 +1152,10 @@ pub async fn find_duplicates(
let mut size_hash_map: std::collections::HashMap<(u64, u64), Vec<(i64, String)>> =
std::collections::HashMap::new();
for (hash, file_size, id, path) in pairs {
size_hash_map.entry((hash, file_size)).or_default().push((id, path));
size_hash_map
.entry((hash, file_size))
.or_default()
.push((id, path));
}
// Phase 3: for large-file groups (> 64 KB) the sample hash is not exact;
@@ -1140,12 +1169,15 @@ pub async fn find_duplicates(
.map(|(_, entries)| entries.len())
.sum();
if confirming_total > 0 {
let _ = app.emit("duplicate_scan_progress", DuplicateScanProgress {
phase: "confirming".to_string(),
processed: 0,
total: confirming_total,
skipped: skipped_before_confirm,
});
let _ = app.emit(
"duplicate_scan_progress",
DuplicateScanProgress {
phase: "confirming".to_string(),
processed: 0,
total: confirming_total,
skipped: skipped_before_confirm,
},
);
}
let app_confirm = app.clone();
let (confirmed, skipped_files): (Vec<(u64, u64, Vec<i64>)>, usize) =
@@ -1163,7 +1195,11 @@ pub async fn find_duplicates(
.flat_map(|((sample_hash, file_size), entries)| {
if file_size <= COVERED {
// Sample was already a full hash — one group, no re-read needed.
return vec![(sample_hash, file_size, entries.into_iter().map(|(id, _)| id).collect())];
return vec![(
sample_hash,
file_size,
entries.into_iter().map(|(id, _)| id).collect(),
)];
}
// Full-file hash pass. Group by full hash so that two sets of
// files that collide only in the sample produce separate groups.
@@ -1179,13 +1215,16 @@ pub async fn find_duplicates(
}
let done = counter.fetch_add(1, Ordering::Relaxed) + 1;
if done % 100 == 0 || done == confirming_total {
let _ = app_confirm.emit("duplicate_scan_progress", DuplicateScanProgress {
phase: "confirming".to_string(),
processed: done,
total: confirming_total,
skipped: skipped_before_confirm
+ confirm_skipped.load(Ordering::Relaxed),
});
let _ = app_confirm.emit(
"duplicate_scan_progress",
DuplicateScanProgress {
phase: "confirming".to_string(),
processed: done,
total: confirming_total,
skipped: skipped_before_confirm
+ confirm_skipped.load(Ordering::Relaxed),
},
);
}
(*id, hash)
})
@@ -1470,16 +1509,17 @@ pub async fn get_worker_states(folder_ids: Vec<i64>) -> Result<Vec<FolderWorkerS
Ok(folder_ids
.into_iter()
.map(|folder_id| {
let state = states
.get(&folder_id)
.copied()
.unwrap_or(indexer::FolderWorkerPausedState {
thumbnail: false,
metadata: false,
embedding: false,
caption: false,
tagging: false,
});
let state =
states
.get(&folder_id)
.copied()
.unwrap_or(indexer::FolderWorkerPausedState {
thumbnail: false,
metadata: false,
embedding: false,
caption: false,
tagging: false,
});
FolderWorkerStates {
folder_id,
thumbnail_paused: state.thumbnail,
@@ -1631,7 +1671,11 @@ pub async fn queue_tagging_jobs(
) -> Result<usize, String> {
let conn = db.get().map_err(|e| e.to_string())?;
let requested_folder_ids = params.folder_ids.unwrap_or_default();
let (total, folder_ids) = match (params.folder_id, params.image_id, requested_folder_ids.is_empty()) {
let (total, folder_ids) = match (
params.folder_id,
params.image_id,
requested_folder_ids.is_empty(),
) {
(_, Some(image_id), _) => {
db::enqueue_tagging_job(&conn, image_id).map_err(|e| e.to_string())?;
// Look up just this image's folder_id rather than fetching all folders
@@ -1675,27 +1719,29 @@ pub async fn clear_tagging_jobs(
) -> Result<usize, String> {
let conn = db.get().map_err(|e| e.to_string())?;
let requested_folder_ids = params.folder_ids.unwrap_or_default();
let (n, folder_ids): (usize, Vec<i64>) = match (params.folder_id, requested_folder_ids.is_empty()) {
(Some(id), _) => (
db::clear_tagging_jobs(&conn, Some(id)).map_err(|e| e.to_string())?,
vec![id],
),
(None, false) => {
let mut total = 0usize;
for &folder_id in &requested_folder_ids {
total += db::clear_tagging_jobs(&conn, Some(folder_id)).map_err(|e| e.to_string())?;
let (n, folder_ids): (usize, Vec<i64>) =
match (params.folder_id, requested_folder_ids.is_empty()) {
(Some(id), _) => (
db::clear_tagging_jobs(&conn, Some(id)).map_err(|e| e.to_string())?,
vec![id],
),
(None, false) => {
let mut total = 0usize;
for &folder_id in &requested_folder_ids {
total += db::clear_tagging_jobs(&conn, Some(folder_id))
.map_err(|e| e.to_string())?;
}
(total, requested_folder_ids)
}
(total, requested_folder_ids)
}
(None, true) => (
db::clear_tagging_jobs(&conn, None).map_err(|e| e.to_string())?,
db::get_folders(&conn)
.map_err(|e| e.to_string())?
.into_iter()
.map(|f| f.id)
.collect(),
),
};
(None, true) => (
db::clear_tagging_jobs(&conn, None).map_err(|e| e.to_string())?,
db::get_folders(&conn)
.map_err(|e| e.to_string())?
.into_iter()
.map(|f| f.id)
.collect(),
),
};
drop(conn);
indexer::emit_folder_job_progress(&app, db.inner(), &folder_ids, true);
Ok(n)
@@ -1747,7 +1793,11 @@ pub async fn get_tagging_queue_scope(app: AppHandle) -> Result<String, String> {
let app_dir = app.path().app_data_dir().map_err(|e| e.to_string())?;
let path = app_dir.join(TAGGING_QUEUE_SCOPE_FILE);
let value = std::fs::read_to_string(path).unwrap_or_default();
Ok(if value.trim() == "selected" { "selected".to_string() } else { "all".to_string() })
Ok(if value.trim() == "selected" {
"selected".to_string()
} else {
"all".to_string()
})
}
#[tauri::command]
@@ -1760,7 +1810,11 @@ pub async fn set_tagging_queue_scope(
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;
}
let value = if params.scope == "selected" { "selected" } else { "all" };
let value = if params.scope == "selected" {
"selected"
} else {
"all"
};
std::fs::write(path, value).map_err(|e| e.to_string())?;
Ok(value.to_string())
}
@@ -1825,14 +1879,21 @@ pub struct VacuumResult {
}
#[tauri::command]
pub async fn get_database_info(app: AppHandle, db: State<'_, DbState>) -> Result<DatabaseInfo, String> {
pub async fn get_database_info(
app: AppHandle,
db: State<'_, DbState>,
) -> Result<DatabaseInfo, String> {
let app_dir = app.path().app_data_dir().map_err(|e| e.to_string())?;
let db_path = app_dir.join("gallery.db");
let size_bytes = std::fs::metadata(&db_path).map(|m| m.len()).unwrap_or(0);
let conn = db.get().map_err(|e| e.to_string())?;
let page_size: i64 = conn.query_row("PRAGMA page_size", [], |r| r.get(0)).map_err(|e| e.to_string())?;
let freelist_count: i64 = conn.query_row("PRAGMA freelist_count", [], |r| r.get(0)).map_err(|e| e.to_string())?;
let page_size: i64 = conn
.query_row("PRAGMA page_size", [], |r| r.get(0))
.map_err(|e| e.to_string())?;
let freelist_count: i64 = conn
.query_row("PRAGMA freelist_count", [], |r| r.get(0))
.map_err(|e| e.to_string())?;
Ok(DatabaseInfo {
size_mb: size_bytes as f64 / 1_048_576.0,
@@ -1841,13 +1902,17 @@ pub async fn get_database_info(app: AppHandle, db: State<'_, DbState>) -> Result
}
#[tauri::command]
pub async fn vacuum_database(app: AppHandle, db: State<'_, DbState>) -> Result<VacuumResult, String> {
pub async fn vacuum_database(
app: AppHandle,
db: State<'_, DbState>,
) -> Result<VacuumResult, String> {
let app_dir = app.path().app_data_dir().map_err(|e| e.to_string())?;
let db_path = app_dir.join("gallery.db");
let before_bytes = std::fs::metadata(&db_path).map(|m| m.len()).unwrap_or(0);
let conn = db.get().map_err(|e| e.to_string())?;
conn.execute_batch("PRAGMA wal_checkpoint(FULL); VACUUM;").map_err(|e| e.to_string())?;
conn.execute_batch("PRAGMA wal_checkpoint(FULL); VACUUM;")
.map_err(|e| e.to_string())?;
drop(conn);
let after_bytes = std::fs::metadata(&db_path).map(|m| m.len()).unwrap_or(0);
@@ -1870,7 +1935,9 @@ pub struct CleanupOrphanedThumbnailsResult {
pub freed_mb: f64,
}
fn collect_db_thumbnail_filenames(conn: &rusqlite::Connection) -> Result<std::collections::HashSet<String>, String> {
fn collect_db_thumbnail_filenames(
conn: &rusqlite::Connection,
) -> Result<std::collections::HashSet<String>, String> {
let mut stmt = conn
.prepare("SELECT thumbnail_path FROM images WHERE thumbnail_path IS NOT NULL")
.map_err(|e| e.to_string())?;
@@ -1993,8 +2060,7 @@ pub async fn set_muted_folder_ids(
.map(|id| id.to_string())
.collect::<Vec<_>>()
.join(",");
std::fs::write(settings_dir.join("muted_folder_ids.txt"), content)
.map_err(|e| e.to_string())
std::fs::write(settings_dir.join("muted_folder_ids.txt"), content).map_err(|e| e.to_string())
}
#[tauri::command]