#include #include #include #include #include #include #include #include using namespace std::chrono_literals; template struct ConsoleIO { static auto ReadlineS(std::istream& is, std::function f) { return [=,&is] { std::string line; std::getline(is, line); return f(line); }; } static std::function Readline(std::function f) { return ReadlineS (std::ref(std::cin), f); } static std::function Prompt(std::string prompt, std::function f) { return [=] { std::cout << prompt << std::flush; return Readline (f)(); }; } }; template struct AppT { using Model = ModelT; using Message = MessageT; using Command = std::function; using InitResult = std::tuple>; using UpdateResult = InitResult; using ViewResult = std::string; using ReadLine = std::function; using Console = ConsoleIO; using Init = std::function; using Update = std::function; using View = std::function; using Done = std::function; struct Config { Init init; Update update; View view; Done done; }; int run (const Config & cfg) { auto const& [init, update, view, done] = cfg; auto [state, cmds] = init(); while (! done (state)) { std::cout << view(state) << "\n"; if (!cmds.empty()) { auto [newstate, newcmds] = update (state, cmds.front()()); cmds.erase (cmds.begin()); cmds.insert (cmds.end(), std::begin(newcmds), std::end (newcmds)); state = newstate; } std::this_thread::sleep_for (100ms); } std::cout << "app finished with " << cmds.size() << " pending commands and final state: \n" << view(state) << '\n'; return 0; } }; // user defined using Model = int; struct SetState { Model s; }; using Message = std::variant; auto strToState (const std::string& s) -> Message { std::stringstream sstr(s); int r; sstr >> r; return SetState { r }; } int main() { using App = AppT; App app; return app.run(App::Config{ []() -> App::InitResult { return {23, {App::Console::Prompt("> ", strToState)}}; }, // init [](const App::Model &state, const App::Message &msg) -> App::UpdateResult { return {std::get(msg).s, {App::Console::Prompt("> ", strToState)}}; }, // update [](const App::Model &state) -> App::ViewResult { return "Model " + std::to_string(state); }, // view [](const App::Model &state) -> bool { return state == 42; } // done }); }