The inconsistency
Four crates now expose the facade's typed models, and they do not agree on the shape:
| crate |
blocks() |
metadata() |
gamut-jpeg |
Vec<MetadataBlock<'_>> |
gamut_metadata::Result<Metadata> |
gamut-jxl |
Vec<MetadataBlock<'_>> |
gamut_metadata::Result<Metadata> |
gamut-dng |
Vec<MetadataBlock<'_>> |
(none — DngMetadata holds the facade's Exif by value) |
gamut-heic |
Result<Vec<MetadataBlock<'_>>> (the crate's error) |
Result<Metadata> (the crate's error) |
So a caller writing format-agnostic code over blocks() cannot: three of the four are infallible
and one is not, and the fallible one reports gamut_heic::Error while the others report
gamut_metadata::MetadataError.
The divergence is not arbitrary. HEIC's payloads are items in an ISOBMFF tree, and resolving an
item to its bytes can fail (a missing iloc extent, an item construction method the crate does not
support), so blocks() there is genuinely a fallible operation. JPEG, JXL and DNG have already
resolved their payloads to owned or borrowed bytes by the time the type exists, so nothing can fail.
What needs deciding
- Is
blocks() fallible everywhere, or infallible everywhere? Making it uniformly fallible
costs three crates a ? for an error they can never return. Making it uniformly infallible
forces HEIC either to resolve items eagerly at parse time or to drop the ones it cannot resolve,
which is a silent loss the workspace generally refuses.
- Whose error type? A crate-native error keeps the crate self-contained; the facade's error
makes the accessor usable through a trait. Today's answer differs per crate by accident rather
than by rule.
- Should this be a trait at all? A
TypedMetadata trait in gamut-metadata would fix both
answers by construction and let a caller write one function over every wired format — but it
also fixes them for every crate wired later, so it is worth choosing on purpose. It must stay
object-safe and C-portable per AGENTS.md.
This outlives any one pull request: it binds gamut-png, gamut-webp, gamut-avif and
gamut-tiff when they are wired (tracked by the #420 remainder).
Evidence
Refs #420.
The inconsistency
Four crates now expose the facade's typed models, and they do not agree on the shape:
blocks()metadata()gamut-jpegVec<MetadataBlock<'_>>gamut_metadata::Result<Metadata>gamut-jxlVec<MetadataBlock<'_>>gamut_metadata::Result<Metadata>gamut-dngVec<MetadataBlock<'_>>DngMetadataholds the facade'sExifby value)gamut-heicResult<Vec<MetadataBlock<'_>>>(the crate's error)Result<Metadata>(the crate's error)So a caller writing format-agnostic code over
blocks()cannot: three of the four are infallibleand one is not, and the fallible one reports
gamut_heic::Errorwhile the others reportgamut_metadata::MetadataError.The divergence is not arbitrary. HEIC's payloads are items in an ISOBMFF tree, and resolving an
item to its bytes can fail (a missing
ilocextent, an item construction method the crate does notsupport), so
blocks()there is genuinely a fallible operation. JPEG, JXL and DNG have alreadyresolved their payloads to owned or borrowed bytes by the time the type exists, so nothing can fail.
What needs deciding
blocks()fallible everywhere, or infallible everywhere? Making it uniformly falliblecosts three crates a
?for an error they can never return. Making it uniformly infallibleforces HEIC either to resolve items eagerly at parse time or to drop the ones it cannot resolve,
which is a silent loss the workspace generally refuses.
makes the accessor usable through a trait. Today's answer differs per crate by accident rather
than by rule.
TypedMetadatatrait ingamut-metadatawould fix bothanswers by construction and let a caller write one function over every wired format — but it
also fixes them for every crate wired later, so it is worth choosing on purpose. It must stay
object-safe and C-portable per
AGENTS.md.This outlives any one pull request: it binds
gamut-png,gamut-webp,gamut-avifandgamut-tiffwhen they are wired (tracked by the #420 remainder).Evidence
crates/gamut-jpeg/src/metadata.rs,crates/gamut-jxl/src/decoder.rs,crates/gamut-dng/src/metadata.rs,crates/gamut-heic/src/image.rs.deliberately not taken there.
Refs #420.