Route dr-ui's decoding through the Decoder trait

With the trait in place the claim still meant nothing while every caller
named dr_decode's free functions: a second decoder would have had to be
threaded through the scan, the thumbnail ladder, import, the viewer,
export, merge and repairs at the moment it arrived.

Each of those now takes a &dyn Decoder and reads headers, previews,
orientation and sensor data through it, including the header budget a
remote fetch asks for (header_bytes) and where it finds the embedded
preview (locate_preview). Only the places that start a job name
dr_decode::default(): the thumbnail, sweep and thumbnail-sweep threads,
the viewer's open handlers, and the request structs a job is handed
(BatchRequest, MergeRequest, the import Request, the repairs Toolkit),
so a caller can be given another decoder by changing what it is handed.

The default is rawler through the same free functions as before, so
nothing a user sees changes. The trait gains Debug as a supertrait so
request structs that derive Debug can carry one.
This commit is contained in:
2026-09-24 21:33:14 -04:00
parent d8fb382ce9
commit 414094bd38
10 changed files with 214 additions and 129 deletions
+24 -5
View File
@@ -517,6 +517,10 @@ pub struct BatchRequest {
/// rendered at all — reported per image rather than refused up front, so
/// the reason lands in the same place every other failure does.
pub gpu: Option<dr_gpu::GpuContext>,
/// TRACES: FR-RAW-2
/// What reads the header and decodes the sensor data, chosen by whoever
/// assembled the batch; the worker never names one.
pub decoder: &'static dyn dr_decode::Decoder,
}
/// TRACES: NFR-ARCH-4
@@ -750,6 +754,22 @@ type RenderedItem = (
Option<dr_export::SourceMetadata>,
);
/// TRACES: FR-RAW-2 | FR-EXP-8
/// Read a fetched photograph's header and open it for rendering, through
/// whichever decoder the batch was given.
///
/// Split from [`render_from_library`] so the half that decodes can be run
/// without a server: the stub-decoder test drives it directly.
pub(crate) fn open_for_export(
gpu: &dr_gpu::GpuContext,
decoder: &dyn dr_decode::Decoder,
bytes: &[u8],
) -> Result<(dr_decode::Metadata, crate::DevelopSession), String> {
let meta = decoder.metadata(bytes).unwrap_or_default();
let session = crate::open_session(gpu, decoder, bytes, &meta)?;
Ok((meta, session))
}
/// Fetch a photograph, apply its stored edit, and render it at full size.
///
/// `None` means the work was cancelled, which is not a failure and has no
@@ -802,13 +822,11 @@ fn render_from_library(
Waited::Silent => None,
};
let meta = dr_decode::metadata(&bytes).unwrap_or_default();
let (date, carried) = from_header(&meta);
let mut session = match crate::open_session(gpu, &bytes, &meta) {
Ok(session) => session,
let (meta, mut session) = match open_for_export(gpu, request.decoder, &bytes) {
Ok(opened) => opened,
Err(e) => return Some(Err(ItemError::Open(e))),
};
let (date, carried) = from_header(&meta);
// TRACES: FR-CAT-8
// The stored edit. FR-EXP-9 is about resolution; this is the other half of
@@ -1400,6 +1418,7 @@ mod tests {
sidecar_cache: std::env::temp_dir().join("dr-batch-test-sidecars"),
offline: true,
gpu: None,
decoder: dr_decode::default(),
}
}