Skip to content

Commit

Permalink
Make convert more generic
Browse files Browse the repository at this point in the history
  • Loading branch information
obhi-d committed Jan 18, 2025
1 parent a992938 commit fc865ea
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 56 deletions.
16 changes: 13 additions & 3 deletions include/acl/reflection/detail/base_concepts.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "acl/reflection/detail/accessors.hpp"
#include "acl/utility/transforms.hpp"
#include "acl/utility/convert.hpp"
#include <concepts>
#include <type_traits>
#include <variant>
Expand All @@ -17,6 +17,10 @@ template <template <typename...> class T, typename... Us>
struct is_specialization_of<T, T<Us...>> : std::true_type
{};

template <typename T>
concept ConvertibleNativeType =
std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>;

template <typename Class, typename Serializer>
concept InputSerializableClass = requires(Class& o, Serializer s) { s >> o; };

Expand Down Expand Up @@ -79,10 +83,16 @@ concept BoolLike = std::is_same_v<std::decay_t<T>, bool>;
template <typename T>
concept ContainerIsStringLike = NativeStringLike<T>;

template <typename T>
using convertible_to_type = std::decay_t<decltype(acl::convert<T>::to_type(std::declval<T>()))>;

template <typename T, typename S>
concept ConvertibleFrom = requires(T t) { acl::convert<T>::from_type(t, std::declval<S>()); };

template <typename T>
concept Convertible = requires(T t) {
acl::convert<T>::to_string(t);
acl::convert<T>::from_string(t, std::string_view());
{ acl::convert<T>::to_type(t) };
acl::convert<T>::from_type(t, std::declval<convertible_to_type<T> const&>());
};

// Array
Expand Down
59 changes: 39 additions & 20 deletions include/acl/reflection/detail/visitor_helpers.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

#pragma once

#include "field_helpers.hpp"
#include "acl/reflection/detail/aggregate.hpp"
#include "acl/reflection/detail/base_concepts.hpp"
#include "acl/reflection/detail/container_utils.hpp"
#include "acl/reflection/visitor.hpp"
#include "acl/utility/config.hpp"
#include "acl/utility/transforms.hpp"
#include "acl/utility/convert.hpp"
#include "field_helpers.hpp"
#include <concepts>
#include <cstddef>
#include <cstdint>
Expand Down Expand Up @@ -79,34 +79,53 @@ void visit_explicitly_reflected(Class& obj, Visitor& visitor)
}

template <typename Class, typename Visitor>
requires(is_reader<Visitor>)
void visit_convertible(Class& obj, Visitor& visitor)
{
using class_type = std::decay_t<Class>;
if constexpr (is_reader<Visitor>)
if constexpr (Visitor::mutate_enums && std::is_enum_v<class_type> &&
acl::detail::ConvertibleFrom<class_type, std::string_view>)
{
visitor.visit(
[&](std::string_view str) -> void
{
if constexpr (Visitor::mutate_enums && std::is_enum_v<class_type>)
{
acl::convert<class_type>::from_string(obj, Visitor::transform_type::transform(str));
}
else
{
acl::convert<class_type>::from_string(obj, str);
}
acl::convert<class_type>::from_type(obj, Visitor::transform_type::transform(str));
});
}
else if constexpr (is_writer<Visitor>)
else if constexpr (acl::detail::ConvertibleFrom<class_type, std::string_view>)
{
if constexpr (Visitor::mutate_enums && std::is_enum_v<class_type>)
{
visitor.visit(Visitor::transform_type::transform(acl::convert<class_type>::to_string(obj)));
}
else
{
visitor.visit(acl::convert<class_type>::to_string(obj));
}
visitor.visit(
[&](std::string_view str) -> void
{
acl::convert<class_type>::from_type(obj, str);
});
}
else
{
acl::detail::convertible_to_type<class_type> value;
visit(value, visitor);
acl::convert<class_type>::from_type(obj, value);
}
}

template <typename Class, typename Visitor>
requires(is_writer<Visitor>)
void visit_convertible(Class const& obj, Visitor& visitor)
{
using class_type = std::decay_t<Class>;
if constexpr (Visitor::mutate_enums && std::is_enum_v<class_type> &&
acl::detail::ConvertibleFrom<class_type, std::string_view>)
{
visitor.visit(Visitor::transform_type::transform(acl::convert<class_type>::to_type(obj)));
}
else if constexpr (acl::detail::ConvertibleFrom<class_type, std::string_view>)
{
visitor.visit(acl::convert<class_type>::to_type(obj));
}
else
{
auto value = acl::convert<class_type>::to_type(obj);
visit(value, visitor);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "acl/serializers/byteswap.hpp"
#include "acl/serializers/config.hpp"
#include "acl/utility/config.hpp"
#include "acl/utility/transforms.hpp"
#include "acl/utility/convert.hpp"
#include "acl/utility/type_traits.hpp"
#include <cassert>
#include <string_view>
Expand Down
14 changes: 11 additions & 3 deletions include/acl/serializers/detail/lite_yml_parser_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "acl/reflection/visitor.hpp"
#include "acl/serializers/config.hpp"
#include "acl/utility/detail/concepts.hpp"
#include <charconv>
#include <cstddef>
#include <string>
#include <type_traits>
Expand Down Expand Up @@ -237,13 +238,20 @@ class in_context_impl : public in_context_base
using tclass_type = std::decay_t<TClassType>;
if constexpr (Convertible<tclass_type>)
{
if constexpr (requires { typename Config::mutate_enums_type; } && std::is_enum_v<tclass_type>)
if constexpr (requires { typename Config::mutate_enums_type; } && std::is_enum_v<tclass_type> &&
acl::detail::ConvertibleFrom<tclass_type, std::string_view>)
{
acl::convert<tclass_type>::from_string(obj, transform_type::transform(slice));
acl::convert<tclass_type>::from_type(obj, transform_type::transform(slice));
}
else if constexpr (acl::detail::ConvertibleFrom<class_type, std::string_view>)
{
acl::convert<tclass_type>::from_type(obj, slice);
}
else
{
acl::convert<tclass_type>::from_string(obj, slice);
acl::detail::convertible_to_type<tclass_type> value;
read_value(value, parser, slice);
acl::convert<tclass_type>::from_type(obj, value);
}
}
else if constexpr (PointerLike<tclass_type>)
Expand Down
2 changes: 1 addition & 1 deletion include/acl/serializers/lite_yml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "acl/serializers/detail/lite_yml_parser_context.hpp"
#include "acl/serializers/detail/lite_yml_writer_context.hpp"
#include "acl/serializers/serializers.hpp"
#include "acl/utility/transforms.hpp"
#include "acl/utility/convert.hpp"

namespace acl::yml
{
Expand Down
2 changes: 1 addition & 1 deletion include/acl/serializers/serializers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "acl/serializers/detail/binary_output_serializer.hpp"
#include "acl/serializers/detail/structured_input_serializer.hpp"
#include "acl/serializers/detail/structured_output_serializer.hpp"
#include "acl/utility/transforms.hpp"
#include "acl/utility/convert.hpp"

namespace acl
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ template <typename T>
})
struct convert<T>
{
static auto to_string(T const& ref) -> std::string_view
static auto to_type(T const& ref) -> std::string_view
{
return (std::string_view)ref;
}

static auto from_string(T& ref, std::string_view v) -> void
static auto from_type(T& ref, std::string_view v) -> void
{
ref = T(v);
}
Expand All @@ -59,12 +59,12 @@ template <typename T>
})
struct convert<T>
{
static auto to_string(T const& ref) -> std::string
static auto to_type(T const& ref) -> std::string
{
return (std::string)ref;
}

static auto from_string(T& ref, std::string_view v) -> void
static auto from_type(T& ref, std::string_view v) -> void
{
ref = T(v);
}
Expand All @@ -73,17 +73,17 @@ struct convert<T>
template <>
struct convert<std::string>
{
static auto to_string(std::string const& ref) -> std::string_view
static auto to_type(std::string const& ref) -> std::string_view
{
return ref;
}

static auto from_string(std::string& ref, std::string_view v) -> void
static auto from_type(std::string& ref, std::string_view v) -> void
{
ref = std::string(v);
}

static auto from_string(std::string& ref, std::string&& v) -> void
static auto from_type(std::string& ref, std::string&& v) -> void
{
ref = std::move(v);
}
Expand All @@ -92,12 +92,12 @@ struct convert<std::string>
template <>
struct convert<std::unique_ptr<char[]>>
{
static auto to_string(std::unique_ptr<char[]> const& ref) -> std::string_view
static auto to_type(std::unique_ptr<char[]> const& ref) -> std::string_view
{
return {ref.get()};
}

static auto from_string(std::unique_ptr<char[]>& ref, std::string_view v) -> void
static auto from_type(std::unique_ptr<char[]>& ref, std::string_view v) -> void
{
ref = std::make_unique<char[]>(v.size());
std::ranges::copy(v, ref.get());
Expand All @@ -107,12 +107,12 @@ struct convert<std::unique_ptr<char[]>>
template <>
struct convert<std::string_view>
{
static auto to_string(std::string_view const& ref) -> std::string_view
static auto to_type(std::string_view const& ref) -> std::string_view
{
return ref;
}

static auto from_string(std::string_view& ref, std::string_view v) -> void
static auto from_type(std::string_view& ref, std::string_view v) -> void
{
ref = v;
}
Expand Down
2 changes: 1 addition & 1 deletion include/acl/utility/detail/concepts.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "acl/utility/config.hpp"
#include "acl/utility/transforms.hpp"
#include "acl/utility/convert.hpp"
#include "acl/utility/type_traits.hpp"
#include <concepts>
#include <cstdint>
Expand Down
Loading

0 comments on commit fc865ea

Please sign in to comment.