216 lines
5.4 KiB
C++
216 lines
5.4 KiB
C++
#pragma once
|
|
|
|
#include <string>
|
|
|
|
#include "communication/bolt/v1/messaging/codes.hpp"
|
|
#include "communication/bolt/v1/packing/codes.hpp"
|
|
#include "logging/default.hpp"
|
|
#include "utils/bswap.hpp"
|
|
#include "utils/types/byte.hpp"
|
|
|
|
namespace bolt
|
|
{
|
|
|
|
template <class Stream>
|
|
class BoltEncoder
|
|
{
|
|
static constexpr int64_t plus_2_to_the_31 = 2147483648L;
|
|
static constexpr int64_t plus_2_to_the_15 = 32768L;
|
|
static constexpr int64_t plus_2_to_the_7 = 128L;
|
|
static constexpr int64_t minus_2_to_the_4 = -16L;
|
|
static constexpr int64_t minus_2_to_the_7 = -128L;
|
|
static constexpr int64_t minus_2_to_the_15 = -32768L;
|
|
static constexpr int64_t minus_2_to_the_31 = -2147483648L;
|
|
|
|
public:
|
|
BoltEncoder(Stream &stream) : stream(stream)
|
|
{
|
|
logger = logging::log->logger("Bolt Encoder");
|
|
}
|
|
|
|
void write(byte value) { write_byte(value); }
|
|
|
|
void write_byte(byte value)
|
|
{
|
|
logger.trace("write byte: {}", value);
|
|
stream.write(value);
|
|
}
|
|
|
|
void write(const byte *values, size_t n) { stream.write(values, n); }
|
|
|
|
void write_null() { stream.write(pack::Null); }
|
|
|
|
void write(bool value) { write_bool(value); }
|
|
|
|
void write_bool(bool value)
|
|
{
|
|
if (value)
|
|
write_true();
|
|
else
|
|
write_false();
|
|
}
|
|
|
|
void write_true() { stream.write(pack::True); }
|
|
|
|
void write_false() { stream.write(pack::False); }
|
|
|
|
template <class T>
|
|
void write_value(T value)
|
|
{
|
|
value = bswap(value);
|
|
stream.write(reinterpret_cast<const byte *>(&value), sizeof(value));
|
|
}
|
|
|
|
void write_integer(int64_t value)
|
|
{
|
|
if (value >= minus_2_to_the_4 && value < plus_2_to_the_7) {
|
|
write(static_cast<byte>(value));
|
|
} else if (value >= minus_2_to_the_7 && value < minus_2_to_the_4) {
|
|
write(pack::Int8);
|
|
write(static_cast<byte>(value));
|
|
} else if (value >= minus_2_to_the_15 && value < plus_2_to_the_15) {
|
|
write(pack::Int16);
|
|
write_value(static_cast<int16_t>(value));
|
|
} else if (value >= minus_2_to_the_31 && value < plus_2_to_the_31) {
|
|
write(pack::Int32);
|
|
write_value(static_cast<int32_t>(value));
|
|
} else {
|
|
write(pack::Int64);
|
|
write_value(value);
|
|
}
|
|
}
|
|
|
|
void write(double value) { write_double(value); }
|
|
|
|
void write_double(double value)
|
|
{
|
|
write(pack::Float64);
|
|
write_value(*reinterpret_cast<const int64_t *>(&value));
|
|
}
|
|
|
|
void write_map_header(size_t size)
|
|
{
|
|
if (size < 0x10) {
|
|
write(static_cast<byte>(pack::TinyMap | size));
|
|
} else if (size <= 0xFF) {
|
|
write(pack::Map8);
|
|
write(static_cast<byte>(size));
|
|
} else if (size <= 0xFFFF) {
|
|
write(pack::Map16);
|
|
write_value<uint16_t>(size);
|
|
} else {
|
|
write(pack::Map32);
|
|
write_value<uint32_t>(size);
|
|
}
|
|
}
|
|
|
|
void write_empty_map() { write(pack::TinyMap); }
|
|
|
|
void write_list_header(size_t size)
|
|
{
|
|
if (size < 0x10) {
|
|
write(static_cast<byte>(pack::TinyList | size));
|
|
} else if (size <= 0xFF) {
|
|
write(pack::List8);
|
|
write(static_cast<byte>(size));
|
|
} else if (size <= 0xFFFF) {
|
|
write(pack::List16);
|
|
write_value<uint16_t>(size);
|
|
} else {
|
|
write(pack::List32);
|
|
write_value<uint32_t>(size);
|
|
}
|
|
}
|
|
|
|
void write_empty_list() { write(pack::TinyList); }
|
|
|
|
void write_string_header(size_t size)
|
|
{
|
|
if (size < 0x10) {
|
|
write(static_cast<byte>(pack::TinyString | size));
|
|
} else if (size <= 0xFF) {
|
|
write(pack::String8);
|
|
write(static_cast<byte>(size));
|
|
} else if (size <= 0xFFFF) {
|
|
write(pack::String16);
|
|
write_value<uint16_t>(size);
|
|
} else {
|
|
write(pack::String32);
|
|
write_value<uint32_t>(size);
|
|
}
|
|
}
|
|
|
|
void write_string(const std::string &str)
|
|
{
|
|
write_string(str.c_str(), str.size());
|
|
}
|
|
|
|
void write_string(const char *str, size_t len)
|
|
{
|
|
write_string_header(len);
|
|
write(reinterpret_cast<const byte *>(str), len);
|
|
}
|
|
|
|
void write_struct_header(size_t size)
|
|
{
|
|
if (size < 0x10) {
|
|
write(static_cast<byte>(pack::TinyStruct | size));
|
|
} else if (size <= 0xFF) {
|
|
write(pack::Struct8);
|
|
write(static_cast<byte>(size));
|
|
} else {
|
|
write(pack::Struct16);
|
|
write_value<uint16_t>(size);
|
|
}
|
|
}
|
|
|
|
void message_success()
|
|
{
|
|
write_struct_header(1);
|
|
write(underlying_cast(MessageCode::Success));
|
|
}
|
|
|
|
void message_success_empty()
|
|
{
|
|
message_success();
|
|
write_empty_map();
|
|
}
|
|
|
|
void message_record()
|
|
{
|
|
write_struct_header(1);
|
|
write(underlying_cast(MessageCode::Record));
|
|
}
|
|
|
|
void message_record_empty()
|
|
{
|
|
message_record();
|
|
write_empty_list();
|
|
}
|
|
|
|
void message_ignored()
|
|
{
|
|
write_struct_header(0);
|
|
write(underlying_cast(MessageCode::Ignored));
|
|
}
|
|
|
|
void message_failure()
|
|
{
|
|
write_struct_header(1);
|
|
write(underlying_cast(MessageCode::Failure));
|
|
}
|
|
|
|
void message_ignored_empty()
|
|
{
|
|
message_ignored();
|
|
write_empty_map();
|
|
}
|
|
|
|
protected:
|
|
Logger logger;
|
|
|
|
private:
|
|
Stream &stream;
|
|
};
|
|
}
|