Visualize.VirtualSource.Engine (Visualize v0.8.1)

Copy Markdown View Source

Virtual sources where feeds run (spec/15 §14, D-194): a value the board process holds beside its feed monitor and calls from its own callbacks, as it holds the monitor (spec/08 §11.4, D-140).

new/2 defines the sources — every input resolved, cycles refused by name, ranks assigned. push/4 shows the engine the feeds' latest deliveries: a feed that changed marks the sources that read it, and the first mark makes a pulse due debounce: milliseconds later. run/2 runs a due pulse: the marked sources in rank order, each at most once, every call bounded (Visualize.VirtualSource.Sandbox.run/3). A source that fails keeps its last good output, and the pulse goes no further along it.

A function of two arguments is called with its context (spec/08 §10.5.6, D-228): its inputs' schemas and deliveries' facts, and its scope's variables, which vars/3 shows the engine by scope. A change to the variables a context-taking source's scope sees marks it, and only it.

iex> alias Visualize.VirtualSource
iex> alias Visualize.VirtualSource.Engine
iex> alias Visualize.Data.{Delivery, Schema}
iex> count = VirtualSource.new!(id: :count, from: [hosts: nil],
...>   schema: %{n: %{type: :number}}, elixir: "fn %{hosts: rows} -> [%{n: Enum.count(rows)}] end")
iex> {:ok, engine} = Engine.new(%{[:count] => count}, feeds: [:hosts], debounce: 0)
iex> hosts = Schema.new!(%{host: %{type: :category}})
iex> engine = Engine.push(engine, %{hosts: Delivery.new([%{host: "a"}, %{host: "b"}])}, %{hosts: hosts}, 0)
iex> engine = Engine.run(engine, 0)
iex> Engine.outputs(engine)[["count"]].rows
[%{"n" => 2}]
iex> Engine.status(engine)
%{["count"] => :live}

Summary

Types

A definition fault: the source's path, where in it, and why (spec/15 §14.1).

A source's fault (spec/15 §14.3): its kind and its detail, never a value.

A container's path, [] the board's and [cell] a cell's (spec/08 §10.5.9).

t()

Functions

The monotonic millisecond the next pulse is due, or nil (spec/15 §14.2).

Every failing source's fault by path, %{kind: kind, detail: detail} (spec/15 §14.3).

The feeds some source reads, sorted: a board asks each of them its ceiling, since a source's function reads the rows it is given (spec/15 §8.2, D-226).

The engine over virtual sources by path, defined (spec/15 §14.1): {:ok, engine}, or {:error, errors} — every input that resolves to nothing, every host function the registry lacks, then every cycle by name. Options: feeds: (the feeds' names, []), functions: (the registry, %{}), vars: (the starting variables, each scope's own by scope as vars/3 takes them, or nil while none is known), debounce: (milliseconds, 0), max_reductions:, timeout: and max_heap: (each call's limits, spec/08 §10.5.4).

Every source's last good output, a %Visualize.Data.Delivery{}, by path.

The feeds' latest deliveries and their schemas shown to the engine at the owner's monotonic millisecond now (spec/15 §14.2): every source that reads a feed whose delivery is not the one last seen is marked, and the first mark makes the next pulse due debounce later.

What a name read from a scope names (spec/15 §14.5): {:source, path} for a virtual source, resolved from the inside out, else {:feed, name} for a name feeds holds, else :error.

The due pulse run at now (spec/15 §14.2): the marked sources in rank order, each at most once; a changed answer marks its readers, which run later in the same pulse. The engine is returned as it is when no pulse is due.

How many times each source has run, by path.

Every source's output schema, by path.

Every source's state by path (spec/15 §14.3): :loading before its first answer, :live after, and {:down, {:virtual_source, id, kind}} while it fails.

Each scope's own variables shown to the engine at the owner's monotonic millisecond now (spec/15 §14.2, D-228): vars maps a scope — [] the board, [cell] a cell — to that scope's variables by name, and a scope it does not name keeps what it had. A source of two arguments is given the cascade at its scope (spec/15 §5): the board's variables with each container's merged over them, inward. Every such source whose cascade changed is marked, and the first mark makes the next pulse due debounce later; a source of one argument is never marked by a variable.

Types

error()

@type error() :: {path(), list(), term()}

A definition fault: the source's path, where in it, and why (spec/15 §14.1).

fault()

@type fault() :: %{kind: atom(), detail: term()}

A source's fault (spec/15 §14.3): its kind and its detail, never a value.

path()

@type path() :: [atom(), ...]

ref()

@type ref() :: {:feed, term()} | {:source, path()}

scope()

@type scope() :: [atom() | String.t()]

A container's path, [] the board's and [cell] a cell's (spec/08 §10.5.9).

t()

@type t() :: %Visualize.VirtualSource.Engine{
  arities: term(),
  cache: term(),
  checked: term(),
  compiled: term(),
  debounce: term(),
  due: term(),
  faults: term(),
  feed_schemas: term(),
  feeds: term(),
  functions: term(),
  inputs: term(),
  marked: term(),
  order: term(),
  outputs: term(),
  ranks: term(),
  readers: term(),
  run_opts: term(),
  runs: term(),
  seen: term(),
  sources: term(),
  vars: term(),
  vars_known: term()
}

Functions

due(engine)

@spec due(t()) :: integer() | nil

The monotonic millisecond the next pulse is due, or nil (spec/15 §14.2).

faults(engine)

@spec faults(t()) :: %{required(path()) => fault()}

Every failing source's fault by path, %{kind: kind, detail: detail} (spec/15 §14.3).

feeds_read(engine)

@spec feeds_read(t()) :: [term()]

The feeds some source reads, sorted: a board asks each of them its ceiling, since a source's function reads the rows it is given (spec/15 §8.2, D-226).

new(sources, opts \\ [])

@spec new(%{required(path()) => Visualize.VirtualSource.t()}, keyword()) ::
  {:ok, t()} | {:error, [error(), ...]}

The engine over virtual sources by path, defined (spec/15 §14.1): {:ok, engine}, or {:error, errors} — every input that resolves to nothing, every host function the registry lacks, then every cycle by name. Options: feeds: (the feeds' names, []), functions: (the registry, %{}), vars: (the starting variables, each scope's own by scope as vars/3 takes them, or nil while none is known), debounce: (milliseconds, 0), max_reductions:, timeout: and max_heap: (each call's limits, spec/08 §10.5.4).

outputs(engine)

@spec outputs(t()) :: %{required(path()) => Visualize.Data.Delivery.t()}

Every source's last good output, a %Visualize.Data.Delivery{}, by path.

push(engine, deliveries, schemas, now)

@spec push(
  t(),
  %{required(term()) => Visualize.Data.Delivery.t()},
  %{required(term()) => Visualize.Data.Schema.t()},
  integer()
) :: t()

The feeds' latest deliveries and their schemas shown to the engine at the owner's monotonic millisecond now (spec/15 §14.2): every source that reads a feed whose delivery is not the one last seen is marked, and the first mark makes the next pulse due debounce later.

resolve(engine, scope, name)

@spec resolve(t(), [atom()], term()) :: ref() | :error

What a name read from a scope names (spec/15 §14.5): {:source, path} for a virtual source, resolved from the inside out, else {:feed, name} for a name feeds holds, else :error.

run(engine, now)

@spec run(t(), integer()) :: t()

The due pulse run at now (spec/15 §14.2): the marked sources in rank order, each at most once; a changed answer marks its readers, which run later in the same pulse. The engine is returned as it is when no pulse is due.

runs(engine)

@spec runs(t()) :: %{required(path()) => non_neg_integer()}

How many times each source has run, by path.

schemas(engine)

@spec schemas(t()) :: %{required(path()) => Visualize.Data.Schema.t()}

Every source's output schema, by path.

status(engine)

@spec status(t()) :: %{required(path()) => :loading | :live | {:down, term()}}

Every source's state by path (spec/15 §14.3): :loading before its first answer, :live after, and {:down, {:virtual_source, id, kind}} while it fails.

vars(engine, vars, now)

@spec vars(t(), %{required(scope()) => map()}, integer()) :: t()

Each scope's own variables shown to the engine at the owner's monotonic millisecond now (spec/15 §14.2, D-228): vars maps a scope — [] the board, [cell] a cell — to that scope's variables by name, and a scope it does not name keeps what it had. A source of two arguments is given the cascade at its scope (spec/15 §5): the board's variables with each container's merged over them, inward. Every such source whose cascade changed is marked, and the first mark makes the next pulse due debounce later; a source of one argument is never marked by a variable.