StateValve (Core)

Namespace: Vortex.Core.StateValve Сборка: ru.vortex.core.statevalve

Назначение

Реактивный вентиль состояния — примитив, сводящий N именованных булевых створок («ключей») в один булев итог по режиму свёртки + инверсия. Нейтрален к домену: оперирует «открыто/закрыто», смысл («закрыто = пауза») придаёт применяющий.

Это примитив, не система: инстанцируется через new (как ReactiveValue, DateTimeTimer), без шины, драйвера, контроллера и пресетов.

  • N именованных створок «открыт/закрыт»
  • Свёртка в один итог: And / Or / Xor
  • Инверсия итога (NOT)
  • Реактивный вывод State : BoolData под owner-lock
  • fail-fast на пустой ключ

Зависимости

  • Vortex.Core.Extensions.ReactiveValuesBoolData

Модель

StateValve
├── State : BoolData                          ← реактивный итог (owner-lock), только чтение/подписка
├── Keys  : IReadOnlyDictionary<string,bool>  ← створки, для отладки
├── Open(string) / Close(string)
└── ctor(ValveMode mode = And, bool invert = false)

ValveMode { And, Or, Xor }

Свёртка (таблицы истинности, при наличии ключей)

Режим Открыт, если
And открыты ВСЕ
Or открыт ХОТЬ ОДИН
Xor открыт РОВНО ОДИН (ноль или ≥2 открытых → закрыт)

Пустой набор → открыт (вентиль не закрывали) — конвенция вентиля, единообразно во всех режимах, до инверсии. Итог: final = invert ? !raw : raw.

Контракт

  • State пишется только пересчётом после Open/Close (owner-lock; внешний Set невозможен).
  • Пустой/null ключ → ArgumentException (fail-fast, баг вызывающего).
  • Освобождение створки = Open(id) — ключ остаётся в наборе открытым; удаления ключей нет.

Ре-энтрантность (однопоточно)

Клапан гардов не добавляет намеренно.

  • Безобидная вложенность (подписчик на State в колбэке зовёт Open/Close) отрабатывает: BoolData дедупит (событие только на реальном изменении), порядок last-write-wins, сходящаяся цепочка затихает.
  • Осциллирующая (подписчик крутит ключ так, что итог переворачивается обратно) — ошибка композиции вызывающего: проявится stack overflow как fail-fast сигнал о встречной петле. Контракт: не сводить самоподдерживающийся цикл.

Использование

var valve = new StateValve(ValveMode.And);        // «идёт» = все ключи открыты
valve.State.OnUpdate += open => SetPaused(!open);

valve.Close("tutor");      // закрыт → State = false
valve.Close("countdown");  // ещё один держит
valve.Open("tutor");       // отпустил, но countdown держит → всё ещё закрыт
valve.Open("countdown");   // все открыты → State = true

Unity-обёртка (StateValveHandler, пакет ru.vortex.unity.statevalve) добавляет настройку в инспекторе, whitelist-фильтр ключей и слабую привязку через IDataStorage.