# Example:
# module M
#     using ..Main: @wrapaccessors
#     using MacroTools
#     one = 0
#     two = 0
#     struct Example end
#     Example_get_val(x::Example) = one
#     Example_set_val(x::Example, v) = global one = v
#     println(prettify(@macroexpand @wrapaccessors Example (one, )))
#     @wrapaccessors Example (one, )
# end
# x = Example()
# @assert x.one == M.one == 0
# x.one == 10
# @assert x.one == M.one == 10
macro wrapaccessors(T, fields)
    @assert fields.head === :tuple

    gen_case(i) = :(name === $(QuoteNode(fields.args[i])))
    gen_get(i) = quote
        $(__module__).$(Symbol(T, :_get_, fields.args[i]))(x)
    end
    gen_set(i) = quote
        $(__module__).$(Symbol(T, :_set_, fields.args[i]))(x, value)
    end

    # err_ex = :(error($(Expr(:string, "type $T has no field ", :name))))
    get_ex = Expr(:block, :($Base.getfield(x, name)))
    set_ex = Expr(:block, :($Base.setfield!(x, name, value)))
    for i=2:length(fields.args)
        get_ex = Expr(:elseif, gen_case(i), gen_get(i), get_ex)
        set_ex = Expr(:elseif, gen_case(i), gen_set(i), set_ex)
    end
    get_ex = Expr(:if, gen_case(1), gen_get(1), get_ex)
    set_ex = Expr(:if, gen_case(1), gen_set(1), set_ex)

    ex = quote
        $Base.@inline function $Base.getproperty(x::$(__module__).$(T), name::$Symbol)
            $get_ex
        end
        $Base.@inline function $Base.setproperty!(x::$(__module__).$(T), name::$Symbol, value)
            $set_ex
        end
        $Base.@inline function $Base.propertynames(x::$(__module__).$(T))
            $(Expr(:tuple, map(QuoteNode, fields.args)...))
        end
    end
    esc(ex)
end


