From bbe00be80ddbd4ad3cd95bb526d2c8ff26bd2f8d Mon Sep 17 00:00:00 2001 From: hhaensel Date: Tue, 5 Jul 2022 08:05:48 +0200 Subject: [PATCH 1/5] add forwarding of methods like getindex, getproperty etc. --- src/Observables.jl | 53 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/Observables.jl b/src/Observables.jl index 31da44d..ce4ac37 100644 --- a/src/Observables.jl +++ b/src/Observables.jl @@ -52,14 +52,6 @@ Gets a unique id for an observable. obsid(observable::Observable) = string(objectid(observable)) obsid(obs::AbstractObservable) = obsid(observe(obs)) -function Base.getproperty(obs::Observable, field::Symbol) - if field === :id - return obsid(obs) - else - getfield(obs, field) - end -end - Observable(val::T; ignore_equal_values::Bool=false) where {T} = Observable{T}(val; ignore_equal_values) Base.eltype(::AbstractObservable{T}) where {T} = T @@ -82,7 +74,7 @@ function Base.setindex!(@nospecialize(observable::Observable), @nospecialize(val if observable.ignore_equal_values isequal(observable.val, val) && return end - observable.val = val + setfield!(observable, :val, val) return notify(observable) end @@ -93,6 +85,49 @@ Returns the current value of `observable`. """ Base.getindex(observable::Observable) = observable.val +# pass indexing and property methods to referenced variable +# at least one index +function Base.getindex(obs::AbstractObservable, arg1, args...) + getindex(getfield(observe(obs), :val), arg1, args...) +end + +function Base.setindex!(obs::AbstractObservable, val, arg1, args...) + setindex!(getfield(observe(obs), :val), val, arg1, args...) + Observables.notify(obs) +end + +# update without triggering listeners: obs[!] = val +Base.setindex!(@nospecialize(obs::AbstractObservable), @nospecialize(val), ::typeof(!)) = setfield!(observe(obs), :val, val) +Base.getindex(@nospecialize(obs::AbstractObservable), ::typeof(!)) = getfield(observe(obs), :val) + +function Base.getproperty(obs::T, field::Symbol) where T <: AbstractObservable + if field === :id + return obsid(obs) + elseif field in fieldnames(T) + getfield(obs, field) + else + getproperty(getfield(observe(obs), :val), field) + end +end + +function Base.setproperty!(@nospecialize(obs::T), field::Symbol, @nospecialize(val)) where T <: AbstractObservable + if field in fieldnames(T) + setfield!(obs, field, val) + else + setproperty!(getfield(observe(obs), :val), field, val) + end + Observables.notify(obs) +end + +for f in (:push!, :pushfirst!, :pop!, :popfirst!) + Core.eval(@__MODULE__, """ + function $f(obs::AbstractObservable{T}, val) where T + $f(getfield(observe(obs), :val), val) + Observables.notify(obs) + end + """ |> Meta.parse) +end + ### Utilities """ From 735c468c692e45b210c6ba48b45d87c66aefbd54 Mon Sep 17 00:00:00 2001 From: hhaensel Date: Tue, 5 Jul 2022 08:14:28 +0200 Subject: [PATCH 2/5] fix definition of push! etc. --- src/Observables.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Observables.jl b/src/Observables.jl index ce4ac37..8b5259e 100644 --- a/src/Observables.jl +++ b/src/Observables.jl @@ -121,9 +121,10 @@ end for f in (:push!, :pushfirst!, :pop!, :popfirst!) Core.eval(@__MODULE__, """ - function $f(obs::AbstractObservable{T}, val) where T + function Base.$f(@nospecialize(obs::AbstractObservable), @nospecialize(val)) $f(getfield(observe(obs), :val), val) - Observables.notify(obs) + notify(obs) + getfield(observe(obs), :val) end """ |> Meta.parse) end From c9895d08945e98754ea84e76e3126e3bfb68deb4 Mon Sep 17 00:00:00 2001 From: hhaensel Date: Tue, 5 Jul 2022 08:22:43 +0200 Subject: [PATCH 3/5] more @nospecialize ... --- src/Observables.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Observables.jl b/src/Observables.jl index 8b5259e..9c7434d 100644 --- a/src/Observables.jl +++ b/src/Observables.jl @@ -87,11 +87,11 @@ Base.getindex(observable::Observable) = observable.val # pass indexing and property methods to referenced variable # at least one index -function Base.getindex(obs::AbstractObservable, arg1, args...) +function Base.getindex(@nospecialize(obs::AbstractObservable), arg1, args...) getindex(getfield(observe(obs), :val), arg1, args...) end -function Base.setindex!(obs::AbstractObservable, val, arg1, args...) +function Base.setindex!(@nospecialize(obs::AbstractObservable), val, arg1, args...) setindex!(getfield(observe(obs), :val), val, arg1, args...) Observables.notify(obs) end From 56e788995f6c7cf0d75fa5636240202803072603 Mon Sep 17 00:00:00 2001 From: hhaensel Date: Tue, 5 Jul 2022 13:56:46 +0200 Subject: [PATCH 4/5] cycle through the layers of observables for getproperty --- src/Observables.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Observables.jl b/src/Observables.jl index 9c7434d..83671ba 100644 --- a/src/Observables.jl +++ b/src/Observables.jl @@ -104,8 +104,8 @@ function Base.getproperty(obs::T, field::Symbol) where T <: AbstractObservable if field === :id return obsid(obs) elseif field in fieldnames(T) - getfield(obs, field) - else + getfield(observe(obs), field) + elseif field in fieldnames(Observable) getproperty(getfield(observe(obs), :val), field) end end From ef05824ecc202497da7e40d955f9e3dbf2e517a5 Mon Sep 17 00:00:00 2001 From: hhaensel Date: Tue, 5 Jul 2022 14:48:47 +0200 Subject: [PATCH 5/5] fixes to getproperty --- src/Observables.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Observables.jl b/src/Observables.jl index 83671ba..63a5bfe 100644 --- a/src/Observables.jl +++ b/src/Observables.jl @@ -103,9 +103,11 @@ Base.getindex(@nospecialize(obs::AbstractObservable), ::typeof(!)) = getfield(ob function Base.getproperty(obs::T, field::Symbol) where T <: AbstractObservable if field === :id return obsid(obs) - elseif field in fieldnames(T) - getfield(observe(obs), field) + elseif T !== Observable && field in fieldnames(T) + getfield(obs, field) elseif field in fieldnames(Observable) + getfield(observe(obs), field) + else getproperty(getfield(observe(obs), :val), field) end end