Initial import
This commit is contained in:
commit
0d42589648
7 changed files with 299 additions and 0 deletions
114
main.cpp
Normal file
114
main.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
template <typename Message> struct ConsoleIO {
|
||||
static auto ReadlineS(std::istream& is, std::function<Message(std::string)> f) {
|
||||
return [=,&is] {
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
return f(line);
|
||||
};
|
||||
}
|
||||
|
||||
static std::function<Message()>
|
||||
Readline(std::function<Message(std::string)> f) {
|
||||
return ReadlineS (std::ref(std::cin), f);
|
||||
}
|
||||
|
||||
static std::function<Message()>
|
||||
Prompt(std::string prompt, std::function<Message(std::string)> f) {
|
||||
return [=] {
|
||||
std::cout << prompt << std::flush;
|
||||
return Readline (f)();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ModelT, typename MessageT> struct AppT {
|
||||
using Model = ModelT;
|
||||
using Message = MessageT;
|
||||
using Command = std::function<Message()>;
|
||||
using InitResult = std::tuple<Model, std::list<Command>>;
|
||||
using UpdateResult = InitResult;
|
||||
using ViewResult = std::string;
|
||||
using ReadLine = std::function<Message (std::string)>;
|
||||
using Console = ConsoleIO<Message>;
|
||||
|
||||
using Init = std::function<InitResult ()>;
|
||||
using Update = std::function<UpdateResult (Model, const Message&)>;
|
||||
using View = std::function<ViewResult (const Model&)>;
|
||||
using Done = std::function<bool (const Model&)>;
|
||||
|
||||
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<SetState>;
|
||||
|
||||
auto strToState (const std::string& s) -> Message {
|
||||
std::stringstream sstr(s);
|
||||
int r;
|
||||
sstr >> r;
|
||||
return SetState { r };
|
||||
}
|
||||
|
||||
int main() {
|
||||
using App = AppT<int, Message>;
|
||||
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<SetState>(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
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue