Main API:

FieldViews.FieldViewableType
FieldViewable(array::AbstractArray{T,N}) :: FieldViewable{T,N,Store}

Wrap an array to enable zero-copy field access via properties.

FieldViewable provides a view-like interface for accessing individual fields of structs stored in an array, without copying data. Field access returns FieldView objects that can be indexed and modified in-place, with changes reflected in the original array.

Examples

struct Point{T}
    x::T
    y::T
    z::T
end

points = [Point(1.0, 2.0, 3.0), Point(4.0, 5.0, 6.0)]
fv = FieldViewable(points)

# Access field views
fv.x  # Returns FieldView{:x, Float64, ...}
fv.x[1]  # Returns 1.0

# Modify in-place (modifies original array)
fv.x[1] = 10.0
points[1].x  # Now 10.0

# Take views
slice = view(fv, 1:1)
slice.y[1] = 99.0
points[1].y  # Now 99.0

Performance Note:

Getting and setting to FieldView vectors is most efficient when the following are satisfied:

  1. The underlying vector (e.g. arr) satisfies the IsStrided trait
  2. The eltype of the array (e.g. Data{Int}) is concrete and inline-allocated
  3. The type of the field (e.g. value::Int) is an isbitstype.

When all three of the above are satisfied, FieldViews can use efficient pointer methods to get and set fields in the array directly, otherwise we must use a slower fallback that loads the entire struct, modify it, and then sets the entire struct back into the array.

See also

  • FieldView: The view type returned by field property access
  • fieldmap: Customize field layout for nested structures
source
FieldViews.FieldViewType
FieldView{field}(parent::AbstractArray)

A view of a specific field across all elements in an array.

FieldView provides element-wise access to a single field of the structs in the parent array. For isbits fields and strided array containers, it uses efficient pointer methods for direct field access. For non-isbits fields, or non-strided arrays it uses a slower fallback which loads the full struct and extracts the field value.

Users typically obtain FieldView objects through property access on FieldViewable:

fv = FieldViewable(points)
x_view = fv.x  # Returns a FieldView{:x, ...}

Indexing

FieldView supports standard array indexing operations:

  • fv.x[i] - Get field value at index i
  • fv.x[i] = val - Set field value at index i (modifies parent array)

Examples

struct Data{T}
    value::T
    weight::Float64
end

arr = [Data(1, 0.5), Data(2, 1.5)]
fv = FieldViewable(arr)

# Access field view
values = fv.value  # FieldView{:value, Int64, ...}
values[1]  # 1

# Modify through view
fv.weight[2] = 2.0
arr[2].weight  # 2.0

Performance Note:

Getting and setting to FieldView vectors is most efficient when the following are satisfied:

  1. The underlying vector (e.g. arr) satisfies the IsStrided trait
  2. The eltype of the array (e.g. Data{Int}) is concrete and inline-allocated (i.e. not backed by a pointer)
  3. The type of the field (e.g. value::Int) is an isbitstype.

When all three of the above are satisfied, FieldViews can use efficient pointer methods to get and set fields in the array directly, otherwise we must use a slower fallback that loads the entire struct, modify it, and then sets the entire struct back into the array.

See also

  • FieldViewable: The view type returned by field property access
  • fieldmap: Customize field layout for nested structures
source

Adaptions for custom types:

FieldViews.fieldmapFunction
fieldmap(::Type{T}) :: Tuple

Define the field layout for type T to be used by FieldViews.

Add methods to this function to customize how FieldViews accesses fields in your types. This is essential for:

  • Flattening nested structures
  • Renaming fields
  • Exposing only certain fields

Default Behavior

By default, returns fieldnames(T), exposing all fields with their original names.

Return Value

A tuple where each element is one of:

  • Symbol or Int: Direct field access
  • Pair{Symbol,Symbol}: Nested field (e.g., :outer => :inner)
  • Pair{Symbol,Renamed}: Nested field with rename
  • Renamed: Renamed direct field

Examples

Flattening nested structures

struct MyType{T}
    x::T
    rest::@NamedTuple{a::Int, b::Int}
end

function FieldViews.fieldmap(::Type{MyType{T}}) where T
    (:x, :rest => :a, :rest => :b)
end

fv = FieldViewable([MyType(1.0, (a=1, b=2))])
fv.a[1]  # Access nested field directly, returns 1

Renaming fields

struct Foo
    data::@NamedTuple{_internal::Int}
end

function FieldViews.fieldmap(::Type{Foo})
    (:data => Renamed(:_internal, :public),)
end

fv = FieldViewable([Foo((_internal=42,))])
fv.public[1]  # Returns 42

See also

source
FieldViews.RenamedType
Renamed(actual::Union{Int,Symbol}, alias::Symbol)

Specify a field rename in custom field mappings.

Used within fieldmap definitions to expose an internal field under a different name. This is useful when you want to expose a given field using a different name, or access Tuple fields (since their fields are just integers).

Arguments

  • actual: The real field name or field index in the struct
  • alias: The name to expose in the FieldViewable interface

Examples

struct Foo
    data::@NamedTuple{_x::Int, _y::Int}
end

function FieldViews.fieldmap(::Type{Foo})
    (:data => Renamed(:_x, :x), :data => Renamed(:_y, :y))
end

fv = FieldViewable([Foo((_x=1, _y=2))])
fv.x[1]  # Access via alias 'x', returns 1

See also

  • fieldmap: Define custom field layouts using Renamed
source
FieldViews.StridedArrayTraitType
StridedArrayTrait(::Type{T}) :: StridedArrayTrait
StridedArrayTrait(x) :: StridedArrayTrait

Query or define whether an array type has strided memory layout.

Returns IsStrided() if the array has constant stride offsets in memory, or Unknown() otherwise. Arrays which support IsStrided() auotmatically get more efficient getindex/setindex! implementations for their isbits fields.

IsStrided arrays must support pointer(v, i) methods, and linear indexing.

Default Behavior

  • StridedArray types return IsStrided()
  • Other AbstractArray types return Unknown()

Extending Support

To opt into the strided interface for a custom array type:

FieldViews.StridedArrayTrait(::Type{<:MyArrayType}) = FieldViews.IsStrided()

Examples

StridedArrayTrait(Vector{Int})  # IsStrided()
StridedArrayTrait(view([1,2,3,4], 1:2:4))  # IsStrided()
StridedArrayTrait(view([1,2,3,4], [1,3,4]))  # Unknown() - non-contiguous indices

A strided array is one where elements are stored at fixed offsets from each other in memory. For example, [1, 2, 3, 4] is strided, as is view(v, 1:2:4) (every other element), but view(v, [1, 3, 4]) is not strided (arbitrary indices).

See also

source
FieldViews.IsStridedType
IsStrided <: StridedArrayTrait

Trait indicating that an array type has strided (constant offset) memory layout.

Used by FieldViews to dispatch on array types that support efficient field access through pointer arithmetic.

See also

source
FieldViews.UnknownType
Unknown <: StridedArrayTrait

Trait indicating that an array type's memory layout is unknown or non-strided.

For arrays with this trait, FieldViews will fall back on accessing/modifying field elements by loading/storing the entire containing struct, and then using FieldLens!! to manipulate and set the required field. This can be slower in some circumstances.

See also

source

Utility

FieldViews.FieldLens!!Type
FieldLens!!{field}

An optic for accessing and modifying a specific field of a struct.

FieldLens!! implements the lens interface from Accessors.jl, providing functional field access, immutable or mutable updates. It is primarily used internally by FieldViews for fallback field access/modification, but can also be used directly with the Accessors.jl API.

The !! in its name is a convention from BangBang.jl which signifies that it will mutate when possible, and perform out-of-place updates when mutation is not possible.

Constructor

FieldLens!!(field::Union{Symbol,Int})
FieldLens!!{field}()

Examples

struct Point{T}
    x::T
    y::T
end

lens = FieldLens!!{:x}()

p = Point(1, 2)
lens(p)  # Get: returns 1

using Accessors
set(p, lens, 10)  # Set: returns Point(10, 2)
mutable struct MPoint{T}
    x::T
    y::T
end

mp = MPoint(1, 2)
lens(mp)  # Get: returns 1

set(mp, lens, 10)  # Set: returns Point(10, 2)
lens(mp)           # Get: returns 10 now since we mutated the object

See also

  • Accessors.jl documentation for general lens usage
source

Info

FieldViews.can_use_fast_pathFunction
can_use_fast_path(::Type{<:FieldView}) :: Bool

Determine whether a FieldView type can use the optimized pointer-based access path.

Returns true if the FieldView can use efficient pointer arithmetic for direct memory access, or false if it must use the potentially slower fallback path that loads and reconstructs entire structs.

Fast Path Requirements

The fast path is used when ALL of the following conditions are met:

  1. Strided storage: The underlying array satisfies StridedArrayTrait(Store) == IsStrided()
  2. Concrete element type: The element type of the underlying storage is concrete
  3. Inline allocated element type: The element type of the underlying storage is not a pointer-backed type (i.e. Base.allocatedinline)
  4. Isbits field: The field being accessed is and isbitstype

When all conditions are met, FieldViews can compute the exact memory address of each field and read/write directly using unsafe_load/unsafe_store!.

Slow-Path Fallback

When any condition is not met, FieldViews uses a fallback that:

  • For immutable types: loads the struct, extracts/modifies the field, constructs a new struct
  • For mutable types: loads the struct, uses setfield! to modify in place

This is called "slow" only relative to pointer arithmetic—it still performs comparably to manual struct manipulation.

Even when can_use_fast_path returns false, FieldViews still provides correct and reasonably efficient access. The fast path is an optimization, not a requirement for correctness.

See Also

source

Dangerous tools

FieldViews.mappedfieldschemaFunction
mappedfieldschema(::Type{T}) -> NamedTuple

Compute the complete field schema for type T, computed using its fieldmap.

Returns a NamedTuple mapping field names (after renaming) to schema information containing:

  • lens: An optic for accessing the field
  • offset: Byte offset of the field in memory (for isbits fields)
  • type: The field's data type

This function processes the output of fieldmap to generate the internal schema used by FieldViews for efficient field access.

Examples

struct Point{T}
    x::T
    y::T
    z::T
end

schema = FieldViews.mappedfieldschema(Point{Float64})
# Returns: (x = (lens=..., offset=0, type=Float64),
#           y = (lens=..., offset=8, type=Float64),
#           z = (lens=..., offset=16, type=Float64))

schema.x.offset  # 0
schema.y.offset  # 8
schema.z.type    # Float64

Implementation Note

This is typically called internally by FieldViews and rarely needs to be called directly by users. Adding methods to mappedfieldschema incorrectly could cause undefined behaviour.

See also

  • fieldmap: The user-facing API for defining field layouts
source