2017-07-20 21:24:18 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
2017-07-24 18:54:47 +01:00
|
|
|
#include "rapidjson/document.h"
|
|
|
|
#include "rapidjson/writer.h"
|
|
|
|
#include "rapidjson/stringbuffer.h"
|
|
|
|
#include "rapidjson/internal/itoa.h"
|
|
|
|
|
2017-07-20 21:24:18 +01:00
|
|
|
// if only there was a standard library function for this
|
2017-07-25 17:27:48 +01:00
|
|
|
template <size_t Len>
|
|
|
|
inline size_t StringCopy(char (&dest)[Len], const char* src)
|
|
|
|
{
|
2017-07-20 21:24:18 +01:00
|
|
|
if (!dest || !src || !Len) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
size_t copied;
|
|
|
|
char* out = dest;
|
|
|
|
for (copied = 1; *src && copied < Len; ++copied) {
|
|
|
|
*out++ = *src++;
|
|
|
|
}
|
|
|
|
*out = 0;
|
|
|
|
return copied - 1;
|
|
|
|
}
|
|
|
|
|
2017-07-20 22:59:32 +01:00
|
|
|
size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId);
|
|
|
|
|
2017-07-20 23:59:15 +01:00
|
|
|
// Commands
|
2017-07-20 21:24:18 +01:00
|
|
|
struct DiscordRichPresence;
|
2017-07-25 17:27:48 +01:00
|
|
|
size_t JsonWriteRichPresenceObj(char* dest,
|
|
|
|
size_t maxLen,
|
|
|
|
int nonce,
|
|
|
|
int pid,
|
|
|
|
const DiscordRichPresence* presence);
|
2017-07-21 23:42:59 +01:00
|
|
|
size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName);
|
2017-07-24 18:54:47 +01:00
|
|
|
|
2017-07-25 17:27:48 +01:00
|
|
|
// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need
|
|
|
|
// to supply some of
|
2017-07-24 18:54:47 +01:00
|
|
|
// your own allocators for stuff rather than use the defaults
|
|
|
|
|
|
|
|
class LinearAllocator {
|
|
|
|
public:
|
|
|
|
char* buffer_;
|
|
|
|
char* end_;
|
2017-07-25 17:27:48 +01:00
|
|
|
LinearAllocator()
|
|
|
|
{
|
2017-07-24 18:54:47 +01:00
|
|
|
assert(0); // needed for some default case in rapidjson, should not use
|
|
|
|
}
|
2017-07-25 17:27:48 +01:00
|
|
|
LinearAllocator(char* buffer, size_t size)
|
|
|
|
: buffer_(buffer)
|
|
|
|
, end_(buffer + size)
|
|
|
|
{
|
|
|
|
}
|
2017-07-24 18:54:47 +01:00
|
|
|
static const bool kNeedFree = false;
|
|
|
|
void* Malloc(size_t size)
|
|
|
|
{
|
|
|
|
char* res = buffer_;
|
|
|
|
buffer_ += size;
|
|
|
|
if (buffer_ > end_) {
|
|
|
|
buffer_ = res;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
|
|
|
|
{
|
|
|
|
if (newSize == 0) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
// allocate how much you need in the first place
|
|
|
|
assert(!originalPtr && !originalSize);
|
|
|
|
return Malloc(newSize);
|
|
|
|
}
|
2017-07-25 17:27:48 +01:00
|
|
|
static void Free(void* ptr) { /* shrug */}
|
2017-07-24 18:54:47 +01:00
|
|
|
};
|
|
|
|
|
2017-07-25 17:27:48 +01:00
|
|
|
template <size_t Size>
|
2017-07-24 18:54:47 +01:00
|
|
|
class FixedLinearAllocator : public LinearAllocator {
|
|
|
|
public:
|
|
|
|
char fixedBuffer_[Size];
|
2017-07-25 17:27:48 +01:00
|
|
|
FixedLinearAllocator()
|
|
|
|
: LinearAllocator(fixedBuffer_, Size)
|
|
|
|
{
|
|
|
|
}
|
2017-07-24 18:54:47 +01:00
|
|
|
static const bool kNeedFree = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
// wonder why this isn't a thing already, maybe I missed it
|
|
|
|
class DirectStringBuffer {
|
|
|
|
public:
|
|
|
|
typedef typename char Ch;
|
|
|
|
char* buffer_;
|
|
|
|
char* end_;
|
|
|
|
char* current_;
|
|
|
|
|
|
|
|
DirectStringBuffer(char* buffer, size_t maxLen)
|
2017-07-25 17:27:48 +01:00
|
|
|
: buffer_(buffer)
|
|
|
|
, end_(buffer + maxLen)
|
|
|
|
, current_(buffer)
|
|
|
|
{
|
|
|
|
}
|
2017-07-24 18:54:47 +01:00
|
|
|
|
|
|
|
void Put(char c)
|
|
|
|
{
|
|
|
|
if (current_ < end_) {
|
|
|
|
*current_++ = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void Flush() {}
|
2017-07-25 17:27:48 +01:00
|
|
|
size_t GetSize() const { return current_ - buffer_; }
|
2017-07-24 18:54:47 +01:00
|
|
|
};
|
|
|
|
|
2017-07-24 22:59:45 +01:00
|
|
|
using MallocAllocator = rapidjson::CrtAllocator;
|
|
|
|
using PoolAllocator = rapidjson::MemoryPoolAllocator<MallocAllocator>;
|
2017-07-24 18:54:47 +01:00
|
|
|
using UTF8 = rapidjson::UTF8<char>;
|
|
|
|
// Writer appears to need about 16 bytes per nested object level (with 64bit size_t)
|
2017-07-24 22:59:45 +01:00
|
|
|
using StackAllocator = FixedLinearAllocator<2048>;
|
2017-07-24 18:54:47 +01:00
|
|
|
constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t));
|
2017-07-25 17:27:48 +01:00
|
|
|
using JsonWriter =
|
|
|
|
rapidjson::Writer<DirectStringBuffer, UTF8, UTF8, StackAllocator, rapidjson::kWriteNoFlags>;
|
2017-07-25 17:06:48 +01:00
|
|
|
using JsonDocumentBase = rapidjson::GenericDocument<UTF8, PoolAllocator, StackAllocator>;
|
2017-07-25 17:27:48 +01:00
|
|
|
class JsonDocument : public JsonDocumentBase {
|
2017-07-25 17:06:48 +01:00
|
|
|
public:
|
|
|
|
static const int kDefaultChunkCapacity = 32 * 1024;
|
2017-07-25 17:27:48 +01:00
|
|
|
// json parser will use this buffer first, then allocate more if needed; I seriously doubt we
|
|
|
|
// send any messages that would use all of this, though.
|
2017-07-25 17:06:48 +01:00
|
|
|
char parseBuffer_[32 * 1024];
|
|
|
|
MallocAllocator mallocAllocator_;
|
|
|
|
PoolAllocator poolAllocator_;
|
|
|
|
StackAllocator stackAllocator_;
|
2017-07-25 17:27:48 +01:00
|
|
|
JsonDocument()
|
|
|
|
: JsonDocumentBase(rapidjson::kObjectType,
|
|
|
|
&poolAllocator_,
|
|
|
|
sizeof(stackAllocator_.fixedBuffer_),
|
|
|
|
&stackAllocator_)
|
|
|
|
, poolAllocator_(parseBuffer_, sizeof(parseBuffer_), kDefaultChunkCapacity, &mallocAllocator_)
|
|
|
|
, stackAllocator_()
|
|
|
|
{
|
|
|
|
}
|
2017-07-25 17:06:48 +01:00
|
|
|
};
|