Use some template magic to automatically deserialize UI messages

We always deserialize arguments in order, and we can extract
argument types from the type of the pointer to method.
This commit is contained in:
Maxime Coste 2022-11-29 17:19:09 +11:00
parent 2688893156
commit cd73f2aa17

View File

@ -183,6 +183,9 @@ private:
} }
}; };
template<typename T>
struct Reader<ArrayView<T>> : Reader<Vector<std::remove_cv_t<T>, MemoryDomain::Undefined>> {};
template<typename Key, typename Value, MemoryDomain domain> template<typename Key, typename Value, MemoryDomain domain>
struct Reader<HashMap<Key, Value, domain>> { struct Reader<HashMap<Key, Value, domain>> {
static HashMap<Key, Value, domain> read(MsgReader& reader) static HashMap<Key, Value, domain> read(MsgReader& reader)
@ -256,7 +259,7 @@ public:
} }
template<typename T> template<typename T>
T read() auto read()
{ {
return Reader<T>::read(*this); return Reader<T>::read(*this);
} }
@ -664,6 +667,17 @@ RemoteClient::RemoteClient(StringView session, StringView name, std::unique_ptr<
if (events & FdEvents::Write and send_data(sock, m_send_buffer)) if (events & FdEvents::Write and send_data(sock, m_send_buffer))
watcher.events() &= ~FdEvents::Write; watcher.events() &= ~FdEvents::Write;
auto exec = [&]<typename ...Args>(void (UserInterface::*method)(Args...)) {
struct Impl // Use a constructor to ensure left-to-right parameter evaluation
{
Impl(UserInterface& ui, void (UserInterface::*method)(Args...), Args... args)
{
(ui.*method)(std::forward<Args>(args)...);
}
};
Impl{*m_ui, method, reader.read<std::remove_cvref_t<Args>>()...};
};
while (events & FdEvents::Read and while (events & FdEvents::Read and
not reader.ready() and fd_readable(sock)) not reader.ready() and fd_readable(sock))
{ {
@ -676,62 +690,34 @@ RemoteClient::RemoteClient(StringView session, StringView name, std::unique_ptr<
switch (reader.type()) switch (reader.type())
{ {
case MessageType::MenuShow: case MessageType::MenuShow:
{ exec(&UserInterface::menu_show);
auto choices = reader.read<Vector<DisplayLine>>();
auto anchor = reader.read<DisplayCoord>();
auto fg = reader.read<Face>();
auto bg = reader.read<Face>();
auto style = reader.read<MenuStyle>();
m_ui->menu_show(choices, anchor, fg, bg, style);
break; break;
}
case MessageType::MenuSelect: case MessageType::MenuSelect:
m_ui->menu_select(reader.read<int>()); exec(&UserInterface::menu_select);
break; break;
case MessageType::MenuHide: case MessageType::MenuHide:
m_ui->menu_hide(); exec(&UserInterface::menu_hide);
break; break;
case MessageType::InfoShow: case MessageType::InfoShow:
{ exec(&UserInterface::info_show);
auto title = reader.read<DisplayLine>();
auto content = reader.read<DisplayLineList>();
auto anchor = reader.read<DisplayCoord>();
auto face = reader.read<Face>();
auto style = reader.read<InfoStyle>();
m_ui->info_show(title, content, anchor, face, style);
break; break;
}
case MessageType::InfoHide: case MessageType::InfoHide:
m_ui->info_hide(); exec(&UserInterface::info_hide);
break; break;
case MessageType::Draw: case MessageType::Draw:
{ exec(&UserInterface::draw);
auto display_buffer = reader.read<DisplayBuffer>();
auto default_face = reader.read<Face>();
auto padding_face = reader.read<Face>();
m_ui->draw(display_buffer, default_face, padding_face);
break; break;
}
case MessageType::DrawStatus: case MessageType::DrawStatus:
{ exec(&UserInterface::draw_status);
auto status_line = reader.read<DisplayLine>();
auto mode_line = reader.read<DisplayLine>();
auto default_face = reader.read<Face>();
m_ui->draw_status(status_line, mode_line, default_face);
break; break;
}
case MessageType::SetCursor: case MessageType::SetCursor:
{ exec(&UserInterface::set_cursor);
auto mode = reader.read<CursorMode>();
auto coord = reader.read<DisplayCoord>();
m_ui->set_cursor(mode, coord);
break; break;
}
case MessageType::Refresh: case MessageType::Refresh:
m_ui->refresh(reader.read<bool>()); exec(&UserInterface::refresh);
break; break;
case MessageType::SetOptions: case MessageType::SetOptions:
m_ui->set_ui_options(reader.read<HashMap<String, String, MemoryDomain::Options>>()); exec(&UserInterface::set_ui_options);
break; break;
case MessageType::Exit: case MessageType::Exit:
m_exit_status = reader.read<int>(); m_exit_status = reader.read<int>();