Use helper template struct in MsgReader

This makes reads for all types, including String, Vector, and Optional,
use the same interface in MsgReader.
This commit is contained in:
Jason Felice 2019-04-20 12:43:52 -04:00
parent 17c5e7aa5f
commit 99be3ff5e2

View File

@ -150,6 +150,58 @@ private:
class MsgReader class MsgReader
{ {
private:
template<typename T>
struct Reader {
static T read(MsgReader& reader)
{
static_assert(std::is_trivially_copyable<T>::value, "");
T res;
reader.read(reinterpret_cast<char*>(&res), sizeof(T));
return res;
}
};
template<typename T, MemoryDomain domain>
struct Reader<Vector<T,domain>> {
static Vector<T, domain> read(MsgReader& reader)
{
uint32_t size = Reader<uint32_t>::read(reader);
Vector<T,domain> res;
res.reserve(size);
while (size--)
res.push_back(std::move(Reader<T>::read(reader)));
return res;
}
};
template<typename Key, typename Value, MemoryDomain domain>
struct Reader<HashMap<Key, Value, domain>> {
static HashMap<Key, Value, domain> read(MsgReader& reader)
{
uint32_t size = Reader<uint32_t>::read(reader);
HashMap<Key, Value, domain> res;
res.reserve(size);
while (size--)
{
auto key = Reader<Key>::read(reader);
auto val = Reader<Value>::read(reader);
res.insert({std::move(key), std::move(val)});
}
return res;
}
};
template<typename T>
struct Reader<Optional<T>> {
static Optional<T> read(MsgReader& reader)
{
if (not Reader<bool>::read(reader))
return {};
return Reader<T>::read(reader);
}
};
public: public:
void read_available(int sock) void read_available(int sock)
{ {
@ -198,44 +250,7 @@ public:
template<typename T> template<typename T>
T read() T read()
{ {
static_assert(std::is_trivially_copyable<T>::value, ""); return Reader<T>::read(*this);
T res;
read(reinterpret_cast<char*>(&res), sizeof(T));
return res;
}
template<typename T>
Vector<T> read_vector()
{
uint32_t size = read<uint32_t>();
Vector<T> res;
res.reserve(size);
while (size--)
res.push_back(read<T>());
return res;
}
template<typename Key, typename Val, MemoryDomain domain>
HashMap<Key, Val, domain> read_hash_map()
{
uint32_t size = read<uint32_t>();
HashMap<Key, Val, domain> res;
res.reserve(size);
while (size--)
{
auto key = read<Key>();
auto val = read<Val>();
res.insert({std::move(key), std::move(val)});
}
return res;
}
template<typename T>
Optional<T> read_optional()
{
if (not read<bool>())
return {};
return read<T>();
} }
void reset() void reset()
@ -262,52 +277,62 @@ private:
}; };
template<> template<>
String MsgReader::read<String>() struct MsgReader::Reader<String> {
{ static String read(MsgReader& reader)
ByteCount length = read<ByteCount>();
String res;
if (length > 0)
{ {
res.force_size((int)length); ByteCount length = Reader<ByteCount>::read(reader);
read(&res[0_byte], (int)length); String res;
if (length > 0)
{
res.force_size((int)length);
reader.read(&res[0_byte], (int)length);
}
return res;
} }
return res; };
}
template<> template<>
Color MsgReader::read<Color>() struct MsgReader::Reader<Color> {
{ static Color read(MsgReader& reader)
Color res;
res.color = read<Color::NamedColor>();
if (res.color == Color::RGB)
{ {
res.r = read<unsigned char>(); Color res;
res.g = read<unsigned char>(); res.color = Reader<Color::NamedColor>::read(reader);
res.b = read<unsigned char>(); if (res.color == Color::RGB)
{
res.r = Reader<unsigned char>::read(reader);
res.g = Reader<unsigned char>::read(reader);
res.b = Reader<unsigned char>::read(reader);
}
return res;
} }
return res; };
}
template<> template<>
DisplayAtom MsgReader::read<DisplayAtom>() struct MsgReader::Reader<DisplayAtom> {
{ static DisplayAtom read(MsgReader& reader)
String content = read<String>(); {
return {std::move(content), read<Face>()}; String content = Reader<String>::read(reader);
} return {std::move(content), Reader<Face>::read(reader)};
}
};
template<> template<>
DisplayLine MsgReader::read<DisplayLine>() struct MsgReader::Reader<DisplayLine> {
{ static DisplayLine read(MsgReader& reader)
return {read_vector<DisplayAtom>()}; {
} return {Reader<Vector<DisplayAtom>>::read(reader)};
}
};
template<> template<>
DisplayBuffer MsgReader::read<DisplayBuffer>() struct MsgReader::Reader<DisplayBuffer> {
{ static DisplayBuffer read(MsgReader& reader)
DisplayBuffer db; {
db.lines() = read_vector<DisplayLine>(); DisplayBuffer db;
return db; db.lines() = Reader<Vector<DisplayLine>>::read(reader);
} return db;
}
};
class RemoteUI : public UserInterface class RemoteUI : public UserInterface
@ -603,7 +628,7 @@ RemoteClient::RemoteClient(StringView session, StringView name, std::unique_ptr<
{ {
case MessageType::MenuShow: case MessageType::MenuShow:
{ {
auto choices = reader.read_vector<DisplayLine>(); auto choices = reader.read<Vector<DisplayLine>>();
auto anchor = reader.read<DisplayCoord>(); auto anchor = reader.read<DisplayCoord>();
auto fg = reader.read<Face>(); auto fg = reader.read<Face>();
auto bg = reader.read<Face>(); auto bg = reader.read<Face>();
@ -657,7 +682,7 @@ RemoteClient::RemoteClient(StringView session, StringView name, std::unique_ptr<
m_ui->refresh(reader.read<bool>()); m_ui->refresh(reader.read<bool>());
break; break;
case MessageType::SetOptions: case MessageType::SetOptions:
m_ui->set_ui_options(reader.read_hash_map<String, String, MemoryDomain::Options>()); m_ui->set_ui_options(reader.read<HashMap<String, String, MemoryDomain::Options>>());
break; break;
case MessageType::Exit: case MessageType::Exit:
m_exit_status = reader.read<int>(); m_exit_status = reader.read<int>();
@ -723,9 +748,9 @@ private:
auto pid = m_reader.read<int>(); auto pid = m_reader.read<int>();
auto name = m_reader.read<String>(); auto name = m_reader.read<String>();
auto init_cmds = m_reader.read<String>(); auto init_cmds = m_reader.read<String>();
auto init_coord = m_reader.read_optional<BufferCoord>(); auto init_coord = m_reader.read<Optional<BufferCoord>>();
auto dimensions = m_reader.read<DisplayCoord>(); auto dimensions = m_reader.read<DisplayCoord>();
auto env_vars = m_reader.read_hash_map<String, String, MemoryDomain::EnvVars>(); auto env_vars = m_reader.read<HashMap<String, String, MemoryDomain::EnvVars>>();
auto* ui = new RemoteUI{sock, dimensions}; auto* ui = new RemoteUI{sock, dimensions};
ClientManager::instance().create_client( ClientManager::instance().create_client(
std::unique_ptr<UserInterface>(ui), pid, std::move(name), std::unique_ptr<UserInterface>(ui), pid, std::move(name),