Skip to content

Conversation

@quinnj
Copy link
Member

@quinnj quinnj commented Jan 30, 2026

Summary

  • Adds a fixedsizearray trait to generalize the pre-allocate + setindex! array construction path (currently only used for ndims > 1 arrays) to any fixed-size array type
  • Adds a StaticArraysCore package extension that enables StructUtils.make for SVector, SMatrix, MVector, and other StaticArray types
  • Uses Memory{T} as the flat backing buffer on Julia 1.11+, with the existing growable path as fallback

Motivation

StructUtils.makearray assumes all 1D arrays are growable (push! into T(undef, 0)). This fails for StaticArrays which are fixed-size and immutable. The ndims > 1 path already uses a pre-allocate + setindex! approach — this PR generalizes that pattern.

Closes JuliaIO/JSON.jl#429

New public API

Function Purpose
fixedsizearray(::Type{T}) Trait: should T use the pre-allocate+fill path?
discover_dims(style, ::Type{T}, source) Type-based dimension discovery (avoids scanning source)
arrayfromdata(::Type{T}, mem, dims) Convert filled Memory buffer to target type T
FixedArrayClosure setindex!-based 1D fill closure (vs push!-based ArrayClosure)

How it works

For fixedsizearray types on Julia 1.11+:

  1. discover_dims gets dimensions (from type params for StaticArrays, source scan for regular Matrix)
  2. Memory{eltype(T)}(undef, prod(dims)) allocates a flat buffer
  3. 1D: FixedArrayClosure fills via linear setindex!; nD: MultiDimClosure fills via reshaped view
  4. arrayfromdata converts the filled Memory to the target type

The StaticArraysCore extension (3 methods):

  • fixedsizearray(::Type{<:StaticArray}) = true
  • discover_dims reads dimensions from type parameters (no source scanning)
  • arrayfromdata converts via T(Tuple(mem)) (StaticArrays' native representation)

Test plan

  • All existing StructUtils tests pass (Pkg.test())
  • New StaticArrays testset: SVector, SMatrix, MVector, nested Vector{SVector}
  • JSON.jl end-to-end: JSON.parse("[1,2,3]", SVector{3,Int}) works
  • JSON.jl full test suite (917 tests) passes with dev StructUtils
  • CI (Julia 1.9 fallback path, Julia 1.11+ Memory path)

🤖 Generated with Claude Code

quinnj and others added 3 commits January 29, 2026 23:37
Generalize the fixed-size array construction path so that any array
type that can't be grown via push! can be handled by pre-allocating a
Memory{T} buffer, filling it via setindex!, and converting to the
target type.

New public API:
- `fixedsizearray(::Type{T})`: trait for types needing pre-allocate+fill
- `discover_dims(style, ::Type{T}, source)`: type-based dimension discovery
- `arrayfromdata(::Type{T}, mem, dims)`: convert filled buffer to target type
- `FixedArrayClosure`: setindex!-based 1D fill closure

The StaticArraysCore extension overrides these to:
- Read dimensions from type parameters (no JSON scanning)
- Convert Memory to StaticArray via Tuple (native representation)

Closes JuliaIO/JSON.jl#429

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The arrayfromdata method uses Memory in its signature, which only
exists on Julia >= 1.11. Without the guard, the extension would fail
to precompile on older Julia versions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use Vector{ET} as the pre-allocated buffer on Julia < 1.11 where
Memory does not exist. Add arrayfromdata(::Type, ::Vector, ::Tuple)
methods in both the main module and the StaticArraysCore extension
so the fixed-size array path works on all supported Julia versions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

Enhance compatibility with StaticArrays.jl

1 participant