Skip to content

@nonstruct does not force make to use lower for complex type mappings? #29

Description

@sairus7

I have this test example to read/write complex tree structure into a simpler tree representation, so I use @nonstruct to force make to call lift/lower methods, as mentioned in docs. But looks like make does not call lower as expected.

MWE:

module Example
using StructUtils
using AbstractTrees
using OrderedCollections

abstract type PrintTree end
AbstractTrees.children(node::PrintTree) = node.children |> values
AbstractTrees.printnode(io::IO, node::PrintTree) = begin print(io, node.id, " => ", node.data) end
Base.show(io::IO, node::PrintTree) = AbstractTrees.print_tree(io, node)

@kwdef mutable struct DataNode <: PrintTree
    id::String = ""
    parent::Union{DataNode, Nothing} = nothing
    children::OrderedDict{String, DataNode} = OrderedDict{String, DataNode}()
    data::Any = nothing
end
function Base.setindex!(node::DataNode, child::DataNode, key)
    node.children[key] = child
    child.parent = node
    child.id = key
    return child
end

StructUtils.structlike(::Type{DataNode}) = false
function StructUtils.lift(::Type{DataNode}, src::T) where T
    @info "lift"
    node = DataNode()
    if isprimitivetype(T) || T <: Union{AbstractString, Number, Bool}
        node.data = src
    elseif T <: AbstractDict
        for (k, v) in src
            node[string(k)] = StructUtils.lift(DataNode, v)
        end
    elseif isstructtype(T)
        for k in fieldnames(T)
            v = getfield(src, k)
            node[string(k)] = StructUtils.lift(DataNode, v)
        end
    end
    return node
end
function StructUtils.lower(node::DataNode)
    @info "lower"
    if isempty(node.children)
        return node.data
    end
    result = OrderedDict{String,Any}()
    for (k, child) in node.children
        result[k] = StructUtils.lower(child)
    end
    return result
end

function test()
    inp = OrderedDict{String, Any}("leaf" => 1)

    node = StructUtils.lift(DataNode, inp)
    @show node

    node = StructUtils.make(DataNode, inp) # make calls lift
    @show node

    out = StructUtils.lower(node)
    @show out

    out = StructUtils.make(OrderedDict{String, Any}, node) # make does not call lower
    @show out

    return nothing
end

end

import .Example
Example.test()

(Here I declare structlike = false instead of @nonstruct to have separate @kwdef functionality, but returning @nonstruct does not change the result.)

Output:

[ Info: lift
[ Info: lift
node =  => nothing
└─ leaf => 1

[ Info: lift
[ Info: lift
node =  => nothing
└─ leaf => 1

[ Info: lower
[ Info: lower
out = OrderedDict{String, Any}("leaf" => 1)
out = OrderedDict{String, Any}("id" => "", "parent" => nothing, "children" => OrderedDict{String, Main.Example.DataNode}("leaf" => leaf => 1
), "data" => nothing)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions