PR-X2 Worker A: generalize aos_to_soa / soa_to_aos to <T, U, N, F>#168
Merged
Conversation
Worker A of PR-X2 (sequential, per .claude/knowledge/pr-x2-design.md
§ "Worker decomposition" line 458). Lifts the f32-only constraint that
W3-W6 shipped, so downstream consumers with u8/u16/u64/i8 SoA fields
(palette indices, BF16 carrier, CausalEdge64 mantissa, quantized
weights) can use the public surface instead of rolling their own
extract loop.
Signature change (Option C per design § "Migration path"):
// Pre-PR-X2:
pub fn aos_to_soa<T, const N: usize, F>(aos: &[T], extract: F)
-> SoaVec<f32, N>
where F: Fn(&T) -> [f32; N]
// After PR-X2 (this commit):
pub fn aos_to_soa<T, U, const N: usize, F>(aos: &[T], extract: F)
-> SoaVec<U, N>
where F: Fn(&T) -> [U; N]
`soa_to_aos` mirrors the same generalisation and adds a `U: Copy`
bound (needed to materialise the per-row `[U; N]` via
`core::array::from_fn`). `SoaVec<T, N>` itself was already generic over
`T` so no internal changes were needed — the constraint was
purely at the closure-helper signature layer.
Caller migration (callers using return-type inference are unaffected):
// Turbofish form gains one type param at position 2:
aos_to_soa::<_, 3, _>(&aos, …) // was
aos_to_soa::<_, _, 3, _>(&aos, …) // now (or `<_, f32, 3, _>` explicit)
Updated callers:
- src/hpc/soa.rs 4 inline test bodies (sed-rewrite)
- src/hpc/bulk.rs 1 module doctest + 1 inline test body
New tests in `src/hpc/soa.rs`:
- aos_to_soa_u64_round_trip — 3-field u64, full range incl. u64::MAX
- aos_to_soa_u8_round_trip — palette/alpha + soa_to_aos round-trip
- aos_to_soa_u16_round_trip — BF16 carrier + soa_to_aos round-trip
- aos_to_soa_inference_only — i8, no turbofish (closure ret-type)
Updated doctests on aos_to_soa + soa_to_aos cover f32 (back-compat),
u64 (CausalEdge64-style), and u8 (palette indices); module header
"Element-type scope" rewritten to record the lift + migration note.
Verified:
cargo test -p ndarray --lib hpc::soa 33 passed
cargo test --doc -p ndarray hpc::soa 13 passed
cargo fmt --check clean
cargo clippy --features approx,serde,rayon -- -D warnings clean
Out of scope (Worker B of PR-X2):
#[soa(pad_to_lanes=N)] field attribute on soa_struct! — separate
commit per design § "Worker decomposition".
4 tasks
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.
Summary
PR-X2 Worker A per
.claude/knowledge/pr-x2-design.md§ "Worker decomposition" line 458. Lifts the f32-only constraint onaos_to_soa/soa_to_aosthat W3-W6 shipped, so downstream consumers withu8/u16/u64/i8SoA fields (palette indices, BF16 carrier,CausalEdge64mantissa, quantized weights) can use the public surface instead of rolling their own extract loop.2 files, +183 / -42 vs
master.Signature change (Option C — change in place)
Per the design's recommended migration path:
soa_to_aosmirrors the same generalisation, adding aU: Copybound (needed to materialise a per-row[U; N]viacore::array::from_fn).SoaVec<T, N>itself was already generic — the constraint was purely at the closure-helper signature layer.Caller migration
Callers using return-type inference are unaffected.
Turbofish callers gain one type param at position 2:
In-tree turbofish callers updated this PR:
src/hpc/soa.rs— 4 inline test bodiessrc/hpc/bulk.rs— 1 module doctest + 1 inline test bodyNew tests
aos_to_soa_u64_round_trip— 3-fieldu64, full range incl.u64::MAXaos_to_soa_u8_round_trip— palette/alpha +soa_to_aosround-tripaos_to_soa_u16_round_trip— BF16 carrier +soa_to_aosround-tripaos_to_soa_inference_only—i8, no turbofish (closure ret-type annotation)Updated doctests on
aos_to_soacover f32 (back-compat), u64 (CausalEdge64-style), u8 (palette).soa_to_aosdoctests cover f32 + u16 (BF16). Module header "Element-type scope" rewritten to record the lift + migration note.Verified locally
cargo test -p ndarray --lib hpc::soa— 33 passedcargo test --doc -p ndarray hpc::soa— 13 passedcargo fmt --check— cleancargo clippy --features approx,serde,rayon -- -D warnings— cleanOut of scope (Worker B of PR-X2)
#[soa(pad_to_lanes=N)]field attribute onsoa_struct!— separate follow-up PR per design § "Worker decomposition" (depends on this generalisation landing first since the macro emitsaos_to_soa-shaped conversions).🤖 Generated with Claude Code
Generated by Claude Code