#pragma once #include #include #include #include #include #include #include #include "secsgem/gem/module_state.hpp" namespace secsgem::gem { struct Module { std::string module_id; std::string recipe_step; // RCPSPEC the step is executing std::string current_substid; // SUBSTID being processed; empty when idle std::unique_ptr fsm; }; class ModuleStore { public: using StateChangeHandler = std::function; ModuleStore() = default; ModuleStore(const ModuleStore&) = delete; ModuleStore& operator=(const ModuleStore&) = delete; ModuleStore(ModuleStore&&) = delete; ModuleStore& operator=(ModuleStore&&) = delete; void set_state_change_handler(StateChangeHandler h) { on_change_ = std::move(h); } bool create(std::string module_id) { if (mods_.count(module_id)) return false; auto fsm = std::make_unique(); const std::string id = module_id; fsm->set_state_change_handler( [this, id](ModuleState f, ModuleState t, ModuleEvent e) { if (on_change_) on_change_(id, f, t, e); }); mods_.emplace(module_id, Module{module_id, "", "", std::move(fsm)}); return true; } bool has(const std::string& mid) const { return mods_.count(mid) > 0; } const Module* get(const std::string& mid) const { auto it = mods_.find(mid); return it == mods_.end() ? nullptr : &it->second; } Module* get(const std::string& mid) { auto it = mods_.find(mid); return it == mods_.end() ? nullptr : &it->second; } // Bind a substrate + recipe step to the module for the next step // (typically called immediately before StartGeneral). bool bind(const std::string& mid, std::string substid, std::string recipe_step) { auto* m = get(mid); if (!m) return false; m->current_substid = std::move(substid); m->recipe_step = std::move(recipe_step); return true; } bool fire(const std::string& mid, ModuleEvent e) { auto* m = get(mid); return m && m->fsm->on_event(e); } std::size_t size() const { return mods_.size(); } std::vector ids() const { std::vector out; out.reserve(mods_.size()); for (const auto& kv : mods_) out.push_back(kv.first); return out; } private: std::map mods_; StateChangeHandler on_change_; }; } // namespace secsgem::gem