The implementation is still far from perfect, it's at beast a proof of concept. There are many edge cases that are definitely still not covered, and many rough edges in the quality of the code. I am also not convinced that exceptions are the best error handling method for this, particularly for publicly exposes interfaces that may be much more susceptible to DoS attacks due to malformed input (and the resulting overhead in handling exceptions).
156 lines
3.8 KiB
C++
156 lines
3.8 KiB
C++
#include "CBOR/Decoder.hpp"
|
|
#include "CBOR/Encoder.hpp"
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <print>
|
|
#include <ranges>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
|
|
struct SomeStruct
|
|
{
|
|
std::string name;
|
|
double speed;
|
|
float fov;
|
|
std::int8_t thing;
|
|
std::int64_t slots;
|
|
std::uint32_t times;
|
|
std::vector<std::string> tools;
|
|
};
|
|
|
|
std::size_t Encode(const SomeStruct &value, std::span<std::uint8_t> buffer)
|
|
{
|
|
CBOR::BasicEncoder enc(buffer);
|
|
enc.BeginIndefiniteMap();
|
|
|
|
enc.Encode("name");
|
|
enc.Encode(value.name);
|
|
|
|
enc.Encode("speed");
|
|
enc.Encode(value.speed);
|
|
|
|
enc.Encode("fov");
|
|
enc.Encode(value.fov);
|
|
|
|
enc.Encode("thing");
|
|
enc.Encode(value.thing);
|
|
|
|
enc.Encode("slots");
|
|
enc.Encode(value.slots);
|
|
|
|
enc.Encode("times");
|
|
enc.Encode(value.times);
|
|
|
|
enc.Encode("tools");
|
|
enc.BeginIndefiniteArray();
|
|
for (std::string_view tool: value.tools) {
|
|
enc.Encode(tool);
|
|
}
|
|
enc.End();
|
|
|
|
enc.End();
|
|
|
|
return enc.EncodedSize();
|
|
}
|
|
|
|
SomeStruct Decode(std::span<std::uint8_t> buffer)
|
|
{
|
|
SomeStruct result;
|
|
|
|
CBOR::Decoder dec(buffer);
|
|
CBOR::Map object = dec.Map();
|
|
while (!object.Done()) {
|
|
CBOR::KeyValue kv = object.Next();
|
|
std::string_view key = kv.Key().String().Get();
|
|
CBOR::Item value = kv.Value();
|
|
if (key == "name") {
|
|
result.name = value.String().Get();
|
|
}
|
|
else if (key == "speed") {
|
|
result.speed = value.Double();
|
|
}
|
|
else if (key == "fov") {
|
|
result.fov = value.Float();
|
|
}
|
|
else if (key == "thing") {
|
|
result.thing = value.Int8();
|
|
}
|
|
else if (key == "slots") {
|
|
result.slots = value.Int64();
|
|
}
|
|
else if (key == "times") {
|
|
result.times = value.Uint32();
|
|
}
|
|
else if (key == "tools") {
|
|
CBOR::Array tools = value.Array();
|
|
while(!tools.Done()) {
|
|
result.tools.push_back(std::string(tools.Next().String().Get()));
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void Compare(const SomeStruct &s1, const SomeStruct &s2)
|
|
{
|
|
if (s1.name != s2.name) {
|
|
throw std::runtime_error("test error: names are not the same");
|
|
}
|
|
if (s1.speed != s2.speed) {
|
|
throw std::runtime_error("test error: speed is not the same");
|
|
}
|
|
if (s1.fov != s2.fov) {
|
|
throw std::runtime_error("test error: fovs are not the same");
|
|
}
|
|
if (s1.thing != s2.thing) {
|
|
throw std::runtime_error("test error: things are not the same");
|
|
}
|
|
if (s1.slots != s2.slots) {
|
|
throw std::runtime_error("test error: slots are not the same");
|
|
}
|
|
if (s1.times != s2.times) {
|
|
throw std::runtime_error("test error: times are not the same");
|
|
}
|
|
for (const auto &[t1, t2]: std::ranges::views::zip(s1.tools, s2.tools)) {
|
|
if (t1 != t2) {
|
|
throw std::runtime_error("test error: some tools are not the same");
|
|
}
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
using namespace std::string_view_literals;
|
|
|
|
std::array<std::uint8_t, 1024> buffer = {0};
|
|
|
|
SomeStruct expected {
|
|
.name = "Player1",
|
|
.speed = 5.0,
|
|
.fov = 110.0f,
|
|
.thing = -15,
|
|
.slots = 40'000'000,
|
|
.times = 1234567,
|
|
.tools = {
|
|
"pickaxe",
|
|
"sword",
|
|
"axe",
|
|
"magical arrow",
|
|
"iron ore",
|
|
},
|
|
};
|
|
|
|
try {
|
|
std::size_t encodedSize = Encode(expected, buffer);
|
|
std::println("Encoded size: {}", encodedSize);
|
|
|
|
SomeStruct result = Decode(std::span<std::uint8_t>(buffer.data(), encodedSize));
|
|
|
|
Compare(expected, result);
|
|
std::println("The test has been completed successfully.");
|
|
}
|
|
catch (const std::exception &e) {
|
|
std::println("Error: {}", e.what());
|
|
}
|
|
}
|