Skip to content

ArgumentsObservable

jkrumbiegel edited this page Nov 18, 2020 · 1 revision
struct Arguments
    args::Tuple
    kwargs::NamedTuple
end

function Arguments(args...; kwargs...)
    Arguments(Tuple(args), NamedTuple(kwargs))
end

function Base.getindex(a::Arguments, i::Int)
    a.args[i]
end

function Base.getindex(a::Arguments, s::Symbol)
    a.kwargs[s]
end

mutable struct ArgumentsObservable
    arguments::Arguments
    listeners::Vector{Pair{Tuple, Any}}
end

function validate(ao, pairs)
    for (id, _) in pairs
        ao.arguments[id]
    end
    nothing
end

function update_arguments!(ao, pairs)
    dict = Dict(pairs)
    newargs = Tuple(get(dict, i, ao.arguments[i]) for i in eachindex(ao.arguments.args))
    newkwargs = NamedTuple(kw => get(dict, kw, ao.arguments[kw]) for kw in keys(ao.arguments.kwargs))
    newarguments = Arguments(newargs, newkwargs)
    ao.arguments = newarguments
    nothing
end

function update!(ao::ArgumentsObservable, pairs::AbstractVector{<:Pair})

    validate(ao, pairs)
    update_arguments!(ao, pairs)

    updated_identifiers = Set(first.(pairs))

    for (used_identifiers, listener) in ao.listeners
        if !isempty(intersect(Set(used_identifiers), updated_identifiers))
            listener(updated_identifiers, (ao.arguments[i] for i in used_identifiers)...)
        end
    end

end

ao = ArgumentsObservable(Arguments(randn(100), randn(100), color = randn(100)), [])


function on(f, ao::ArgumentsObservable, args::Union{Int, Symbol}...)

    push!(ao.listeners, Tuple(args) => f)
    f

end

on(ao, 1, :color) do changed, x, color
    println("What changed?")
    println(changed)
    if 1 in changed
        println("New x length: $(length(x))")
    end
    if :color in changed
        println("New color length: $(length(color))")
    end
end

# no reaction
update!(ao, [2 => randn(100)])
# reaction
update!(ao, [1 => randn(200), :color => randn(200)])
Clone this wiki locally