colconv 0.1.0

SIMD-dispatched color-conversion kernels covering the FFmpeg AVPixelFormat space, with a Sink-based API so consumers pick which derived outputs (RGB / Luma / HSV / custom) they want without paying for the ones they don't.
Documentation
name: coverage

on:
  push:
    branches:
      - main
    paths-ignore:
      - 'README.md'
      - 'COPYRIGHT'
      - 'LICENSE'
      - '**.md'
      - '**.txt'
      - 'art'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'COPYRIGHT'
      - 'LICENSE'
      - '**.md'
      - '**.txt'
      - 'art'
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always

# Matrix dimensions that must be covered for Codecov to reflect the full
# SIMD tier cascade:
#
# - aarch64 NEON (macOS): covers src/row/arch/neon.rs plus the
#   `neon_available()` branch of the dispatcher.
# - aarch64 scalar-forced: covers the scalar fallback branch of the
#   dispatcher on aarch64 (reached only when `colconv_force_scalar` is
#   set, since NEON is mandatory otherwise).
# - x86_64 default (Linux): covers whichever top tier the runner CPU
#   supports (AVX-512BW on Ice/Cascade Lake Azure VMs, else AVX2). Per-
#   tier kernels are reached by the in-kernel equivalence tests that
#   self-gate on `is_x86_feature_detected!`.
# - x86_64 AVX2-max: `--cfg colconv_disable_avx512` forces the AVX2
#   dispatcher branch to run regardless of runner CPU. Covers the AVX2
#   branch on runners that would otherwise always pick AVX-512.
# - x86_64 SSE4.1-max: `--cfg colconv_disable_avx512 --cfg
#   colconv_disable_avx2` forces the SSE4.1 dispatcher branch.
# - x86_64 scalar-forced: `--cfg colconv_force_scalar` forces the scalar
#   dispatcher branch on x86_64.
# - x86_64 Windows: validates the MSVC toolchain compiles the intrinsic-
#   heavy modules and reports coverage of their default runtime path.
#
# Coverage is collected with `cargo-llvm-cov` — LLVM source-based
# instrumentation (compile-time `-C instrument-coverage`, runtime
# `profraw` profile dump). One engine across every host (macOS,
# Linux, Windows) so the per-platform numbers compose uniformly when
# Codecov merges them.
#
# Each platform excludes the SIMD files it *cannot* compile (gated
# behind `#[cfg(target_arch)]`) via `--ignore-filename-regex`. Without
# exclusion those files would show as 0/N uncovered, dragging the
# per-platform number down. After Codecov merges, every arch file
# is covered by its native host.

jobs:
  coverage:
    name: coverage (${{ matrix.label }})
    strategy:
      matrix:
        include:
          # ---- aarch64 (macOS) ----
          - os: macos-latest
            label: macos-aarch64
            rustflags: ''
            sde_cpu: ''
            ignore_regex: 'src/.*arch/x86_|src/.*arch/wasm_'
          - os: macos-latest
            label: macos-aarch64-scalar
            rustflags: '--cfg colconv_force_scalar'
            sde_cpu: ''
            ignore_regex: 'src/.*arch/x86_|src/.*arch/wasm_'

          # ---- x86_64 (Linux) ----
          # Standard ubuntu-latest is AMD EPYC Milan — has AVX2 but no
          # AVX-512. The default tier exercises whichever top tier the
          # runner supports at runtime (AVX2 in practice). For AVX-512
          # coverage we run cargo-llvm-cov under Intel SDE (`sde-avx512` tier
          # below) since no free GitHub runner has the hardware.
          - os: ubuntu-latest
            label: linux-x86_64
            rustflags: ''
            sde_cpu: ''
            ignore_regex: 'src/.*arch/neon|src/.*arch/wasm_'
          - os: ubuntu-latest
            label: linux-x86_64-avx2-max
            rustflags: '--cfg colconv_disable_avx512'
            sde_cpu: ''
            ignore_regex: 'src/.*arch/neon|src/.*arch/wasm_'
          - os: ubuntu-latest
            label: linux-x86_64-sse41-max
            rustflags: '--cfg colconv_disable_avx512 --cfg colconv_disable_avx2'
            sde_cpu: ''
            ignore_regex: 'src/.*arch/neon|src/.*arch/wasm_'
          - os: ubuntu-latest
            label: linux-x86_64-scalar
            rustflags: '--cfg colconv_force_scalar'
            sde_cpu: ''
            ignore_regex: 'src/.*arch/neon|src/.*arch/wasm_'

          # SDE-based tiers — emulated Intel CPUs covering kernels that
          # the AMD Milan runner can't reach natively. cargo-llvm-cov
          # produces a self-contained instrumented binary that runs
          # cleanly under SDE via the cargo target-runner env var.
          # Slower than native (~5-10x) but still well within free-
          # runner budget.
          #
          # `-icx` = Ice Lake (Server) — AVX-512BW, AVX-512VL, AVX-512F,
          # AVX-512DQ. Covers every AVX-512 kernel + its dispatcher branch.
          - os: ubuntu-latest
            label: linux-x86_64-sde-avx512
            rustflags: ''
            sde_cpu: 'icx'
            ignore_regex: 'src/.*arch/neon|src/.*arch/wasm_'
          # `-skx` = Skylake (Server). Wait — Skylake server does have
          # AVX-512. Use `-skl` = Skylake (Client / 6th-gen Core), which
          # is AVX2-max (no AVX-512), to lock the AVX2 kernel in on a
          # deterministic Intel core (vs the AMD-native default tier).
          - os: ubuntu-latest
            label: linux-x86_64-sde-avx2
            rustflags: ''
            sde_cpu: 'skl'
            ignore_regex: 'src/.*arch/neon|src/.*arch/wasm_'

          # ---- x86_64 (Windows) ----
          - os: windows-latest
            label: windows-x86_64
            rustflags: ''
            sde_cpu: ''
            ignore_regex: 'src/.*arch/neon|src/.*arch/wasm_'
    runs-on: ${{ matrix.os }}
    env:
      RUSTFLAGS: ${{ matrix.rustflags }}
    steps:
      - uses: actions/checkout@v6

      - name: Install Rust
        run: |
          rustup update stable --no-self-update
          rustup default stable
          rustup component add llvm-tools-preview

      - name: Install cargo-llvm-cov
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-llvm-cov

      - name: Install Intel SDE
        if: matrix.sde_cpu != ''
        # v5.0: own-repo Release LFS binaries instead of Intel CDN
        # (fixes HTTP 202 flakes). `sdeVersion` omitted → action's
        # bundled default (its tested-latest within this major).
        uses: petarpetrovt/setup-sde@v5.0
        with:
          environmentVariableName: SDE_PATH

      - name: Generate coverage
        shell: bash
        # SDE tiers route the test binary through `sde64 -<cpu> --`
        # via the cargo target-runner env var. cargo-llvm-cov's
        # instrumentation is baked into the binary at compile time
        # via `-C instrument-coverage`, so there's no runtime engine
        # to fight with SDE.
        run: |
          mkdir -p coverage
          if [ -n "${{ matrix.sde_cpu }}" ]; then
            export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="$SDE_PATH/sde64 -${{ matrix.sde_cpu }} --"
          fi
          cargo llvm-cov \
            --all-features \
            --workspace \
            --ignore-filename-regex '${{ matrix.ignore_regex }}' \
            --cobertura \
            --output-path coverage/cobertura.xml
        continue-on-error: false

      - name: Upload coverage artifact
        uses: actions/upload-artifact@v7
        with:
          name: coverage-${{ matrix.label }}
          path: coverage/cobertura.xml

  upload-codecov:
    name: Upload merged coverage to Codecov
    needs: coverage
    runs-on: ubuntu-latest
    if: always()
    strategy:
      fail-fast: false
      matrix:
        label:
          - macos-aarch64
          - macos-aarch64-scalar
          - linux-x86_64
          - linux-x86_64-avx2-max
          - linux-x86_64-sse41-max
          - linux-x86_64-scalar
          - linux-x86_64-sde-avx512
          - linux-x86_64-sde-avx2
          - windows-x86_64
    steps:
      - uses: actions/checkout@v6

      - name: Download ${{ matrix.label }} report
        uses: actions/download-artifact@v8
        with:
          name: coverage-${{ matrix.label }}
          path: coverage/

      - name: Upload ${{ matrix.label }} to Codecov
        uses: codecov/codecov-action@v6
        with:
          files: coverage/cobertura.xml
          flags: ${{ matrix.label }}
          fail_ci_if_error: true
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}