feat(reflect-cpp): Switched from glaze -> reflect cpp
A bug was discovered in glaze which prevented valid toml output. We have switched to toml++ and reflect-cpp. The interface has remained the same so this should not break any code
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_ISSCHEMAFULREADER_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_ISSCHEMAFULREADER_HPP_
|
||||
|
||||
#include <concepts>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "../../Result.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
using MockVariantType = std::variant<std::string, int>;
|
||||
|
||||
template <class R>
|
||||
struct MockMapReader {
|
||||
void read(const std::string_view&, typename R::InputVarType&) const {}
|
||||
};
|
||||
|
||||
template <class R>
|
||||
struct MockObjectReader {
|
||||
void read(const int, typename R::InputVarType&) const {}
|
||||
};
|
||||
|
||||
template <class R>
|
||||
struct MockUnionReader {
|
||||
static rfl::Result<MockVariantType> read(const R&, const size_t,
|
||||
typename R::InputVarType&) {
|
||||
return error("This is a mock type.");
|
||||
}
|
||||
};
|
||||
|
||||
template <class R>
|
||||
concept IsSchemafulReader =
|
||||
requires(R r, typename R::InputVarType var, typename R::InputObjectType obj,
|
||||
typename R::InputMapType m, typename R::InputUnionType u,
|
||||
MockMapReader<R> map_reader, MockObjectReader<R> object_reader) {
|
||||
/// A schemaful reader needs to differentiate between objects, for which
|
||||
/// the field names are known at compile time and maps, for which the
|
||||
/// field names are not known at compile time.
|
||||
{ r.read_map(map_reader, m) } -> std::same_as<std::optional<Error>>;
|
||||
|
||||
/// A schemaful reader can read fields by order and does not have to
|
||||
/// compare strings - the correct order of the fields is guaranteed by the
|
||||
/// schema.
|
||||
{
|
||||
r.read_object(object_reader, obj)
|
||||
} -> std::same_as<std::optional<Error>>;
|
||||
|
||||
/// A schemaful reader needs an explicit union type.
|
||||
{
|
||||
r.template read_union<MockVariantType, MockUnionReader<R>>(u)
|
||||
} -> std::same_as<rfl::Result<MockVariantType>>;
|
||||
|
||||
/// It needs to be possible to transform variables to maps.
|
||||
{ r.to_map(var) } -> std::same_as<rfl::Result<typename R::InputMapType>>;
|
||||
|
||||
/// It needs to be possible to transform variables to unions.
|
||||
{
|
||||
r.to_union(var)
|
||||
} -> std::same_as<rfl::Result<typename R::InputUnionType>>;
|
||||
};
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_ISSCHEMAFULWRITER_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_ISSCHEMAFULWRITER_HPP_
|
||||
|
||||
#include <concepts>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
template <class W>
|
||||
concept IsSchemafulWriter = requires(
|
||||
W w, typename W::OutputVarType var, typename W::OutputArrayType arr,
|
||||
typename W::OutputMapType m, typename W::OutputObjectType obj,
|
||||
typename W::OutputUnionType u, size_t index, size_t size,
|
||||
std::string_view name, std::string val) {
|
||||
/// A schemaful writer needs to know two additional types:
|
||||
/// 1) Maps - unlike objects, their field names are not known at compile time.
|
||||
/// 2) Unions - schemaful formats need explicit union types.
|
||||
|
||||
/// Sets an empty map as the root element of the document.
|
||||
/// Some serialization formats require you to pass the expected size in
|
||||
/// advance. If you are not working with such a format, you can ignore the
|
||||
/// parameter `size`. Returns the new array for further modification.
|
||||
{ w.map_as_root(size) } -> std::same_as<typename W::OutputMapType>;
|
||||
|
||||
/// Sets an empty union as the root element of the document.
|
||||
{ w.union_as_root() } -> std::same_as<typename W::OutputUnionType>;
|
||||
|
||||
/// Adds an empty array to an existing map. Returns the new
|
||||
/// array for further modification.
|
||||
{
|
||||
w.add_array_to_map(name, size, &m)
|
||||
} -> std::same_as<typename W::OutputArrayType>;
|
||||
|
||||
/// Adds an empty array to an existing union.
|
||||
/// The index refers to the index of the element in the union.
|
||||
/// Returns the new array for further modification.
|
||||
{
|
||||
w.add_array_to_union(index, size, &u)
|
||||
} -> std::same_as<typename W::OutputArrayType>;
|
||||
|
||||
/// Adds an empty map to an existing array. Returns the new
|
||||
/// map for further modification.
|
||||
{ w.add_map_to_array(size, &arr) } -> std::same_as<typename W::OutputMapType>;
|
||||
|
||||
/// Adds an empty map to an existing map. The key or name of the field
|
||||
/// is signified by `name`. Returns the new map for further modification.
|
||||
{
|
||||
w.add_map_to_map(name, size, &m)
|
||||
} -> std::same_as<typename W::OutputMapType>;
|
||||
|
||||
/// Adds an empty map to an existing object. The key or name of the field
|
||||
/// is signified by `name`. Returns the new map for further modification.
|
||||
{
|
||||
w.add_map_to_object(name, size, &obj)
|
||||
} -> std::same_as<typename W::OutputMapType>;
|
||||
|
||||
/// Adds an empty map to an existing union.
|
||||
/// The index refers to the index of the element in the union.
|
||||
/// Returns the new map for further modification.
|
||||
{
|
||||
w.add_map_to_union(index, size, &u)
|
||||
} -> std::same_as<typename W::OutputMapType>;
|
||||
|
||||
/// Adds an empty object to an existing map. The key or name of the field
|
||||
/// is signified by `name`. Returns the new object for further modification.
|
||||
{
|
||||
w.add_object_to_map(name, size, &m)
|
||||
} -> std::same_as<typename W::OutputObjectType>;
|
||||
|
||||
/// Adds an empty object to an existing union.
|
||||
/// The index refers to the index of the element in the union.
|
||||
/// Returns the new object for further modification.
|
||||
{
|
||||
w.add_object_to_union(index, size, &u)
|
||||
} -> std::same_as<typename W::OutputObjectType>;
|
||||
|
||||
/// Adds an empty union to an existing array. Returns the new
|
||||
/// union for further modification.
|
||||
{ w.add_union_to_array(&arr) } -> std::same_as<typename W::OutputUnionType>;
|
||||
|
||||
/// Adds an empty union to an existing map. The key or name of the field
|
||||
/// is signified by `name`. Returns the new union for further modification.
|
||||
{ w.add_union_to_map(name, &m) } -> std::same_as<typename W::OutputUnionType>;
|
||||
|
||||
/// Adds an empty union to an existing object. The key or name of the field
|
||||
/// is signified by `name`. Returns the new union for further modification.
|
||||
{
|
||||
w.add_union_to_object(name, &obj)
|
||||
} -> std::same_as<typename W::OutputUnionType>;
|
||||
|
||||
/// Adds an empty union to an existing union.
|
||||
/// The index refers to the index of the element in the union.
|
||||
/// Returns the new union for further modification.
|
||||
{
|
||||
w.add_union_to_union(index, &u)
|
||||
} -> std::same_as<typename W::OutputUnionType>;
|
||||
|
||||
/// Adds a null value to a map. Returns an
|
||||
/// OutputVarType containing the null value.
|
||||
{ w.add_null_to_map(name, &m) } -> std::same_as<typename W::OutputVarType>;
|
||||
|
||||
/// Adds a basic value (bool, numeric, string) to an existing map. The key
|
||||
/// or name of the field is signified by `name`. Returns an
|
||||
/// OutputVarType containing the new value.
|
||||
{
|
||||
w.add_value_to_map(name, val, &m)
|
||||
} -> std::same_as<typename W::OutputVarType>;
|
||||
|
||||
/// Adds a null value to a union. Returns an
|
||||
/// OutputVarType containing the null value.
|
||||
{ w.add_null_to_union(index, &u) } -> std::same_as<typename W::OutputVarType>;
|
||||
|
||||
/// Adds a basic value (bool, numeric, string) to an existing union. The key
|
||||
/// or name of the field is signified by `name`. Returns an
|
||||
/// OutputVarType containing the new value.
|
||||
{
|
||||
w.add_value_to_union(index, val, &u)
|
||||
} -> std::same_as<typename W::OutputVarType>;
|
||||
|
||||
/// Signifies to the writer that we do not want to add any further elements to
|
||||
/// this map. Some serialization formats require this. If you are working
|
||||
/// with a serialization format that doesn't, just leave the function empty.
|
||||
{ w.end_map(&m) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_OPTIONALREADER_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_OPTIONALREADER_HPP_
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../../Result.hpp"
|
||||
#include "../Parser_base.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
template <class R, class W, class T, class ProcessorsType>
|
||||
struct OptionalReader {
|
||||
static Result<std::optional<T>> read(
|
||||
const R& _r, const size_t _index,
|
||||
const typename R::InputVarType& _var) noexcept {
|
||||
if (_index == 1) {
|
||||
return std::optional<T>();
|
||||
}
|
||||
return Parser<R, W, std::remove_cvref_t<T>, ProcessorsType>::read(_r, _var);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_SHAREDPTRREADER_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_SHAREDPTRREADER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../../Result.hpp"
|
||||
#include "../Parser_base.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
template <class R, class W, class T, class ProcessorsType>
|
||||
struct SharedPtrReader {
|
||||
static Result<std::shared_ptr<T>> read(
|
||||
const R& _r, const size_t _index,
|
||||
const typename R::InputVarType& _var) noexcept {
|
||||
if (_index == 1) {
|
||||
return std::shared_ptr<T>();
|
||||
}
|
||||
return Parser<R, W, std::remove_cvref_t<T>, ProcessorsType>::read(_r, _var)
|
||||
.transform([](T&& _t) { return std::make_shared<T>(std::move(_t)); });
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_UNIQUEPTRREADER_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_UNIQUEPTRREADER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../../Result.hpp"
|
||||
#include "../Parser_base.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
template <class R, class W, class T, class ProcessorsType>
|
||||
struct UniquePtrReader {
|
||||
static Result<std::unique_ptr<T>> read(
|
||||
const R& _r, const size_t _index,
|
||||
const typename R::InputVarType& _var) noexcept {
|
||||
if (_index == 1) {
|
||||
return std::unique_ptr<T>();
|
||||
}
|
||||
return Parser<R, W, std::remove_cvref_t<T>, ProcessorsType>::read(_r, _var)
|
||||
.transform([](T&& _t) { return std::make_unique<T>(std::move(_t)); });
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_VARIANTREADER_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_VARIANTREADER_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../../Result.hpp"
|
||||
#include "../../internal/nth_element_t.hpp"
|
||||
#include "../Parser_base.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
template <class R, class W, class VariantType, class ProcessorsType,
|
||||
class... AlternativeTypes>
|
||||
class VariantReader {
|
||||
public:
|
||||
static Result<VariantType> read(
|
||||
const R& _r, const size_t _index,
|
||||
const typename R::InputVarType& _var) noexcept {
|
||||
return [&]<size_t... _is>(std::integer_sequence<size_t, _is...>) {
|
||||
Result<VariantType> result =
|
||||
error("Could not parse union: Index out of bounds.");
|
||||
(try_one_type<_is>(_r, _index, _var, &result), ...);
|
||||
return result;
|
||||
}(std::make_integer_sequence<size_t, sizeof...(AlternativeTypes)>());
|
||||
}
|
||||
|
||||
private:
|
||||
template <size_t _i>
|
||||
static void try_one_type(const R& _r, const size_t _index,
|
||||
const typename R::InputVarType& _var,
|
||||
Result<VariantType>* _result) noexcept {
|
||||
if (_index == _i) {
|
||||
using T = internal::nth_element_t<_i, AlternativeTypes...>;
|
||||
*_result =
|
||||
Parser<R, W, std::remove_cvref_t<T>, ProcessorsType>::read(_r, _var)
|
||||
.transform(
|
||||
[](auto&& _val) -> VariantType { return std::move(_val); });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_TUPLETONAMEDTUPLE_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_TUPLETONAMEDTUPLE_HPP_
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../../Field.hpp"
|
||||
#include "../../Tuple.hpp"
|
||||
#include "../../internal/StringLiteral.hpp"
|
||||
#include "../../make_named_tuple.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
template <int _i>
|
||||
inline consteval auto to_field_name() {
|
||||
return internal::StringLiteral<5>('f',
|
||||
static_cast<char>('0' + ((_i / 100) % 10)),
|
||||
static_cast<char>('0' + ((_i / 10) % 10)),
|
||||
static_cast<char>('0' + (_i % 10)));
|
||||
}
|
||||
|
||||
template <int _i>
|
||||
inline auto to_field(const auto& _t) {
|
||||
using T = std::remove_cvref_t<decltype(_t)>;
|
||||
return rfl::Field<to_field_name<_i>(), const T*>(&_t);
|
||||
}
|
||||
|
||||
/// Schemaful formats often don't have an explicit tuple representation.
|
||||
/// This is the required workaround.
|
||||
template <class... Ts>
|
||||
auto tuple_to_named_tuple(const Tuple<Ts...>& _tup) {
|
||||
static_assert(sizeof...(Ts) <= 1000,
|
||||
"The tuple cannot contain more than 1000 elements.");
|
||||
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
|
||||
return rfl::make_named_tuple(to_field<_is>(rfl::get<_is>(_tup))...);
|
||||
}(std::make_integer_sequence<int, sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
/// Schemaful formats often don't have an explicit tuple representation.
|
||||
/// This is the required workaround.
|
||||
template <class... Ts>
|
||||
auto tuple_to_named_tuple(const std::tuple<Ts...>& _tup) {
|
||||
static_assert(sizeof...(Ts) <= 1000,
|
||||
"The tuple cannot contain more than 1000 elements.");
|
||||
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
|
||||
return rfl::make_named_tuple(to_field<_is>(std::get<_is>(_tup))...);
|
||||
}(std::make_integer_sequence<int, sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_TUPLETONAMEDTUPLE_T_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_TUPLETONAMEDTUPLE_T_HPP_
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "../../NamedTuple.hpp"
|
||||
#include "../../Tuple.hpp"
|
||||
#include "tuple_to_named_tuple.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
template <class IntegerSequence, class... Ts>
|
||||
struct ToNamedTuple;
|
||||
|
||||
template <int... _is, class... Ts>
|
||||
struct ToNamedTuple<std::integer_sequence<int, _is...>, Ts...> {
|
||||
using Type = NamedTuple<Field<to_field_name<_is>(), Ts>...>;
|
||||
};
|
||||
|
||||
template <class TupleType>
|
||||
struct TupleToNamedTuple;
|
||||
|
||||
template <class... Ts>
|
||||
struct TupleToNamedTuple<Tuple<Ts...>> {
|
||||
using Type =
|
||||
typename ToNamedTuple<std::make_integer_sequence<int, sizeof...(Ts)>,
|
||||
Ts...>::Type;
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct TupleToNamedTuple<std::tuple<Ts...>> {
|
||||
using Type =
|
||||
typename ToNamedTuple<std::make_integer_sequence<int, sizeof...(Ts)>,
|
||||
Ts...>::Type;
|
||||
};
|
||||
|
||||
/// Given
|
||||
/// std::tuple<T1, T2, T3, ...> or rfl::Tuple<T1, T2, T3, ...>
|
||||
/// return
|
||||
/// NamedTuple<Field<"f000", T1>, Field<"f001", T2>, Field<"f002", T3>, ...>
|
||||
template <class T>
|
||||
using tuple_to_named_tuple_t = typename TupleToNamedTuple<T>::Type;
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef RFL_PARSING_SCHEMAFUL_TUPLETOOBJECT_HPP_
|
||||
#define RFL_PARSING_SCHEMAFUL_TUPLETOOBJECT_HPP_
|
||||
|
||||
#include "../schema/Type.hpp"
|
||||
#include "../../common.hpp"
|
||||
|
||||
namespace rfl::parsing::schemaful {
|
||||
|
||||
/// Schemaful formats often don't have an explicit tuple representation.
|
||||
/// This is the required workaround.
|
||||
RFL_API schema::Type::Object tuple_to_object(const schema::Type::Tuple& _tup);
|
||||
|
||||
} // namespace rfl::parsing::schemaful
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user