Skip to content

Instantly share code, notes, and snippets.

@indiosmo
Created August 14, 2018 01:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save indiosmo/08ab24181770125d5a2448d27f6ae99f to your computer and use it in GitHub Desktop.
Save indiosmo/08ab24181770125d5a2448d27f6ae99f to your computer and use it in GitHub Desktop.
SML - Hierarchical Machine
struct client_protocol
{
// clang-format off
// public interface
struct ev_connect{};
struct ev_disconnect{};
// connection handlers
struct ev_error{};
struct ev_connected{};
struct ev_handshake_ack{};
struct ev_disconnected {};
struct ev_fin {};
// stream handlers
struct ev_retry{};
struct ev_payload
{
const_buffer data;
};
// clang-format on
struct events
{
std::function<void()> established;
std::function<void()> disconnected;
std::function<void()> error;
std::function<void(const_buffer)> payload;
};
struct actions
{
std::function<void()> connect;
std::function<void(bool initiator)> disconnect;
std::function<void()> start_stream;
std::function<void()> send_handshake;
std::function<void()> wait_retry;
};
struct connected
{
auto operator()()
{
using namespace boost::sml;
namespace sml = boost::sml;
// clang-format off
return make_transition_table(
*"handshake"_s + sml::on_entry<_> / [](actions& ac) { ac.start_stream(); ac.send_handshake(); }
,"handshake"_s + sml::event<ev_handshake_ack> = "established"_s
,"established"_s + sml::on_entry<_> / [](events& ev){ ev.established(); }
,"established"_s + sml::event<ev_payload> / [](events& ev, const ev_payload& e) {
ev.payload(e.data);
}
);
// clang-format on
}
};
struct protocol
{
auto operator()()
{
using namespace boost::sml;
namespace sml = boost::sml;
// clang-format off
return make_transition_table(
*"disconnected"_s + sml::event<ev_connect> = "connecting"_s
,"connecting"_s + sml::on_entry<_> / [](actions& ac) { ac.connect(); }
,"connecting"_s + sml::event<ev_connected> = state<connected>
,"connecting"_s + sml::event<ev_disconnect> = "disconnecting"_s
,state<connected> + sml::on_exit<_> / [](events& ev) { ev.disconnected(); }
,state<connected> + sml::event<ev_disconnect> = "disconnecting"_s
,state<connected> + sml::event<ev_retry> = "waiting_retry"_s
,state<connected> + sml::event<ev_fin> = "fin"_s
,state<connected> + sml::event<ev_error> / [](actions& ac, events& ev)
{
ac.disconnect(false);
ev.error();
} = X
,"disconnecting"_s + sml::on_entry<_> / [](actions& ac) { ac.disconnect(true); }
,"disconnecting"_s + sml::event<ev_disconnected> = "disconnected"_s
,"waiting_retry"_s + sml::on_entry<_> / [](actions& ac) { ac.wait_retry(); }
,"waiting_retry"_s + sml::event<ev_connect> = "connecting"_s
,"waiting_retry"_s + sml::event<ev_disconnect> = "disconnecting"_s
,"fin"_s + sml::on_entry<_> / [](actions& ac) { ac.disconnect(false); }
);
// clang-format on
}
};
auto operator()()
{
using namespace boost::sml;
namespace sml = boost::sml;
// clang-format off
return make_transition_table(
*state<protocol> + sml::event<ev_error> / [](actions& ac, events& ev)
{
ac.disconnect(false);
ev.error();
} = X
);
// clang-format on
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment