/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see .
*/
#include "utility/dict.hpp"
#include "resources/serializer.hpp"
#include "resources/serialize-error.hpp"
#include "resources/deserializer.hpp"
#include "resources/deserialize-error.hpp"
#include "utility/hash/fnv1a.hpp"
#include
#include
#include
#include
#include
using namespace hash::literals;
template
static void serialize_any(const std::any& any, serialize_context& ctx)
{
serializer().serialize(std::any_cast(any), ctx);
}
template
static void deserialize_any(std::any& any, deserialize_context& ctx)
{
T value;
deserializer().deserialize(value, ctx);
any = std::move(value);
}
/**
* Serializes a dict with an unsigned 32-bit key.
*
* @throw serialize_error Write error.
* @throw serialize_error Unsupported dict value type.
*/
template <>
void serializer>::serialize(const dict& dict, serialize_context& ctx)
{
// Map type indices to tuples containing a type hash and serialize function pointer
static const std::unordered_map
<
std::type_index,
std::tuple
<
std::uint32_t,
void (*)(const std::any&, serialize_context&)
>
> type_map
{
{std::type_index(typeid(bool)), {"bool"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::uint8_t)), {"uint8"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::uint16_t)), {"uint16"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::uint32_t)), {"uint32"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::uint64_t)), {"uint64"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::int8_t)), {"int8"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::int16_t)), {"int16"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::int32_t)), {"int32"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::int64_t)), {"int64"_fnv1a32, &serialize_any}},
{std::type_index(typeid(float)), {"float"_fnv1a32, &serialize_any}},
{std::type_index(typeid(double)), {"double"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::string)), {"string"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::u8string)), {"u8string"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::u16string)), {"u16string"_fnv1a32, &serialize_any}},
{std::type_index(typeid(std::u32string)), {"u32string"_fnv1a32, &serialize_any}}
};
// Write dict size
std::uint64_t size = static_cast(dict.size());
ctx.write64(reinterpret_cast(&size), 1);
// Write dict entries
for (const auto& [key, value]: dict)
{
if (auto i = type_map.find(value.type()); i != type_map.end())
{
const auto& [type_hash, type_serializer] = i->second;
// Write entry type hash and key
ctx.write32(reinterpret_cast(&type_hash), 1);
ctx.write32(reinterpret_cast(&key), 1);
// Serialize entry value
type_serializer(value, ctx);
}
else
{
throw serialize_error("Unsupported dict value type");
}
}
};
/**
* Deserializes a dict with an unsigned 32-bit key.
*
* @throw deserialize_error Write error.
* @throw deserialize_error Unsupported dict value type.
*/
template <>
void deserializer>::deserialize(dict& dict, deserialize_context& ctx)
{
// Map type hashes to deserialize function pointers
static const std::unordered_map
<
std::uint32_t,
void (*)(std::any&, deserialize_context&)
> type_map
{
{"bool"_fnv1a32, &deserialize_any},
{"uint8"_fnv1a32, &deserialize_any},
{"uint16"_fnv1a32, &deserialize_any},
{"uint32"_fnv1a32, &deserialize_any},
{"uint64"_fnv1a32, &deserialize_any},
{"int8"_fnv1a32, &deserialize_any},
{"int16"_fnv1a32, &deserialize_any},
{"int32"_fnv1a32, &deserialize_any},
{"int64"_fnv1a32, &deserialize_any},
{"float"_fnv1a32, &deserialize_any},
{"double"_fnv1a32, &deserialize_any},
{"string"_fnv1a32, &deserialize_any},
{"u8string"_fnv1a32, &deserialize_any},
{"u16string"_fnv1a32, &deserialize_any},
{"u32string"_fnv1a32, &deserialize_any}
};
// Read dict size
std::uint64_t size = 0;
ctx.read64(reinterpret_cast(&size), 1);
// Read dict entries
for (std::size_t i = 0; i < size; ++i)
{
// Read entry type hash
std::uint32_t type_hash = 0;
ctx.read32(reinterpret_cast(&type_hash), 1);
if (auto i = type_map.find(type_hash); i != type_map.end())
{
// Read entry key
std::uint32_t key = 0;
ctx.read32(reinterpret_cast(&key), 1);
// Deserialize entry value
i->second(dict[key], ctx);
}
else
{
throw deserialize_error("Unsupported dict value type");
}
}
};