feat(core)!: replace generic primitives with gamut re-exports, keep sensor types - #42
Merged
Conversation
Picks up visualcommons/gamut#295 (TransferCharacteristics::Linear, CICP code point 8, plus SourceTransfer::Linear and SourceProfile::LINEAR_SRGB), landed via visualcommons/gamut#297. This is the gate for the ColorDescription slice of the core-primitives migration: the linear-sRGB working space is now expressible as a CICP pair. Per the README pin-bump procedure: this commit only moves the hash (plus Cargo.lock). Full workspace test run passes (345 tests). Benchmarks are unaffected and were not re-baselined: at this commit no rawshift code path consumes gamut yet (gamut-core is dependency-wired only), so the bump cannot change rawshift behaviour. No CHANGELOG entry for the same reason.
…ensor types
rawshift-core now re-exports gamut's generic image vocabulary instead of
defining its own, keeping only what gamut deliberately does not model: the
sensor set (RawImage + builder, CfaPattern, XTransPattern,
white_level_from_bit_depth), codec descriptors, the typed ImageMetadata model,
and URational/SRational.
Deleted -> replaced:
- `Size` -> `gamut_core::Dimensions` re-export. Construction rule: struct
literals preserve the old infallible zero-permitting semantics at existing
call sites; `Dimensions::new` (fallible, rejects zero) is available where
strictness is wanted. `Rect` now composes `Dimensions` with hand-written
serde (four flat integers) since gamut has no serde yet (gamut#257); a
`dimensions_serde` with-module serves downstream struct fields.
- `pixel.rs` (Sample/FromF32/Rgb<S>/Rgba<S> + aliases) -> gamut-core's sealed
`Pixel`/`Sample` traits and marker types (Rgb16, Rgba8, ...), plus
ImageBuf/ImageRef/PixelFormat/ColorModel. The old module was confirmed dead:
zero call sites beyond a prelude re-export. f32 stays transform-internal —
gamut's Sample is sealed over u8/u16 and rawshift adds no pixel formats.
- `BitDepth` -> `gamut_color::BitDepth` re-export (variants and semantics are
identical; gamut#260 provided Sixteen). It is #[non_exhaustive] and carries
no Default/serde upstream, so a `bit_depth_serde` with-module covers wire
use and containing types hand-write their Defaults.
- `ColorSpace` -> new `ColorDescription`, a CICP (H.273) code-point pair with
consts SRGB, LINEAR_SRGB (working space, Default), DISPLAY_P3, REC2020, and
UNSPECIFIED. LINEAR_SRGB is expressible because gamut#295 added
TransferCharacteristics::Linear (code point 8) — found missing during this
migration, filed, and landed first per the upstream-first policy.
ICC-authoritative spaces (Adobe RGB, ProPhoto RGB) map to UNSPECIFIED: the
pair never lies about the samples, and the preserved ICC profile is the
authority. Manual serde uses the numeric code points as the wire form. The
old enum's wide-gamut variants were never constructed anywhere, so no
behaviour changes.
- Core `RgbImage` -> new wrapper in rawshift-image over
`gamut_core::ImageBuf<Rgb16>` carrying ColorDescription + baseline exposure
+ default crop. The public `data` field becomes `data()`/`data_mut()`, and
the buffer length invariant (len == w*h*3) is enforced at every
construction: `new`/`with_color` are fallible, and the mutate-then-set_size
two-step is replaced by an atomic validated `replace_data`. Misuse that
previously produced silently inconsistent images is now a compile- or
construction-time error.
- `MetadataExtractor` -> `ExtractMetadata` (rename, same contract).
New error surface: `RawError::Gamut { context, source }` wraps
`gamut_core::Error` with the rawshift operation name (context stays ours until
gamut#254 lands structured diagnostics).
Carve-out: the `IccProfile` deletion rides with the metadata migration (#19).
gamut-icc has no sRGB-profile synthesis helper, and the type is fully
entangled with the img-parts embed paths #19 replaces wholesale — removing it
here would create the dual path the epic forbids.
All ~49 files of call sites across formats/, processing/, transforms/,
codecs/, examples/, tests/, and benches migrated. Behavioural parity is
preserved throughout: infallible construction sites keep their semantics via
struct literals, and fallible RgbImage construction is `?`-propagated in
Result contexts or `.expect`ed where the buffer is correct by construction.
BREAKING CHANGE: 0.x break, accepted by the epic. Size/ColorSpace/BitDepth
(local)/pixel module/RgbImage.data field/MetadataExtractor are gone from the
public API; RgbImage construction is fallible.
This was referenced Jul 18, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #18.
Two commits: a pin bump (
b08a1a2→dde9f64, per the documented procedure — hash-only commit, full test run) and the core-primitives migration.What is Delivered
rawshift-core now re-exports gamut's generic image vocabulary and keeps only what gamut deliberately does not model: the sensor set (
RawImage+builder,CfaPattern,XTransPattern,white_level_from_bit_depth), codec descriptors, the typedImageMetadatamodel, andURational/SRational.Sizegamut_core::Dimensionsre-export. Struct literals preserve old infallible semantics at existing call sites; fallibleDimensions::newavailable where strictness is wanted.RectcomposesDimensions; manual serde (flat x/y/width/height) + adimensions_serdewith-module (gamut#257 gap).pixel.rs(Sample/FromF32/Rgb<S>/Rgba<S>+ aliases)Pixel/Sample+ markers (Rgb16,Rgba8, …),ImageBuf/ImageRef/PixelFormat/ColorModel. Old module was dead code — zero call sites beyond a prelude re-export. f32 stays transform-internal.BitDepthgamut_color::BitDepthre-export (identical variants; gamut#260 providedSixteen).bit_depth_serdewith-module; containing types hand-writeDefault.ColorSpaceColorDescription— a CICP (H.273) code-point pair with constsSRGB,LINEAR_SRGB(working space,Default),DISPLAY_P3,REC2020,UNSPECIFIED; manual serde over the numeric code points.RgbImageImageBuf<Rgb16>+ColorDescription+ exposure/crop.datafield →data()/data_mut().MetadataExtractorExtractMetadata(rename).Upstream-first in action
The
LINEAR_SRGBconst is expressible only becauseTransferCharacteristics::Linear(code point 8) was missing from gamut — found during this migration's audit, filed as gamut#295, landed via gamut#297, pin bumped, then this change was written. No workaround, no shim. Adobe RGB / ProPhoto map toUNSPECIFIEDby design: the CICP pair never lies about the samples; the preserved ICC profile is the authority. (The old enum's wide-gamut variants were never constructed anywhere — verified — so no behaviour changes.)Structural strictness
The new
RgbImagemakes the length invariant (data.len() == w*h*3) unrepresentable-when-broken: constructors are fallible (RawError::Gamut { context, source }, new variant per the V1 error model), and the old mutate-data-then-set_sizetwo-step — a window where dims and buffer disagreed — is replaced by atomic, validatedreplace_data. Misuse that used to produce silently inconsistent images is now a construction-time error.Carve-out
IccProfiledeletion rides with #19: gamut-icc has no sRGB-profile synthesis helper, and the type is fully entangled with the img-parts embed paths #19 replaces wholesale. Removing it here would create the dual path the epic forbids. Noted on both issues.Breaking (0.x, accepted by the epic)
Size/ColorSpace/localBitDepth/pixelmodule/RgbImage.datafield/MetadataExtractorare gone;RgbImageconstruction is fallible.Verification Done
cargo test --workspace— 368 passed, 0 failed (fixture-gated tests ignored as usual).cargo test -p rawshift-image --features serde— 350 passed;cargo test -p rawshift-core/--features serde— 18 / 22 passed, including new tests: CICP code-point round-trips, serde wire-format assertions ({"primaries":1,"transfer":8}for the working space),Rectserde round-trip,RgbImagelength-invariant rejection,replace_dataatomicity,bit_depth_serderejection of unmodelled depths.cargo clippy --workspace --all-targets -- -D warningsandcargo clippy -p rawshift-image --all-targets --features full -- -D warnings— both clean (thefullrun caught 4 feature-gatedpixel_countstragglers; fixed).RUSTDOCFLAGS="-D warnings" cargo doc --no-deps -p rawshift-core --features serde— clean.cargo build -p rawshift(facade) — clean.cargo fmt+ lefthook pre-commit — green.Size, rawshiftColorSpace::,set_size,with_color_space, orMetadataExtractorreferences remain.