API Reference

StructUtils.DefaultStyleType
StructUtils.DefaultStyle

Default struct style that all StructUtils.jl interface methods are defined for by default.

source
StructUtils.EarlyReturnType
StructUtils.EarlyReturn{T}

A wrapper type that can be used in function arguments to applyeach to short-circuit iteration and return a value from applyeach.

Example usage:

julia function find_needle_in_haystack(haystack, needle) ret = applyeach(haystack) do k, v k == needle && return StructUtils.EarlyReturn(v) end ret isa StructUtils.EarlyReturn && return ret.value throw(ArgumentError("needle not found in haystack") end`

source
StructUtils.StructStyleType
StructUtils.StructStyle

Abstract type that all concrete struct styles must subtype. Custom struct styles allow fine-grained control over various StructUtils.jl interface methods like fieldtags, fielddefaults, lift, lower, etc.

source
StructUtils.addkeyval!Function
StructUtils.addkeyval!(d, k, v)

Add a key-value pair to a dictionary-like object d. This function is called by StructUtils.make when d is dictlike. The default implementation is to call d[k] = v for AbstractDict.

source
StructUtils.applyeachFunction
StructUtils.applyeach(style, f, x) -> Union{StructUtils.EarlyReturn, Nothing}

A custom foreach-like function that operates specifically on (key, val) or (ind, val) pairs, and supports short-circuiting (via StructUtils.EarlyReturn). It also supports a StructStyle argument to allow for style-specific behavior for non-owned types.

For each key-value or index-value pair in x, call f(k, v). If f returns a StructUtils.EarlyReturn instance, applyeach should return the EarlyReturn immediately and stop iterating (i.e. short-circuit). Otherwise, the return value of f can be ignored and iteration continues.

Key types are generally expected to be Symbols, Strings, or Integers.

An example overload of applyeach for a generic iterable would be:

function StructUtils.applyeach(style::StructUtils.StructStyle, f, x::MyIterable)
    for (i, v) in enumerate(x)
        ret = f(StructUtils.lowerkey(style, i), StructUtils.lower(style, v))
        # if `f` returns EarlyReturn, return immediately
        ret isa StructUtils.EarlyReturn && return ret
    end
    return
end

Note that applyeach must include the style argument when overloading.

Also note that before applying f, the key or index is passed through StructUtils.lowerkey(style, k), and the value v is passed through StructUtils.lower(style, v).

If a value is #undef or otherwise not defined, the f function should generally be called with nothing or skipped.

source
StructUtils.arraylikeFunction

StructUtils.arraylike(x) -> Bool StructUtils.arraylike(::StructStyle, x) -> Bool StructUtils.arraylike(::StructStyle, ::Type{T}) -> Bool

Returns true if x or type T is array-like, false otherwise. This function is called by StructUtils.make to determine if T is array-like. The default implementation returns true for <:AbstractArray, <:AbstractSet, <:Tuple, <:Base.Generator, and <:Core.SimpleVector types, and false for <:AbstractArray{T,0}.

Once initialize is called, StructUtils.make will call push! to add values to the array-like object.

source
StructUtils.dictlikeFunction

StructUtils.dictlike(x) -> Bool StructUtils.dictlike(::StructStyle, x) -> Bool StructUtils.dictlike(::StructStyle, ::Type{T}) -> Bool

Returns true if x or type T is dictionary-like, false otherwise. When StructUtils.make(T, source) is called, if dictlike(T) is true, an instance will be initialized, and then addkeyval!ed for each key-value pair in source.

source
StructUtils.fielddefaultFunction
StructUtils.fielddefaults(::StructStyle, ::Type{T}) -> NamedTuple
StructUtils.fielddefault(::StructStyle, ::Type{T}, fieldname) -> NamedTuple

Returns a NamedTuple of field defaults for the struct T. Field defaults can be added manually by overloading fielddefaults, or included via convenient syntax using the StructUtils.jl macros: @tags, @noarg, @defaults, or @kwarg.

source
StructUtils.fielddefaultsFunction
StructUtils.fielddefaults(::StructStyle, ::Type{T}) -> NamedTuple
StructUtils.fielddefault(::StructStyle, ::Type{T}, fieldname) -> NamedTuple

Returns a NamedTuple of field defaults for the struct T. Field defaults can be added manually by overloading fielddefaults, or included via convenient syntax using the StructUtils.jl macros: @tags, @noarg, @defaults, or @kwarg.

source
StructUtils.fieldtagkeyFunction
StructUtils.fieldtagkey(::StructStyle) -> Symbol

Field tags defined on struct fields can be grouped by keys that are associated with a particular struct style. This function returns the key that should be used to retrieve field tags for a given struct style. By default, this function returns nothing. An example overload might look like:

struct MySQLStyle <: StructStyle end

StructUtils.fieldtagkey(::MySQLStyle) = :mysql

@tags struct Foo
    a::Int &(mysql=(name="foo_a",),)
    b::String
end

In this example, when StructUtils.make is called on Foo with the MySQLStyle style, only (name="foo_a",) will be retrieved from the field tags for a because the mysql key is associated with the MySQLStyle struct style. In other words, fieldtag keys allow custom struct styles to "namespace" field tags so structs can overload specific tags in multiple ways for different namespaces, i.e. a::Int &(mysql=(name="foo_a",), json=(name="json_a",)).

source
StructUtils.fieldtagsFunction
StructUtils.fieldtags(::StructStyle, ::Type{T}) -> NamedTuple
StructUtils.fieldtags(::StructStyle, ::Type{T}, fieldname) -> NamedTuple

Returns a NamedTuple of field tags for the struct T. Field tags can be added manually by overloading fieldtags, or included via convenient syntax using the StructUtils.jl macros: @tags, @noarg, @defaults, or @kwarg. Note this function returns the tags of all fields as a single NamedTuple.

source
StructUtils.initializeFunction
StructUtils.initialize(::StructStyle, T, source) -> T

In StructUtils.make, this function is called to initialize a new instance of T, when T is dictlike, arraylike, or noarg. The source is passed from the call to make, and can be used for initialization if appropriate. The default implementation of initialize is to call T() or T(undef, 0) for <:AbstractArray types.

source
StructUtils.kwargFunction

StructUtils.kwarg(x) -> Bool StructUtils.kwarg(::StructStyle, x) -> Bool StructUtils.kwarg(::StructStyle, ::Type{T}) -> Bool

Signals that x or type T can be constructed by passing struct fields as keyword arguments to the constructor, like t = T(field1=a, field2=b, ...). Automatically overloaded when structs use the StructUtils.@kwarg macro in their struct definition. The default value is false unless explicitly overloaded.

Note that StructUtils.@kwarg is a separate implementation of Base.@kwdef, yet should be a drop-in replacement for it.

source
StructUtils.liftFunction

StructUtils.lift(::Type{T}, x) -> T StructUtils.lift(::StructStyle, ::Type{T}, x) -> T

Lifts a value x to a type T. This function is called by StructUtils.make to lift unit/atom values to the appropriate type. The default implementation is the identity function for most types, but it also includes special cases for Symbol, Char, UUID, VersionNumber, Regex, and TimeType types to be constructed from strings. Allows transforming a "domain value" that may be some primitive representation into a more complex Julia type.

source
StructUtils.liftkeyFunction

StructUtils.liftkey(::Type{T}, x) -> x StructUtils.liftkey(style::StructStyle, ::Type{T}, x) -> x

Allows customizing how a key is lifted before being passed to addkeyval! in dictlike construction.

By default, calls StructUtils.lift.

Example

struct Point
    x::Int; y::Int
end

# lift a Point from a string value
StructUtils.liftkey(::StructUtils.StructStyle, x::String) = Point(parse(Int, split(x, "_")[1]), parse(Int, split(x, "_")[2]))

d = Dict("1_2" => 99)
StructUtils.make(Dict{Point, Int}, Dict("1_2" => 99))
# Dict{Point, Int} with 1 entry:
#   Point(1, 2) => 99

For loss-less round-tripping also provide a StructUtils.lowerkey overload to "lower" the key.

source
StructUtils.lowerFunction

StructUtils.lower(x) -> x StructUtils.lower(::StructStyle, x) -> x

Domain value transformation function. This function is called by StructUtils.applyeach on each value in the source object before calling the apply function. By default, lower is the identity function. This allows a domain transformation of values according to the style used.

source
StructUtils.lowerkeyMethod

StructUtils.lowerkey(x) -> x StructUtils.lowerkey(style::StructUtils.StructStyle, x) -> x

Allows customizing how a value is lowered when used specifically as a key. By default, calls StructUtils.lower. Called from StructUtils.applyeach on the key or index before passed to the key-value function.

Example

struct Point
    x::Int; y::Int
end

# lower a Point as a single string value
StructUtils.lowerkey(::StructUtils.StructStyle, p::Point) = "$(p.x)_$(p.y)"

d = Dict(Point(1, 2) => 99)

StructUtils.make(Dict{String, Dict{String, Point}}, Dict(Point(1, 2) => Dict(Point(3, 4) => Point(5, 6))))
# Dict{String, Dict{String, Point}} with 1 entry:
#   "1_2" => Dict("3_4"=>Point(5, 6))

For loss-less round-tripping also provide a StructUtils.liftkey overload to "lift" the key back.

source
StructUtils.makeFunction
StructUtils.make(T, source) -> T
StructUtils.make(T, source, style) -> T
StructUtils.make!(f, style, T, source)
StructUtils.make!(style, x::T, source)

Construct a struct of type T from source using the given style. The source can be any type of object, and the style can be any StructStyle subtype (default StructUtils.DefaultStyle()).

make will use any knowledge of noarg, arraylike, or dictlike in order to determine how to construct an instance of T. The fallback for structs is to rely on the automatic "all argument" constructor that structs have defined by default (e.g. T(fields...)).

make calls applyeach on the source object, where the key-value pairs from source will be used in constructing T.

The 3rd definition above allows passing in an "applicator" function that is applied to the constructed struct. This is useful when the initial T is abstract or a union type and a choosetype field tag or other StructUtils.make definition is used to determine the concrete runtime type to construct.

The 4th definition allows passing in an already-constructed instance of T (x), which must be mutable, and source key-value pairs will be applied as to x as source keys are matched to struct field names.

For structs, fieldtags will be accounted for and certain tags can be used to influence the construction of the struct.

source
StructUtils.make!Function
StructUtils.make(T, source) -> T
StructUtils.make(T, source, style) -> T
StructUtils.make!(f, style, T, source)
StructUtils.make!(style, x::T, source)

Construct a struct of type T from source using the given style. The source can be any type of object, and the style can be any StructStyle subtype (default StructUtils.DefaultStyle()).

make will use any knowledge of noarg, arraylike, or dictlike in order to determine how to construct an instance of T. The fallback for structs is to rely on the automatic "all argument" constructor that structs have defined by default (e.g. T(fields...)).

make calls applyeach on the source object, where the key-value pairs from source will be used in constructing T.

The 3rd definition above allows passing in an "applicator" function that is applied to the constructed struct. This is useful when the initial T is abstract or a union type and a choosetype field tag or other StructUtils.make definition is used to determine the concrete runtime type to construct.

The 4th definition allows passing in an already-constructed instance of T (x), which must be mutable, and source key-value pairs will be applied as to x as source keys are matched to struct field names.

For structs, fieldtags will be accounted for and certain tags can be used to influence the construction of the struct.

source
StructUtils.noargFunction

StructUtils.noarg(x) -> Bool StructUtils.noarg(::StructStyle, x) -> Bool StructUtils.noarg(::StructStyle, ::Type{T}) -> Bool

Signals that x or type T is a mutable type that can be constructed by calling an empty constructor, like t = T(). Automatically overloaded when structs use the @noarg macro in their struct definition. The default value is false unless explicitly overloaded.

source
StructUtils.nulllikeFunction

StructUtils.nulllike(x) -> Bool StructUtils.nulllike(::StructStyle, x) -> Bool StructUtils.nulllike(::StructStyle, ::Type{T}) -> Bool

Returns true if x or type T is null-like, false otherwise. This function is mainly used in the make! implementation to determine if a Union type can be narrowed by excluding nulllike types like Nothing and Missing.

source
StructUtils.reset!Method

StructUtils.reset!(x::T)

If T was defined with default values via @defaults, @tags, @kwarg, or @noarg, reset! will reset the fields of x to their default values. T must be a mutable struct type.

source
StructUtils.structlikeFunction

StructUtils.structlike(x) -> Bool StructUtils.structlike(::StructStyle, x) -> Bool StructUtils.structlike(::StructStyle, ::Type{T}) -> Bool

Returns true if x or type T is struct-like, false otherwise. This function is called by StructUtils.make to determine if T is struct-like. The default implementation returns true for isstructtype(T) and !Base.issingletontype(T).

structlike structs are expected to be able to be constructed by the default constructor like T(field1, field2, ...).

Due to how StructUtils.make works, structlike is often overloaded to false by "unit"/"atom" types where fields should be considered private to the make process and should instead attempt to lift the source object into the unit type.

source
StructUtils.@choosetypeMacro
StructUtils.@choosetype T func
StructUtils.@choosetype style T func

Convenience macro for defining a StructUtils.make! overload for an abstract type T where func is a function that "chooses" a concrete type S at runtime. func can be one of two forms:

  • source -> S
  • (source, tags) -> S)

That is, it either takes just the source object that is passed to make and must choose a concrete type S, or it can take both the source and a set of fieldtags that may be present for the field of a type being "made".

The 2nd definition also takes a style argument, allowing for overloads of non-owned types T.

Example:

abstract type Vehicle end

struct Car <: Vehicle
    make::String
    model::String
    seatingCapacity::Int
    topSpeed::Float64
end

struct Truck <: Vehicle
    make::String
    model::String
    payloadCapacity::Float64
end

StructUtils.@choosetype Vehicle x -> x["type"] == "car" ? Car : x["type"] == "truck" ? Truck : throw(ArgumentError("Unknown vehicle type: $(x["type"])"))

x = StructUtils.make(Vehicle, Dict("type" => "car", "make" => "Toyota", "model" => "Corolla", "seatingCapacity" => 4, "topSpeed" => 120.5))
@test x == Car("Toyota", "Corolla", 4, 120.5)
source
StructUtils.@defaultsMacro
@defaults struct T
    ...
end

Macro to enhance a struct definition by automatically generating an outer constructor with default values for trailing fields. The generated constructor will accept arguments for non-default fields and pass default values to the inner constructor. StructUtils.fielddefaults trait is also overridden to return a NamedTuple of default values for the struct type.

The @noarg, @kwarg, @defaults, and @tags macros all support specifying "field tags" for each field in a struct. Field tags are a NamedTuple prefixed by & and are a way to attach metadata to a field. The field tags are accessible via the StructUtils.fieldtags function, and certain field tags are used by the StructUtils.make function to control how fields are constructed, including:

  • dateformat: a DateFormat object to use when parsing or formatting a Dates.TimeType field
  • lower: a function to apply to a field when applyeach is called on a struct
  • lift: a function to apply to a field when StructUtils.make is called on a struct
  • ignore: a Bool to indicate if a field should be skipped/ignored when applyeach or make is called
  • name: a Symbol to be used instead of a defined field name in applyeach or used to match a field in make
  • choosetype: a function to apply to a field when StructUtils.make is called to determine the concrete type of an abstract or Union typed field

For example, the following struct definition includes a field with a dateformat tag:

@tags struct MyStruct
    date::Date &(dateformat=dateformat"yyyy-mm-dd",)
end

Example

@defaults struct Foo
    a::Int
    b::String = "foo"
    c::Float64 = 1.0
    d::Vector{Int} = [1, 2, 3]
end

In the above example, the @defaults macro generates the following outer constructor:

function Foo(a)
    return Foo(a, "foo", 1.0, [1, 2, 3])
end
source
StructUtils.@kwargMacro
@kwarg struct T
    ...
end

Macro to enhance a struct definition by automatically generating a keyword argument constructor. Default values can be specified for fields, which will be set in the generated constructor. StructUtils.kwarg trait is also overridden to return true for the struct type. This allows structs to easily participate in programmatic construction via StructUtils.make.

The @noarg, @kwarg, @defaults, and @tags macros all support specifying "field tags" for each field in a struct. Field tags are a NamedTuple prefixed by & and are a way to attach metadata to a field. The field tags are accessible via the StructUtils.fieldtags function, and certain field tags are used by the StructUtils.make function to control how fields are constructed, including:

  • dateformat: a DateFormat object to use when parsing or formatting a Dates.TimeType field
  • lower: a function to apply to a field when applyeach is called on a struct
  • lift: a function to apply to a field when StructUtils.make is called on a struct
  • ignore: a Bool to indicate if a field should be skipped/ignored when applyeach or make is called
  • name: a Symbol to be used instead of a defined field name in applyeach or used to match a field in make
  • choosetype: a function to apply to a field when StructUtils.make is called to determine the concrete type of an abstract or Union typed field

For example, the following struct definition includes a field with a dateformat tag:

@tags struct MyStruct
    date::Date &(dateformat=dateformat"yyyy-mm-dd",)
end

Example

@kwarg struct Foo
    a::Int
    b::String = "foo"
    c::Float64 = 1.0
    d::Vector{Int} = [1, 2, 3]
end

In the above example, the @kwarg macro generates the following inner constructor:

function Foo(; a, b="foo", c=1.0, d=[1, 2, 3])
    return Foo(a, b, c, d)
end
source
StructUtils.@noargMacro
@noarg mutable struct T
    ...
end

Macro to enhance a mutable struct definition by automatically generating an empty or "no-argument" constructor. Similar to the @kwarg macro, default values can be specified for fields, which will be set in the generated constructor. StructUtils.noarg trait is also overridden to return true for the struct type. This allows structs to easily participate in programmatic construction via StructUtils.make.

Note that const fields are currently not allowed in @noarg structs.

The @noarg, @kwarg, @defaults, and @tags macros all support specifying "field tags" for each field in a struct. Field tags are a NamedTuple prefixed by & and are a way to attach metadata to a field. The field tags are accessible via the StructUtils.fieldtags function, and certain field tags are used by the StructUtils.make function to control how fields are constructed, including:

  • dateformat: a DateFormat object to use when parsing or formatting a Dates.TimeType field
  • lower: a function to apply to a field when applyeach is called on a struct
  • lift: a function to apply to a field when StructUtils.make is called on a struct
  • ignore: a Bool to indicate if a field should be skipped/ignored when applyeach or make is called
  • name: a Symbol to be used instead of a defined field name in applyeach or used to match a field in make
  • choosetype: a function to apply to a field when StructUtils.make is called to determine the concrete type of an abstract or Union typed field

For example, the following struct definition includes a field with a dateformat tag:

@tags struct MyStruct
    date::Date &(dateformat=dateformat"yyyy-mm-dd",)
end

Example

@noarg mutable struct Foo
    a::Int
    b::String
    c::Float64 = 1.0
    d::Vector{Int} = [1, 2, 3]
end

In the above example, the @noarg macro generates the following inner constructor:

function Foo()
    x = new()
    x.c = 1.0
    x.d = [1, 2, 3]
    return x
end
source
StructUtils.@tagsMacro
@tags struct T
    ...
end

Macro to enhance a struct definition by allowing field tags to be specified for each field.

The @noarg, @kwarg, @defaults, and @tags macros all support specifying "field tags" for each field in a struct. Field tags are a NamedTuple prefixed by & and are a way to attach metadata to a field. The field tags are accessible via the StructUtils.fieldtags function, and certain field tags are used by the StructUtils.make function to control how fields are constructed, including:

  • dateformat: a DateFormat object to use when parsing or formatting a Dates.TimeType field
  • lower: a function to apply to a field when applyeach is called on a struct
  • lift: a function to apply to a field when StructUtils.make is called on a struct
  • ignore: a Bool to indicate if a field should be skipped/ignored when applyeach or make is called
  • name: a Symbol to be used instead of a defined field name in applyeach or used to match a field in make
  • choosetype: a function to apply to a field when StructUtils.make is called to determine the concrete type of an abstract or Union typed field

For example, the following struct definition includes a field with a dateformat tag:

@tags struct MyStruct
    date::Date &(dateformat=dateformat"yyyy-mm-dd",)
end
source
StructUtils.SelectorsModule
Selection syntax

Special "selection syntax" is provided that allows easy querying of objects/arrays that implement StructUtils.applyeach using a syntax similar to XPath or CSS selectors, applied using common Julia syntax.

This syntax mainly uses various forms of getindex to select elements of an object or array. Supported syntax includes:

  • x["key"] / x.key / x[:key] / x[1] - select the value associated for a key in object x (key can be a String, Symbol, or Integer for an array)
  • x[:] - select all values in object or array x, returned as a Selectors.List, which is a custom array type that supports the selection syntax
  • x.key - when x is a List, select the value for key in each element of the List (like a broadcasted getindex)
  • x[~, key] - recursively select all values in object or array x that have key
  • x[~, :] - recursively select all values in object or array x, returned as a flattened List
  • x[:, (k, v) -> Bool] - apply a key-value function f to each key-value/index-value in object or array x, and return a List of all values for which f returns true
source