Skip to content

Commit

Permalink
dev: Add an improved version of serialization.
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmin42 committed Oct 1, 2024
1 parent e89c0ef commit c01630e
Show file tree
Hide file tree
Showing 6 changed files with 353 additions and 37 deletions.
5 changes: 4 additions & 1 deletion PB/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ add_library(${PBLIB_LIBRARY_NAME} STATIC
include/pb/components/OGLEngine.h
include/pb/components/RuntimeUUID.h
include/pb/components/SVGInflater.h
include/pb/components/Serializer.h
include/pb/components/SerializationStrategy.h
include/pb/components/SkiaResources.h
include/pb/components/TSQueue.h
Expand Down Expand Up @@ -187,6 +188,7 @@ add_library(${PBLIB_LIBRARY_NAME} STATIC
src/RegularImageV2.cpp
src/RuntimeUUID.cpp
src/SVGInflater.cpp
src/Serializer.cpp
src/SerializationStrategy.cpp
src/SkiaResources.cpp
src/StagedImages.cpp
Expand Down Expand Up @@ -240,7 +242,8 @@ add_executable(${PBLIB_TESTS_LIBRARY_NAME}
tests/TestMain.cpp
tests/TestDurableHashService.cpp
tests/TestProjectSerializerService.cpp
tests/TestProjectManagementSystem.cpp)
tests/TestProjectManagementSystem.cpp
tests/TestSerializer.cpp)

target_include_directories(${PBLIB_TESTS_LIBRARY_NAME} PRIVATE
include
Expand Down
162 changes: 162 additions & 0 deletions PB/include/pb/components/Serializer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#pragma once

#include <variant>

#pragma warning(push)
#pragma warning(disable : 4996)
#include <spdlog/spdlog.h>
#pragma warning(pop)

#include <pb/util/Concepts.h>
#include <pb/util/Traits.h>

namespace PB {
// TODO: There is still some work to do here to handle the & const and && cases.

template <SerializationPrimitiveConcept T>
std::variant<Json, PBDev::Error> flatSimple(int depth, T object)
{
UNUSED(depth);
#ifdef _CLANG_UML_
Json json;
#else
Json json = object;
#endif
return json;
}

template <typename T>
std::variant<Json, PBDev::Error> flatSimple(int depth, T entry);

template <SerializationPrimitiveConcept T>
std::variant<Json, PBDev::Error> flatAndTagSimple(int depth, std::string tag,
T object)
{
Json json;
json[tag] = object;
#ifndef _CLANG_UML_
spdlog::info("{}T {}\n", std::string(depth * 2, ' '), json.dump());
#endif
return json;
}

template <typename T>
std::variant<Json, PBDev::Error> flatAndTagSimple(int depth, std::string tag,
T object)
{
Json json;

std::variant<Json, PBDev::Error> jsonOrError = flatSimple(depth, object);

if (std::holds_alternative<PBDev::Error>(jsonOrError)) {
return jsonOrError;
}
json[tag] = std::get<Json>(jsonOrError);
#ifndef _CLANG_UML_
spdlog::info("{}T {}\n", std::string(depth * 2, ' '), json.dump());
#endif
return json;
}

template <typename Head, typename... Tail>
std::variant<Json, PBDev::Error>
flatDictionary(int depth, std::tuple<std::string, Head> const &head,
std::tuple<std::string, Tail> const &...args)
{
std::variant<Json, PBDev::Error> jsonOrError =
flatDictionary<Tail...>(depth + 1, args...);

if (std::holds_alternative<PBDev::Error>(jsonOrError)) {
return jsonOrError;
}
#ifndef _CLANG_UML_
spdlog::info("{}T {}\n", std::string(depth * 2, ' '),
std::get<Json>(jsonOrError).dump());
#endif
auto &[tag, head] = head;

std::variant<Json, PBDev::Error> headJsonOrError =
flatAndTagSimple<Head>(depth + 1, tag, head);

if (std::holds_alternative<PBDev::Error>(headJsonOrError)) {
return headJsonOrError;
}
#ifndef _CLANG_UML_
spdlog::info("{}T {}\n", std::string(depth * 2, ' '),
std::get<Json>(headJsonOrError).dump());
#endif
std::get<Json>(jsonOrError).update(std::get<Json>(headJsonOrError));
#ifndef _CLANG_UML_
spdlog::info("{}T {}\n", std::string(depth * 2, ' '),
std::get<Json>(jsonOrError).dump());
#endif
return jsonOrError;
}

template <typename... Tail>
std::variant<Json, PBDev::Error>
flatAndTagDictionary(int depth, std::string tag,
std::tuple<std::string, Tail> const &...args)
{
std::variant<Json, PBDev::Error> jsonOrError =
flatDictionary<Tail...>(depth + 1, args...);

if (std::holds_alternative<PBDev::Error>(jsonOrError)) {
return jsonOrError;
}

Json json;
json[tag] = std::get<Json>(jsonOrError);
return json;
}
template <typename T>
std::variant<Json, PBDev::Error> flatMaybeContainer(int depth,
T const &maybeContainer)
{
if constexpr (ContainerConcept<T>) {
Json json;
for (auto element : maybeContainer) {
using ValueType = typename T::value_type;
std::variant<Json, PBDev::Error> elementOrError =
flatMaybeContainer<ValueType>(depth + 1, element);
if (std::holds_alternative<PBDev::Error>(elementOrError)) {
return elementOrError;
}
json.push_back(std::get<Json>(elementOrError));
}
return json;
}
else if constexpr (StdMapsConcept<T>) {
Json json;
for (auto [key, value] : maybeContainer) {
std::variant<Json, PBDev::Error> valueOrError =
flatMaybeContainer(depth + 1, value);
if (std::holds_alternative<PBDev::Error>(valueOrError)) {
return valueOrError;
}

json[key] = std::get<Json>(valueOrError);
}

return json;
}
else if constexpr (BimapConcept<T>) {
Json json;
for (auto entry : maybeContainer) {
auto &value = entry.right;
std::variant<Json, PBDev::Error> valueOrError =
flatMaybeContainer(depth + 1, value);
if (std::holds_alternative<PBDev::Error>(valueOrError)) {
return valueOrError;
}

json[entry.left] = std::get<Json>(valueOrError);
}
return json;
}
else {
return flatSimple<T>(depth, maybeContainer);
}
}

} // namespace PB
68 changes: 43 additions & 25 deletions PB/include/pb/util/Concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <concepts>
#include <optional>

#include <boost/bimap/bimap.hpp>

#include <pb/util/Error.h>
#include <pb/util/Traits.h>

Expand All @@ -11,36 +13,52 @@ namespace PB {
template <typename T>
concept SerializationPrimitiveConcept =
std::same_as<T, int> || std::same_as<T, bool> ||
std::same_as<T, std::string> || std::same_as<T, Path>;
std::same_as<T, unsigned> || std::same_as<T, std::string> ||
std::same_as<T, Path>;

template <typename T>
concept ContainerConcept = requires(T a, typename T::value_type v) {
{
a.begin()
} -> std::same_as<typename T::iterator>;
{
a.end()
} -> std::same_as<typename T::iterator>;
concept BimapConcept = requires(T t, typename T::left_value_type lkey,
typename T::right_value_type rkey) {
{
a.size()
} -> std::convertible_to<std::size_t>;
{
a.empty()
} -> std::same_as<bool>;
a.insert(a.end(), v);
t.left.erase(lkey)
} -> std::same_as<size_t>;
};

template <typename T>
concept TaskConcept = requires(T a) {
{
a.taskStep()
};
{
a.stoppingCondition()
} -> std::same_as<bool>;
{
a.stepsCount()
} -> std::same_as<int>;
};
concept StdMapsConcept =
requires(T a, typename T::key_type k, typename T::mapped_type v) {
{
a.begin()
} -> std::same_as<typename T::iterator>;
{
a.end()
} -> std::same_as<typename T::iterator>;
{
a.size()
} -> std::convertible_to<std::size_t>;
{
a.empty()
} -> std::same_as<bool>;
a.insert({k, v});
} && !BimapConcept<T>;

template <typename T>
concept ContainerConcept =
requires(T a, typename T::value_type v) {
{
a.begin()
} -> std::same_as<typename T::iterator>;
{
a.end()
} -> std::same_as<typename T::iterator>;
{
a.size()
} -> std::convertible_to<std::size_t>;
{
a.empty()
} -> std::same_as<bool>;
a.insert(a.end(), v);
} && !std::same_as<T, std::string> && !std::same_as<T, const std::string> &&
!StdMapsConcept<T> && !BimapConcept<T>;

} // namespace PB
18 changes: 18 additions & 0 deletions PB/src/Serializer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <pb/components/Serializer.h>

#include <boost/uuid/uuid_io.hpp>

namespace PB {
template <>
std::variant<Json, PBDev::Error> flatSimple(int depth, boost::uuids::uuid uuid)
{
Json json;
json = boost::uuids::to_string(uuid);
#ifndef _CLANG_UML_
spdlog::info("{}(string, uuid) {}\n", std::string(depth * 2, ' '),
json.dump());
#endif
return json;
}

} // namespace PB
11 changes: 0 additions & 11 deletions PB/src/TextImage.cpp

This file was deleted.

Loading

0 comments on commit c01630e

Please sign in to comment.