Skip to content

Commit

Permalink
Let map store ObserverFuncs & add precompile
Browse files Browse the repository at this point in the history
This addresses a comment made in
#48 (comment)
by implementing storage for the ObserverFunctions
added by `map`.
This also adds optional precompilation support for observables,
precompiling the methods based on the `T` in `Observable{T}`.
  • Loading branch information
timholy committed Jan 4, 2021
1 parent cb2d6e2 commit 8d283d8
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 2 deletions.
27 changes: 25 additions & 2 deletions src/Observables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Like a `Ref` but updates can be watched by adding a handler using `on`.
mutable struct Observable{T} <: AbstractObservable{T}
listeners::Vector{Any}
val::T
inputs::Vector{Any} # for map!ed Observables

Observable{T}() where {T} = new{T}([])
Observable{T}(val) where {T} = new{T}([], val)
# Construct an Observable{Any} without runtime dispatch
Expand Down Expand Up @@ -58,6 +60,8 @@ function Base.getproperty(obs::Observable, field::Symbol)
return getfield(obs, field)
elseif field === :listeners
return getfield(obs, field)
elseif field === :inputs
return getfield(obs, field)
elseif field === :id
return obsid(obs)
else
Expand Down Expand Up @@ -131,6 +135,20 @@ mutable struct ObserverFunction <: Function
end
end

Base.precompile(obsf::ObserverFunction) = precompile(obsf.f, (eltype(obsf.observable),))
function Base.precompile(observable::Observable)
tf = true
T = eltype(observable)
for f in observable.listeners
precompile(f, (T,))
end
if isdefined(observable, :inputs)
for obsf in observable.inputs
tf &= precompile(obsf)
end
end
return tf
end

"""
on(f, observable::AbstractObservable; weak = false)
Expand Down Expand Up @@ -335,8 +353,13 @@ Updates `observable` with the result of calling `f` with values extracted from a
`f` will be passed the values contained in the refs as the respective argument.
All other objects in `args` are passed as-is.
"""
function Base.map!(f, observable::AbstractObservable, os...)
onany(MapUpdater(f, observable), os...)
function Base.map!(f::F, observable::AbstractObservable, os...) where F
obsfuncs = onany(MapUpdater(f, observable), os...)
if !isdefined(observable, :inputs)
observable.inputs = obsfuncs
else
append!(observable.inputs, obsfuncs)
end
return observable
end

Expand Down
3 changes: 3 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ end
@test r2[] == 3
r1[] = 3
@test r2[] == 4

# Make sure `precompile` doesn't error
precompile(r1)
end

@testset "disconnect observerfuncs" begin
Expand Down

0 comments on commit 8d283d8

Please sign in to comment.