Split library.rs into library/ by area of behaviour
library.rs was 7,729 lines wiring together everything "open a remote library" touches: scanning, pulling other devices' judgements out of sidecars found along the way, writing local edits back out to the sidecar outbox, pushing/reloading XMP by hand, fetching and prefetching thumbnails and originals, generating thumbnails locally, the metadata and thumbnail background sweeps, on-disk paths for the catalog and model files, and reading the grid's cells, spans and rating filter. Same motivation as the develop.rs split (docs/dev/code-health.md CH-1): a pure, no-behaviour-change move into one file per area, each under about 1,500 lines. Tracing actual call sites rather than trusting the file's physical layout mattered here: `persist`, `load_folder_etags`, `pull_sidecars`, `load_sidecar_etags`, `record_sidecar_read` and `apply_judgement` sit textually beside the XMP push/reload functions but are called only from `run_scan` (pulling a device's own past judgements out of the sidecars a scan just walked), so they went to scan.rs and not xmp.rs. `cells` came out at over 1,800 lines once its tests moved with it and split further into cells.rs (windowed reads, trash, ordinals) and spans.rs (collection scope, manual reordering, the capture-time histogram) -- ten submodules rather than the nine first planned. Previously-private items reached from a sibling module became `pub(super)`, narrower than the whole-crate reachability one file gave them. Tests moved with the code they test; the two test fixtures used across more than one file (`scanned`, and develop.rs's `session_with_a_left_half_subject` in the matching commit) joined the shared `test_support` module alongside the existing `entry`/ `with_images`/`image_ids` helpers. `mod.rs` re-exports every module's public items under `library::`, including the `pub(crate)` `test_support` module `repairs.rs` reads its fixtures from, so no file outside `library` needed a change. The previous commit split develop.rs the same way; taken alone it left dr-ui without library.rs, so that intermediate commit does not build on its own. This one restores it.
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
//! TRACES: FR-CAT-1 | FR-CAT-4 | FR-NC-3 | NFR-P9
|
||||
//! Opening a remote library: scan → catalog → grid.
|
||||
//!
|
||||
//! This is the wire between three pieces that already worked separately —
|
||||
//! `dr_sync::scan` walks the tree, `dr_catalog` indexes it, and
|
||||
//! `dr_decode::preview` turns bytes into pixels. Until now the "Open library"
|
||||
//! button logged its intent and stopped.
|
||||
//!
|
||||
//! # Threading
|
||||
//!
|
||||
//! Slint's event loop is single-threaded and must never block (NFR-P9), so
|
||||
//! every network and decode operation runs on a worker thread and results
|
||||
//! return through an mpsc channel drained by a Slint timer. That is the same
|
||||
//! shape the login flow uses; it is repeated rather than shared because the
|
||||
//! message types differ and a generic version would obscure both.
|
||||
//!
|
||||
//! # Why thumbnails are fetched, not derived from the scan
|
||||
//!
|
||||
//! A scan yields paths and sizes, nothing visual. Each thumbnail costs its own
|
||||
//! range request, so they are fetched **only for cells the grid actually
|
||||
//! wants** — never for the whole library up front. On the reference library
|
||||
//! that is the difference between a few MB and ~370 GB (ARCH §6.7).
|
||||
//!
|
||||
//! Split into one module per area (docs/dev/code-health.md CH-1): filtering,
|
||||
//! sidecar writes, on-disk paths, scanning, XMP, thumbnail fetch and
|
||||
//! generation, the background sweeps, and reading the grid's cells and spans.
|
||||
//! `mod.rs` re-exports every module's public items so nothing outside
|
||||
//! `library` needs to change.
|
||||
|
||||
mod cells;
|
||||
mod filters;
|
||||
mod paths;
|
||||
mod scan;
|
||||
mod sidecar;
|
||||
mod spans;
|
||||
mod sweep;
|
||||
mod thumbnails_fetch;
|
||||
mod thumbnails_gen;
|
||||
mod xmp;
|
||||
|
||||
pub use cells::*;
|
||||
pub use filters::*;
|
||||
pub use paths::*;
|
||||
pub use scan::*;
|
||||
pub use sidecar::*;
|
||||
pub use spans::*;
|
||||
pub use sweep::*;
|
||||
pub use thumbnails_fetch::*;
|
||||
pub use thumbnails_gen::*;
|
||||
pub use xmp::*;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test_support {
|
||||
//! Fixtures shared with the modules that build on this one's catalog
|
||||
//! layout -- `repairs`, whose work lists are read over the same `images`
|
||||
//! and `remote` rows a scan writes.
|
||||
use dr_catalog::Catalog;
|
||||
use dr_sync::{RemoteEntry, RemoteId, RemotePath};
|
||||
|
||||
use super::scan::persist;
|
||||
|
||||
pub fn entry(path: &str, file_id: u64, size: u64) -> RemoteEntry {
|
||||
RemoteEntry {
|
||||
id: RemoteId::Stable(file_id),
|
||||
path: RemotePath::new(path),
|
||||
kind: dr_sync::EntryKind::File,
|
||||
validator: dr_sync::Validator::new("v"),
|
||||
size,
|
||||
modified: None,
|
||||
has_preview: false,
|
||||
materialised: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// A catalog with `n` images, ready to file into collections.
|
||||
pub fn with_images(n: usize) -> Catalog {
|
||||
let catalog = Catalog::in_memory().unwrap();
|
||||
let images: Vec<RemoteEntry> = (0..n)
|
||||
.map(|i| entry(&format!("PhotosRaw/img{i:03}.CR2"), i as u64, 1000))
|
||||
.collect();
|
||||
let result = dr_sync::ScanResult {
|
||||
images,
|
||||
directories: vec![(RemotePath::new("PhotosRaw"), dr_sync::Validator::new("e"))],
|
||||
progress: Default::default(),
|
||||
sidecars: Vec::new(),
|
||||
};
|
||||
persist(&catalog, "PhotosRaw", &result).unwrap();
|
||||
catalog
|
||||
}
|
||||
|
||||
/// A catalog with `n` scanned images, none trashed.
|
||||
///
|
||||
/// Shared with `spans`, whose collection-membership tests build on the
|
||||
/// same "n images, no folders beyond the root" catalog `cells`'s trash
|
||||
/// tests do.
|
||||
pub fn scanned(n: u64) -> Catalog {
|
||||
let catalog = Catalog::in_memory().unwrap();
|
||||
let images = (1..=n)
|
||||
.map(|i| entry(&format!("PhotosRaw/IMG_{i:04}.CR2"), 1000 + i, 30_000_000))
|
||||
.collect();
|
||||
persist(
|
||||
&catalog,
|
||||
"PhotosRaw",
|
||||
&dr_sync::ScanResult {
|
||||
images,
|
||||
directories: vec![(RemotePath::new("PhotosRaw"), dr_sync::Validator::new("e1"))],
|
||||
progress: Default::default(),
|
||||
sidecars: Vec::new(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
catalog
|
||||
}
|
||||
|
||||
pub fn image_ids(catalog: &Catalog) -> Vec<dr_types::ImageId> {
|
||||
let mut stmt = catalog
|
||||
.connection()
|
||||
.prepare("SELECT id FROM images ORDER BY source_ref")
|
||||
.unwrap();
|
||||
stmt.query_map([], |r| Ok(dr_types::ImageId(r.get::<_, i64>(0)? as u64)))
|
||||
.unwrap()
|
||||
.map(Result::unwrap)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user