Skip to content

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

@sairus7

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions