Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 61 additions & 6 deletions include/serdepp/serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define __CPPSER_SERIALIZER_HPP__

#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <unordered_map>
Expand Down Expand Up @@ -89,7 +90,7 @@ namespace serde
constexpr serde_context(T& format) : adaptor(format) {}
T& adaptor;
size_t read_count_ = 0;
bool skip_all_ = false;
bool skip_all_ = false;
constexpr void read() { read_count_++; }
};

Expand Down Expand Up @@ -211,7 +212,7 @@ namespace serde
}

template<typename T, typename serde_ctx>
inline void into(serde_ctx& ctx, T& data, std::string_view key) const {
inline void into(serde_ctx& ctx, T& data, std::string_view key) const {
serde::serde_serializer<T, serde_ctx>::into(ctx, data, key);
}
};
Expand Down Expand Up @@ -344,7 +345,7 @@ namespace serde
}
return serde_struct<Context, T, type_tuple>(context_, value_);
}

inline constexpr serde_struct& no_remain() {
using namespace std::literals;
if(context_.skip_all_) return *this;
Expand Down Expand Up @@ -463,7 +464,8 @@ namespace serde

template<typename T, typename serde_ctx>
struct serde_serializer<T, serde_ctx, std::enable_if_t<is_mappable_v<T> &&
is_emptyable_v<T> >> {
is_emptyable_v<T> &&
is_str_v<typename T::key_type> >> {
constexpr inline static auto from(serde_ctx& ctx, T& data, std::string_view key) {
serde_adaptor<typename serde_ctx::Adaptor, T, type::map_t>::from(ctx.adaptor, key, data);
ctx.read();
Expand All @@ -474,6 +476,59 @@ namespace serde
}
};

template<typename T>
constexpr inline std::string serialize(const T& data) {
if constexpr(std::is_arithmetic_v<T>) {
return std::to_string(data);
} else {
std::ostringstream oss;
oss << data;
return oss.str();
}
}

template <typename T>
constexpr inline T deserialize( const std::string & data ) {
if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
return static_cast<T>(std::stoll(data));
} else if constexpr (std::is_same_v<T, bool>) {
if (data == "true" || data == "1") return true;
if (data == "false" || data == "0") return false;
} else {
throw serde::unimplemented_error("unsupported type!!!");
}
}

template<typename T, typename serde_ctx>
struct serde_serializer<T, serde_ctx, std::enable_if_t<is_mappable_v<T> &&
is_emptyable_v<T> &&
!is_str_v<typename T::key_type> >> {
constexpr inline static auto from(serde_ctx& ctx, T& data, std::string_view key) {
using key_type = typename T::key_type;
using new_T = std::unordered_map<std::string, typename T::mapped_type>;
new_T map_data;
serde_adaptor<typename serde_ctx::Adaptor, new_T, type::map_t>::from(ctx.adaptor, key, map_data);
std::transform(map_data.begin(), map_data.end(), std::inserter(data, data.begin()),
[](const auto& pair) {
return std::make_pair(deserialize<key_type>(pair.first), pair.second);
});
ctx.read();
}
constexpr inline static auto into(serde_ctx& ctx, const T& data, std::string_view key) {

using value_type = typename T::mapped_type;
using new_T = std::unordered_map<std::string, value_type>;
new_T map_data;
std::transform(data.begin(), data.end(), std::inserter(map_data, map_data.begin()),
[](const auto& pair) {
return std::make_pair(serialize(pair.first), pair.second);
});
serde_adaptor<typename serde_ctx::Adaptor, new_T, type::map_t>::into(ctx.adaptor, key, map_data);
Comment on lines +506 to +526
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that we may need to revisit the current approach for implementing T <-> string conversions in the serde core.

There appears to be a small issue with the direction I suggested previously. After giving it some more thought, I think the approach where each adapter is responsible for its own implementation—similar to the adapter you implemented in the previous PR—might be a better and cleaner solution overall.

With the current approach, I see a couple of concerns:

  1. Implementing this would require introducing STL containers into the serdepp core.

    I do understand why using unordered_map is effectively unavoidable in this case
    (according to the C++ specification, when T = M<K, V>, we can extract K and V, but not M itself, which makes it impossible to construct something like M<string, V>).

    That said, serdepp currently tries to intentionally avoid using STL containers in the core library.
    In the C++ ecosystem, it’s fairly common to rely on spec-compatible custom implementations instead of STL containers, often due to performance considerations.

  2. This approach would make serdepp less adapter-neutral.

    Serdepp was originally designed with the goal of supporting adapters that are not necessarily JSON-compatible.
    From that perspective, implementing it this way might go slightly against that original intention.

In summary:

It might be better to delegate the responsibility for T <-> key support to the adapter itself.
Rather than adding a separate to_string specialization in the core, we could rely on the existing serde serialize and deserialize implementations that adapters already provide.

Additionally, it could be helpful to introduce shared utility functions for this behavior, so that different adapters can reuse the same logic where appropriate.

Additionally, since we’re currently using squash merges, it should be fine to make the changes in this PR.


ctx.read();
}
};

template<typename T, typename serde_ctx>
struct serde_serializer<T, serde_ctx, std::enable_if_t<is_sequenceable_v<T> &&
is_emptyable_v<T> &&
Expand Down Expand Up @@ -559,7 +614,7 @@ namespace serde
case SERDE_TYPE::MAP:
if(!serde_type_checker<Format>::is_map(format)) return true;
break;
case SERDE_TYPE::STRUCT:
case SERDE_TYPE::STRUCT:
if(!serde_type_checker<Format>::is_struct(format)) return true;
break;
case SERDE_TYPE::INTEGER:
Expand All @@ -575,7 +630,7 @@ namespace serde
if(!serde_type_checker<Format>::is_string(format)) return true;
break;
default: return true;
//case SERDE_TYPE::UNKNOWN:
//case SERDE_TYPE::UNKNOWN:
}
try {
data = deserialize<T>(format);
Expand Down
Loading