defmodule Scopes.Core.Environ do @cell_registry __MODULE__.Cells alias Scopes.Core alias Scopes.Core.Shape defmodule State do defstruct [cells: %{}, init_seq: []] end def child_spec(opts) do %{id: __MODULE__, start: {__MODULE__, :start_link, opts}} end def start_link() do Registry.start_link(keys: :unique, name: @cell_registry) end def cells(), do: @cell_registry def setup({state, proc}, init_seq, proc_env \\ &proc_env/2) do env_scope = {%State{init_seq: init_seq}, proc_env, [], self()} env = Core.neuron(env_scope) msg = Shape.create([:csys, :zero], data: %{addr: [:csys, :c00, "0-0"]}) proc = {state, proc, [], env} Core.create(msg, proc) env end def proc_env(msg, scope = {state, _proc, _syns, env}) do case Shape.head(msg) do {:exec, func} -> func.(state) [:csys, :created | _rest] -> process_creation(msg, scope) _ -> send(env, msg) # forward message to application end end def process_creation(msg, {state, proc, syns, env}) do data = Shape.data(msg) new = data.new addr = data[:addr] cells = if addr do [dom, cat, item] = addr Map.update(state.cells, {dom, cat}, %{item => new}, fn x -> Map.put(x, item, new) end) else state.cells end {step, seq} = List.pop_at(state.init_seq, 0) state1 = %State{cells: cells, init_seq: seq} Core.update({state1, proc, syns, env}) if step do step.(state1) end end # accessing cell registry via state.cells def get_cell(state, [dom, cat, item]) do get_in(state.cells, [{dom, cat}, item]) end def send_message(state, addr, head, data) do cell = get_cell(state, addr) Core.send_message(cell, head, data) end def connect(state, addr, target, op \\ []) do send_message(state, addr, ~w(csys connect)a, %{target: get_cell(state, 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, &send_message(&1, addr, ~w(csys data)a, %{value: value})) end end