Default to OrderedStruct for NamedTuples?
Would it be possible to define default StructType for NamedTuples as StructTypes.OrderedStruct()? Or are there any obvious conflicts I'm not seeing? It seems like the problems that might arise because of this are similar to those described in #61, but I am unable to come up with any other StructType for NamedTuples, that might be of use.
Is there a reason you'd prefer OrderedStruct vs UnorderedStruct? I've had an idea of possibly refactoring things slightly to allow per-module overloads for specific cases. You can already do this yourself, like we do in JSON3, with our various read overloads, but it could be nice to allow overloading directly. So you'd be able to do something like StructTypes.StructType(::Val{:MyModule}, ::Type{<:NamedTuple}) = StructTypes.UnorderedStruct() or something like that.
[EDIT: simplified defs -- check PR for more details]
These definitions appear to work.
These allow obj to have fields that are not in T (issuing a @debug msg) but obj must contain all the fields in T except for those are allowed to be nothing or missing.
I'll make a pull request for this:
StructType(::Type{T}) where {T <: NamedTuple} = UnorderedStruct()
constructfrom(t::Type{NamedTuple}, obj::NamedTuple) =
constructfrom(StructType(t), t, StructType(typeof(obj)), obj)
constructfrom(::Union{Struct, UnorderedStruct}, t::Type{T}, ::Union{Struct, UnorderedStruct}, obj::NamedTuple) where {T <: NamedTuple} =
construct_nt(t, obj)
construct_nt(::Type{NamedTuple}, obj) = obj
function construct_nt(t::Type{T}, obj) where {T <: NamedTuple}
keys = fieldnames(t)
keyset = Set(keys)
result = Dict()
for (key, value) in pairs(obj)
field = construct(Symbol, key)
if field in keyset
result[field] = constructfrom(fieldtype(t, field), value)
delete!(keyset, field)
else
msg = "Extraneous field $field in $obj, not in type $t"
try
throw(ArgumentError(msg))
catch err
@debug msg exception=err,catch_backtrace()
end
end
end
for key in keyset
type = fieldtype(t, key)
if nothing isa type
result[key] = nothing
elseif missing isa type
result[key] = missing
else
continue
end
delete!(keyset, key)
end
length(keyset) > 0 && throw(ArgumentError("Missing required fields $(join(keyset, ",")) from $obj in type $t"))
t(result[key] for key in keys)
end
Is there a reason you'd prefer OrderedStruct vs UnorderedStruct?
~I've had this case for NamedTuples where I have a row-table like Vector{T} for some T <:NamedTuple, and I want to push! a new row onto it, and maybe either the table or the row was just deserialized from JSON. The order matters because the keys must be in the right order for the types to match to succesfully push!.~
Nevermind, I forgot what OrderedStruct meant (it's about assumptions on JSON format, not whether or not we want the structs fields to be ordered correctly, which of course we always do for a struct).