Skip to content

feat(core)!: replace generic primitives with gamut re-exports, keep sensor types - #42

Merged
justin13888 merged 2 commits into
masterfrom
18-core-gamut-reexports
Jul 19, 2026
Merged

feat(core)!: replace generic primitives with gamut re-exports, keep sensor types#42
justin13888 merged 2 commits into
masterfrom
18-core-gamut-reexports

Conversation

@justin13888

Copy link
Copy Markdown
Collaborator

Closes #18.

Two commits: a pin bump (b08a1a2dde9f64, 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 typed ImageMetadata model, and URational/SRational.

Deleted Replaced by
Size gamut_core::Dimensions re-export. Struct literals preserve old infallible semantics at existing call sites; fallible Dimensions::new available where strictness is wanted. Rect composes Dimensions; manual serde (flat x/y/width/height) + a dimensions_serde with-module (gamut#257 gap).
pixel.rs (Sample/FromF32/Rgb<S>/Rgba<S> + aliases) gamut-core's sealed 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.
core BitDepth gamut_color::BitDepth re-export (identical variants; gamut#260 provided Sixteen). bit_depth_serde with-module; containing types hand-write Default.
ColorSpace ColorDescription — a CICP (H.273) code-point pair with consts SRGB, LINEAR_SRGB (working space, Default), DISPLAY_P3, REC2020, UNSPECIFIED; manual serde over the numeric code points.
core RgbImage new rawshift-image wrapper over ImageBuf<Rgb16> + ColorDescription + exposure/crop. data field → data()/data_mut().
MetadataExtractor ExtractMetadata (rename).

Upstream-first in action

The LINEAR_SRGB const is expressible only because TransferCharacteristics::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 to UNSPECIFIED by 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 RgbImage makes 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_size two-step — a window where dims and buffer disagreed — is replaced by atomic, validated replace_data. Misuse that used to produce silently inconsistent images is now a construction-time error.

Carve-out

IccProfile deletion 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/local BitDepth/pixel module/RgbImage.data field/MetadataExtractor are gone; RgbImage construction is fallible.

Verification Done

  • cargo test --workspace368 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), Rect serde round-trip, RgbImage length-invariant rejection, replace_data atomicity, bit_depth_serde rejection of unmodelled depths.
  • cargo clippy --workspace --all-targets -- -D warnings and cargo clippy -p rawshift-image --all-targets --features full -- -D warnings — both clean (the full run caught 4 feature-gated pixel_count stragglers; 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.
  • Migration coverage swept by four independent passes over disjoint file sets (formats / processing+transforms / encode+export+prelude / examples+tests+benches), each reporting per-file, followed by a central compile-and-fix loop; final grep confirms no Size, rawshift ColorSpace::, set_size, with_color_space, or MetadataExtractor references remain.

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.
@justin13888
justin13888 merged commit 7b33d76 into master Jul 19, 2026
10 of 11 checks passed
@justin13888
justin13888 deleted the 18-core-gamut-reexports branch July 19, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rawshift-core: replace generic primitives with gamut re-exports, keep sensor types

1 participant