API Reference
StructUtils.DefaultStyle
— TypeStructUtils.DefaultStyle
Default struct style that all StructUtils.jl interface methods are defined for by default.
StructUtils.EarlyReturn
— TypeStructUtils.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
`
StructUtils.StructStyle
— TypeStructUtils.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.
StructUtils.addkeyval!
— FunctionStructUtils.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
.
StructUtils.applyeach
— FunctionStructUtils.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.
StructUtils.arraylike
— FunctionStructUtils.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.
StructUtils.dictlike
— FunctionStructUtils.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 initialize
d, and then addkeyval!
ed for each key-value pair in source
.
StructUtils.fielddefault
— FunctionStructUtils.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
.
StructUtils.fielddefaults
— FunctionStructUtils.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
.
StructUtils.fieldtagkey
— FunctionStructUtils.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",))
.
StructUtils.fieldtags
— FunctionStructUtils.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.
StructUtils.initialize
— FunctionStructUtils.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.
StructUtils.kwarg
— FunctionStructUtils.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.
StructUtils.lift
— FunctionStructUtils.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.
StructUtils.liftkey
— FunctionStructUtils.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.
StructUtils.lower
— FunctionStructUtils.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.
StructUtils.lowerkey
— MethodStructUtils.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.
StructUtils.make
— FunctionStructUtils.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.
StructUtils.make!
— FunctionStructUtils.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.
StructUtils.noarg
— FunctionStructUtils.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.
StructUtils.nulllike
— FunctionStructUtils.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
.
StructUtils.reset!
— MethodStructUtils.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.
StructUtils.structlike
— FunctionStructUtils.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.
StructUtils.@choosetype
— MacroStructUtils.@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)
StructUtils.@defaults
— Macro@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
: aDateFormat
object to use when parsing or formatting aDates.TimeType
fieldlower
: a function to apply to a field whenapplyeach
is called on a structlift
: a function to apply to a field whenStructUtils.make
is called on a structignore
: aBool
to indicate if a field should be skipped/ignored whenapplyeach
ormake
is calledname
: aSymbol
to be used instead of a defined field name inapplyeach
or used to match a field inmake
choosetype
: a function to apply to a field whenStructUtils.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
StructUtils.@kwarg
— Macro@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
: aDateFormat
object to use when parsing or formatting aDates.TimeType
fieldlower
: a function to apply to a field whenapplyeach
is called on a structlift
: a function to apply to a field whenStructUtils.make
is called on a structignore
: aBool
to indicate if a field should be skipped/ignored whenapplyeach
ormake
is calledname
: aSymbol
to be used instead of a defined field name inapplyeach
or used to match a field inmake
choosetype
: a function to apply to a field whenStructUtils.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
StructUtils.@noarg
— Macro@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
: aDateFormat
object to use when parsing or formatting aDates.TimeType
fieldlower
: a function to apply to a field whenapplyeach
is called on a structlift
: a function to apply to a field whenStructUtils.make
is called on a structignore
: aBool
to indicate if a field should be skipped/ignored whenapplyeach
ormake
is calledname
: aSymbol
to be used instead of a defined field name inapplyeach
or used to match a field inmake
choosetype
: a function to apply to a field whenStructUtils.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
StructUtils.@tags
— Macro@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
: aDateFormat
object to use when parsing or formatting aDates.TimeType
fieldlower
: a function to apply to a field whenapplyeach
is called on a structlift
: a function to apply to a field whenStructUtils.make
is called on a structignore
: aBool
to indicate if a field should be skipped/ignored whenapplyeach
ormake
is calledname
: aSymbol
to be used instead of a defined field name inapplyeach
or used to match a field inmake
choosetype
: a function to apply to a field whenStructUtils.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
StructUtils.Selectors
— ModuleSelection 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 objectx
(key can be a String, Symbol, or Integer for an array)x[:]
- select all values in object or arrayx
, returned as aSelectors.List
, which is a custom array type that supports the selection syntaxx.key
- whenx
is aList
, select the value forkey
in each element of theList
(like a broadcastedgetindex
)x[~, key]
- recursively select all values in object or arrayx
that havekey
x[~, :]
- recursively select all values in object or arrayx
, returned as a flattenedList
x[:, (k, v) -> Bool]
- apply a key-value functionf
to each key-value/index-value in object or arrayx
, and return aList
of all values for whichf
returnstrue
StructUtils.Selectors.List
— TypeList(...)
A custom array wrapper that supports the Selectors selection syntax.