diff --git a/src/serialization.cpp b/src/serialization.cpp index c305d10..0894b0d 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -2,8 +2,6 @@ #include "connection.h" #include "discord-rpc.h" -MallocAllocator MallocAllocatorInst; - // it's ever so slightly faster to not have to strlen the key template void WriteKey(JsonWriter& w, T& k) @@ -11,6 +9,35 @@ void WriteKey(JsonWriter& w, T& k) w.Key(k, sizeof(T) - 1); } +struct WriteObject { + JsonWriter& writer; + WriteObject(JsonWriter& w) + : writer(w) + { + writer.StartObject(); + } + template + WriteObject(JsonWriter& w, T& name) + : writer(w) + { + WriteKey(writer, name); + writer.StartObject(); + } + ~WriteObject() { writer.EndObject(); } +}; + +struct WriteArray { + JsonWriter& writer; + template + WriteArray(JsonWriter& w, T& name) + : writer(w) + { + WriteKey(writer, name); + writer.StartArray(); + } + ~WriteArray() { writer.EndArray(); } +}; + template void WriteOptionalString(JsonWriter& w, T& k, const char* value) { @@ -28,150 +55,115 @@ void JsonWriteNonce(JsonWriter& writer, int nonce) writer.String(nonceBuffer); } -void JsonWriteCommandStart(JsonWriter& writer, int nonce, const char* cmd) -{ - writer.StartObject(); - - JsonWriteNonce(writer, nonce); - - WriteKey(writer, "cmd"); - writer.String(cmd); - - WriteKey(writer, "args"); - writer.StartObject(); -} - -void JsonWriteCommandEnd(JsonWriter& writer) -{ - writer.EndObject(); // args - writer.EndObject(); // top level -} - size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, int nonce, int pid, const DiscordRichPresence* presence) { - DirectStringBuffer sb(dest, maxLen); - StackAllocator wa; - JsonWriter writer(sb, &wa, WriterNestingLevels); + JsonWriter writer(dest, maxLen); - JsonWriteCommandStart(writer, nonce, "SET_ACTIVITY"); + { + WriteObject top(writer); - WriteKey(writer, "pid"); - writer.Int(pid); + JsonWriteNonce(writer, nonce); - WriteKey(writer, "activity"); - writer.StartObject(); + WriteKey(writer, "cmd"); + writer.String("SET_ACTIVITY"); - WriteOptionalString(writer, "state", presence->state); - WriteOptionalString(writer, "details", presence->details); + { + WriteObject args(writer, "args"); - if (presence->startTimestamp || presence->endTimestamp) { - WriteKey(writer, "timestamps"); - writer.StartObject(); + WriteKey(writer, "pid"); + writer.Int(pid); - if (presence->startTimestamp) { - WriteKey(writer, "start"); - writer.Int64(presence->startTimestamp); - } + { + WriteObject activity(writer, "activity"); - if (presence->endTimestamp) { - WriteKey(writer, "end"); - writer.Int64(presence->endTimestamp); - } + WriteOptionalString(writer, "state", presence->state); + WriteOptionalString(writer, "details", presence->details); - writer.EndObject(); - } + if (presence->startTimestamp || presence->endTimestamp) { + WriteObject timestamps(writer, "timestamps"); - if (presence->largeImageKey || presence->largeImageText || presence->smallImageKey || - presence->smallImageText) { - WriteKey(writer, "assets"); - writer.StartObject(); + if (presence->startTimestamp) { + WriteKey(writer, "start"); + writer.Int64(presence->startTimestamp); + } - WriteOptionalString(writer, "large_image", presence->largeImageKey); - WriteOptionalString(writer, "large_text", presence->largeImageText); - WriteOptionalString(writer, "small_image", presence->smallImageKey); - WriteOptionalString(writer, "small_text", presence->smallImageText); + if (presence->endTimestamp) { + WriteKey(writer, "end"); + writer.Int64(presence->endTimestamp); + } + } - writer.EndObject(); - } + if (presence->largeImageKey || presence->largeImageText || + presence->smallImageKey || presence->smallImageText) { + WriteObject assets(writer, "assets"); + WriteOptionalString(writer, "large_image", presence->largeImageKey); + WriteOptionalString(writer, "large_text", presence->largeImageText); + WriteOptionalString(writer, "small_image", presence->smallImageKey); + WriteOptionalString(writer, "small_text", presence->smallImageText); + } - if (presence->partyId || presence->partySize || presence->partyMax) { - WriteKey(writer, "party"); - writer.StartObject(); + if (presence->partyId || presence->partySize || presence->partyMax) { + WriteObject party(writer, "party"); + WriteOptionalString(writer, "id", presence->partyId); + if (presence->partySize) { + WriteArray size(writer, "size"); + writer.Int(presence->partySize); + if (0 < presence->partyMax) { + writer.Int(presence->partyMax); + } + } + } - WriteOptionalString(writer, "id", presence->partyId); - if (presence->partySize) { - WriteKey(writer, "size"); - writer.StartArray(); + if (presence->matchSecret || presence->joinSecret || presence->spectateSecret) { + WriteObject secrets(writer, "secrets"); + WriteOptionalString(writer, "match", presence->matchSecret); + WriteOptionalString(writer, "join", presence->joinSecret); + WriteOptionalString(writer, "spectate", presence->spectateSecret); + } - writer.Int(presence->partySize); - if (0 < presence->partyMax) { - writer.Int(presence->partyMax); + writer.Key("instance"); + writer.Bool(presence->instance != 0); } - - writer.EndArray(); } - - writer.EndObject(); } - if (presence->matchSecret || presence->joinSecret || presence->spectateSecret) { - WriteKey(writer, "secrets"); - writer.StartObject(); - - WriteOptionalString(writer, "match", presence->matchSecret); - WriteOptionalString(writer, "join", presence->joinSecret); - WriteOptionalString(writer, "spectate", presence->spectateSecret); - - writer.EndObject(); - } - - writer.Key("instance"); - writer.Bool(presence->instance != 0); - - writer.EndObject(); // activity - - JsonWriteCommandEnd(writer); - - return sb.GetSize(); + return writer.Size(); } size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId) { - DirectStringBuffer sb(dest, maxLen); - StackAllocator wa; - JsonWriter writer(sb, &wa, WriterNestingLevels); + JsonWriter writer(dest, maxLen); - writer.StartObject(); - WriteKey(writer, "v"); - writer.Int(version); - WriteKey(writer, "client_id"); - writer.String(applicationId); - writer.EndObject(); + { + WriteObject obj(writer); + WriteKey(writer, "v"); + writer.Int(version); + WriteKey(writer, "client_id"); + writer.String(applicationId); + } - return sb.GetSize(); + return writer.Size(); } size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) { - DirectStringBuffer sb(dest, maxLen); - StackAllocator wa; - JsonWriter writer(sb, &wa, WriterNestingLevels); + JsonWriter writer(dest, maxLen); - writer.StartObject(); + { + WriteObject obj(writer); - JsonWriteNonce(writer, nonce); + JsonWriteNonce(writer, nonce); - WriteKey(writer, "cmd"); - writer.String("SUBSCRIBE"); + WriteKey(writer, "cmd"); + writer.String("SUBSCRIBE"); - WriteKey(writer, "evt"); - writer.String(evtName); + WriteKey(writer, "evt"); + writer.String(evtName); + } - writer.EndObject(); - - return sb.GetSize(); + return writer.Size(); } diff --git a/src/serialization.h b/src/serialization.h index 172b67b..f961d3c 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -120,8 +120,23 @@ using UTF8 = rapidjson::UTF8; // Writer appears to need about 16 bytes per nested object level (with 64bit size_t) using StackAllocator = FixedLinearAllocator<2048>; constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t)); -using JsonWriter = +using JsonWriterBase = rapidjson::Writer; +class JsonWriter : public JsonWriterBase { +public: + DirectStringBuffer stringBuffer_; + StackAllocator stackAlloc_; + + JsonWriter(char* dest, size_t maxLen) + : JsonWriterBase(stringBuffer_, &stackAlloc_, WriterNestingLevels) + , stringBuffer_(dest, maxLen) + , stackAlloc_() + { + } + + size_t Size() const { return stringBuffer_.GetSize(); } +}; + using JsonDocumentBase = rapidjson::GenericDocument; class JsonDocument : public JsonDocumentBase { public: