Current section
Files
Jump to
Current section
Files
lib/observables/combineLatest_var.ex
defmodule Observables.Operator.CombineLatestVar do
@moduledoc false
use Observables.GenObservable
alias Observables.Obs
def init([pids, inits, obstp]) do
Logger.debug("CombineLatestVar: #{inspect(self())}")
# Define the index for the next observable.
index = length(inits)
# Create a map that maps observable pids to their indices.
indmap = pids |> Map.new
# Create a map that maps indices of observables to their current values.
valmap = inits |> Map.new
{:ok, {valmap, indmap, index, obstp}}
end
# Handle a new observable to listen to.
def handle_event({:newobs, obs, init}, {valmap, indmap, index, obstp}) do
# Tag the new observable with a :newval tag and its newly given index so that we can process it properly.
{t_f, t_pid} = obs
|> Obs.map(fn val -> {:newval, index, val} end)
# Make the tagged observable send to us.
t_f.(self())
# Add the initial value as the entry for the new observable to the value map with its newly given index as the key.
new_valmap = valmap |> Map.put(index, init)
# Add the given index as the entry for the new observable to the index map with the pid of the tagged observable as its key.
new_indmap = indmap |> Map.put(t_pid, index)
# Increase the index counter
new_index = index + 1
# Produce a value with the initial value of the new observable if possible.
vals = new_valmap |> Map.values
if Enum.any?(vals, fn val -> val == nil end) do
{:novalue, {new_valmap, new_indmap, new_index, obstp}}
else
{:value, List.to_tuple(vals), {new_valmap, new_indmap, new_index, obstp}}
end
end
# Handle a new value being sent to us from one of the observables we listen to.
def handle_event({:newval, index, value}, {valmap, indmap, cindex, obstp}) do
new_valmap = %{valmap | index => value}
vals = new_valmap |> Map.values
if Enum.any?(vals, fn val -> val == nil end) do
{:novalue, {new_valmap, indmap, cindex, obstp}}
else
{:value, List.to_tuple(vals), {new_valmap, indmap, cindex, obstp}}
end
end
def handle_done(obstp, {valmap, indmap, cindex, obstp}) do
Logger.debug("#{inspect(self())}: CombineLatestVar has a dead observable stream, going on with possibility of termination.")
{:ok, :continue, {valmap, indmap, cindex, nil}}
end
def handle_done(pid, {valmap, indmap, cindex, nil}) do
Logger.debug("#{inspect(self())}: CombineLatestVar has one dead dependency and already a dead observable stream, going on with possibility of termination.")
index = Map.get(indmap, pid)
new_indmap = Map.delete(indmap, pid)
new_valmap = Map.delete(valmap, index)
{:ok, :continue, {new_valmap, new_indmap, cindex, nil}}
end
def handle_done(pid, {valmap, indmap, cindex, obstp}) do
Logger.debug("#{inspect(self())}: CombineLatestVar has one dead dependency, but an active observable stream, going on without possibility of termination at this point.")
index = Map.get(indmap, pid)
new_indmap = Map.delete(indmap, pid)
new_valmap = Map.delete(valmap, index)
{:ok, :continue, :notermination, {new_valmap, new_indmap, cindex, obstp}}
end
end