defmodule Scopes.Core.Environ do @cell_registry __MODULE__.Cells alias Scopes.Core alias Scopes.Core.Actor alias Scopes.Core.Shape require Logger defmodule State do defstruct [init_seq: []] end def cells(), do: @cell_registry def child_spec(opts) do %{id: __MODULE__, start: {__MODULE__, :setup, opts}} end def setup({state, proc}, init_seq, proc_env \\ &proc_env/2) do Registry.start_link(keys: :unique, name: cells()) env_scope = {%State{init_seq: init_seq}, proc_env, [], self()} env = Core.neuron(env_scope) Actor.register(env, cells(), {:env, :c00}) msg = Shape.create([:csys, :zero], data: %{addr: {:csys, :c00, "0-0"}}) scope = {state, proc, [], env} Core.create(msg, scope) #{:ok, env} :ignore end def proc_env(msg, scope) do case Shape.head(msg) do {:exec, func} -> func.() [:csys, :created | _rest] -> process_created(msg, scope) _ -> send(Core.env(scope), msg) # forward message to application end end def process_created(msg, {state, proc, syns, env}) do data = Shape.data(msg) new = data.new addr = data[:addr] if addr do Actor.register(new, cells(), addr) end {step, seq} = List.pop_at(state.init_seq, 0) state1 = %State{init_seq: seq} Core.update({state1, proc, syns, env}) if step do Process.sleep(1) step.() end end # accessing cell registry def get_cell(addr) do data = Registry.lookup(cells(), addr) if data do [{cell, _val}] = data cell else Logger.warning "No cell found at address #{inspect(addr)}!" nil end end def send_message(addr, head, data) do rcvr = get_cell(addr) Core.send_message(rcvr, head, data) end def send_value(addr, value) do send_message(addr, ~w(csys data)a, %{value: value}) end def connect(addr = {dom, _cat, _item}, target, op \\ []) do send_message(addr, [dom, :connect], %{target: get_cell(target), op: op}) end # delegating tasks to env def delegate(env, func) do Core.send_message(env, {:exec, func}) end def forward_value(env, addr, value) do delegate(env, fn -> send_message(addr, ~w(csys data)a, %{value: value}) end) end end