:3
This commit is contained in:
parent
a743cdabe5
commit
bd402f57f5
|
@ -2,6 +2,8 @@
|
|||
AlignConsecutiveAssignments: true
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
BasedOnStyle: Chromium
|
||||
|
|
35
flake.lock
35
flake.lock
|
@ -16,9 +16,26 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1708475490,
|
||||
"narHash": "sha256-g1v0TsWBQPX97ziznfJdWhgMyMGtoBFs102xSYO4syU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0e74ca98a74bc7270d28838369593635a5db3260",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"treefmt-nix": "treefmt-nix",
|
||||
"utils": "utils"
|
||||
}
|
||||
},
|
||||
|
@ -37,6 +54,24 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717850719,
|
||||
"narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
|
|
22
flake.nix
22
flake.nix
|
@ -3,12 +3,14 @@
|
|||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
treefmt-nix,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
|
@ -18,7 +20,7 @@
|
|||
inherit system;
|
||||
|
||||
overlays = [
|
||||
(self: super: {
|
||||
(_self: super: {
|
||||
ccacheWrapper = super.ccacheWrapper.override {
|
||||
extraConfig = ''
|
||||
export CCACHE_COMPRESS=1
|
||||
|
@ -54,9 +56,8 @@
|
|||
deps = with (
|
||||
if !stdenv.isDarwin
|
||||
then pkgs.pkgsStatic
|
||||
else pkgs
|
||||
); # TODO: Remove when fixed on darwin
|
||||
|
||||
else pkgs # TODO: Remove when fixed on darwin
|
||||
);
|
||||
[
|
||||
curl
|
||||
fmt
|
||||
|
@ -110,7 +111,18 @@
|
|||
default = draconisplusplus;
|
||||
};
|
||||
|
||||
formatter = alejandra;
|
||||
formatter = treefmt-nix.lib.mkWrapper pkgs {
|
||||
projectRootFile = "flake.nix";
|
||||
programs = {
|
||||
alejandra.enable = true;
|
||||
deadnix.enable = true;
|
||||
|
||||
clang-format = {
|
||||
enable = true;
|
||||
package = pkgs.clang-tools_18;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
devShell = mkShell.override {inherit stdenv;} {
|
||||
packages =
|
||||
|
|
8529
include/ctre.hpp
8529
include/ctre.hpp
File diff suppressed because it is too large
Load diff
|
@ -21,7 +21,8 @@ struct AddStructName {
|
|||
internal::remove_namespaces<internal::get_type_name<StructType>()>()>;
|
||||
using FieldType = Field<field_name_, LiteralType>;
|
||||
const auto add_new_field = [](auto&&... _fields) {
|
||||
return make_named_tuple(FieldType(LiteralType()), std::move(_fields)...);
|
||||
return make_named_tuple(FieldType(LiteralType()),
|
||||
std::move(_fields)...);
|
||||
};
|
||||
return std::apply(add_new_field, std::move(_view.fields()));
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ struct AnyOf {
|
|||
private:
|
||||
static Error make_error_message(const std::vector<Error>& _errors) {
|
||||
std::string msg =
|
||||
"Expected at least one of the following validations to pass, but none "
|
||||
"Expected at least one of the following validations to pass, but "
|
||||
"none "
|
||||
"of them did:";
|
||||
for (size_t i = 0; i < _errors.size(); ++i) {
|
||||
msg += "\n" + std::to_string(i + 1) + ") " + _errors.at(i).what();
|
||||
|
|
|
@ -33,15 +33,18 @@ struct Attribute {
|
|||
template <class U>
|
||||
Attribute(Attribute<U>&& _attr) : value_(_attr.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Attribute(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Attribute(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Attribute(const Attribute<U>& _attr) : value_(_attr.value()) {}
|
||||
|
||||
|
@ -75,7 +78,8 @@ struct Attribute {
|
|||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
namespace rfl {
|
||||
|
||||
/// The Box class behaves very similarly to the unique_ptr, but unlike the
|
||||
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user
|
||||
/// tries to access it after calling std::move does something else that is
|
||||
/// clearly bad practice).
|
||||
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the
|
||||
/// user tries to access it after calling std::move does something else that
|
||||
/// is clearly bad practice).
|
||||
template <class T>
|
||||
class Box {
|
||||
public:
|
||||
|
@ -25,9 +25,7 @@ class Box {
|
|||
/// You can generate them from unique_ptrs as well, in which case it will
|
||||
/// return an Error, if the unique_ptr is not set.
|
||||
static Result<Box<T>> make(std::unique_ptr<T>&& _ptr) {
|
||||
if (!_ptr) {
|
||||
return Error("std::unique_ptr was a nullptr.");
|
||||
}
|
||||
if (!_ptr) { return Error("std::unique_ptr was a nullptr."); }
|
||||
return Box<T>(std::move(_ptr));
|
||||
}
|
||||
|
||||
|
@ -99,7 +97,8 @@ inline auto operator<=>(const Box<T1>& _b1, const Box<T2>& _b2) {
|
|||
|
||||
template <class CharT, class Traits, class T>
|
||||
inline std::basic_ostream<CharT, Traits>& operator<<(
|
||||
std::basic_ostream<CharT, Traits>& _os, const Box<T>& _b) {
|
||||
std::basic_ostream<CharT, Traits>& _os,
|
||||
const Box<T>& _b) {
|
||||
_os << _b.get();
|
||||
return _os;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to add a description to the field - this is only relevant for the JSON
|
||||
/// schema and will be ignored by the normal serialization routines.
|
||||
/// Used to add a description to the field - this is only relevant for the
|
||||
/// JSON schema and will be ignored by the normal serialization routines.
|
||||
template <internal::StringLiteral _description, class T>
|
||||
struct Description {
|
||||
/// The underlying type.
|
||||
|
@ -42,15 +42,18 @@ struct Description {
|
|||
template <class U>
|
||||
Description(Description<_description, U>&& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Description(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Description(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Description(const Description<_description, U>& _field)
|
||||
: value_(_field.value()) {}
|
||||
|
@ -88,7 +91,8 @@ struct Description {
|
|||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
|
|
|
@ -39,15 +39,18 @@ struct Field {
|
|||
template <class U>
|
||||
Field(Field<_name, U>&& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Field(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Field(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Field(const Field<_name, U>& _field) : value_(_field.value()) {}
|
||||
|
||||
|
@ -87,7 +90,8 @@ struct Field {
|
|||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
|
|
|
@ -29,11 +29,13 @@ struct Flatten {
|
|||
template <class U>
|
||||
Flatten(Flatten<U>&& _f) : value_(_f.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Flatten(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Flatten(U&& _value) : value_(_value) {}
|
||||
|
||||
|
@ -64,7 +66,8 @@ struct Flatten {
|
|||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Flatten<T>& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
|
|
|
@ -28,7 +28,8 @@ class Literal {
|
|||
using ValueType =
|
||||
std::conditional_t<sizeof...(fields_) <=
|
||||
std::numeric_limits<std::uint8_t>::max(),
|
||||
std::uint8_t, std::uint16_t>;
|
||||
std::uint8_t,
|
||||
std::uint16_t>;
|
||||
|
||||
/// The number of different fields or different options that the literal
|
||||
/// can assume.
|
||||
|
@ -58,7 +59,8 @@ class Literal {
|
|||
return Literal(Literal<fields_...>::template value_of<_name>());
|
||||
}
|
||||
|
||||
/// Constructs a new Literal, equivalent to make, for reasons of consistency.
|
||||
/// Constructs a new Literal, equivalent to make, for reasons of
|
||||
/// consistency.
|
||||
template <internal::StringLiteral _name>
|
||||
static Literal<fields_...> from_name() {
|
||||
return Literal<fields_...>::template make<_name>();
|
||||
|
@ -138,7 +140,8 @@ class Literal {
|
|||
/// The name defined by the Literal.
|
||||
std::string name() const { return find_name(); }
|
||||
|
||||
/// Returns all possible values of the literal as a std::vector<std::string>.
|
||||
/// Returns all possible values of the literal as a
|
||||
/// std::vector<std::string>.
|
||||
static std::vector<std::string> names() { return allowed_strings_vec(); }
|
||||
|
||||
/// Helper function to retrieve a name at compile time.
|
||||
|
@ -292,13 +295,11 @@ class Literal {
|
|||
template <int _i = 0>
|
||||
static Result<int> find_value(const std::string& _str) {
|
||||
using FieldType = typename std::tuple_element<_i, FieldsType>::type;
|
||||
if (FieldType::field_.str() == _str) {
|
||||
return _i;
|
||||
}
|
||||
if (FieldType::field_.str() == _str) { return _i; }
|
||||
if constexpr (_i + 1 == num_fields_) {
|
||||
return Error(
|
||||
"Literal does not support string '" + _str +
|
||||
"'. The following strings are supported: " + allowed_strings() + ".");
|
||||
return Error("Literal does not support string '" + _str +
|
||||
"'. The following strings are supported: " +
|
||||
allowed_strings() + ".");
|
||||
} else {
|
||||
return find_value<_i + 1>(_str);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ class NamedTuple {
|
|||
public:
|
||||
using Fields = std::tuple<std::remove_cvref_t<FieldTypes>...>;
|
||||
using Names = Literal<std::remove_cvref_t<FieldTypes>::name_...>;
|
||||
using Values = std::tuple<typename std::remove_cvref_t<FieldTypes>::Type...>;
|
||||
using Values =
|
||||
std::tuple<typename std::remove_cvref_t<FieldTypes>::Type...>;
|
||||
|
||||
public:
|
||||
/// Construct from the values.
|
||||
|
@ -166,7 +167,8 @@ class NamedTuple {
|
|||
/// Template specialization for NamedTuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(NamedTuple<TupContent...> _named_tuple, const Tail&... _tail) const {
|
||||
auto add(NamedTuple<TupContent...> _named_tuple,
|
||||
const Tail&... _tail) const {
|
||||
return add(_named_tuple.fields(), _tail...);
|
||||
}
|
||||
|
||||
|
@ -177,7 +179,8 @@ class NamedTuple {
|
|||
const auto transform_field = [&_f](auto... _fields) {
|
||||
return std::tuple_cat(_f(std::move(_fields)).fields()...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
const auto to_nt =
|
||||
[]<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = std::apply(transform_field, std::move(fields()));
|
||||
|
@ -191,7 +194,8 @@ class NamedTuple {
|
|||
const auto transform_field = [&_f](auto... _fields) {
|
||||
return std::tuple_cat(_f(std::move(_fields)).fields()...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
const auto to_nt =
|
||||
[]<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = std::apply(transform_field, std::move(fields()));
|
||||
|
@ -285,7 +289,8 @@ class NamedTuple {
|
|||
/// Replaces one or several fields, returning a new version
|
||||
/// with the non-replaced fields left unchanged.
|
||||
template <internal::StringLiteral _name, class FType, class... OtherRFields>
|
||||
auto replace(Field<_name, FType>&& _field, OtherRFields&&... _other_fields) {
|
||||
auto replace(Field<_name, FType>&& _field,
|
||||
OtherRFields&&... _other_fields) {
|
||||
using RField = Field<_name, FType>;
|
||||
constexpr auto num_other_fields = sizeof...(OtherRFields);
|
||||
if constexpr (num_other_fields == 0) {
|
||||
|
@ -361,7 +366,8 @@ class NamedTuple {
|
|||
const auto transform_field = [&_f](auto... fields) {
|
||||
return std::make_tuple(_f(std::move(fields))...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
const auto to_nt =
|
||||
[]<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = std::apply(transform_field, std::move(fields()));
|
||||
|
@ -375,7 +381,8 @@ class NamedTuple {
|
|||
const auto transform_field = [&_f](auto... fields) {
|
||||
return std::make_tuple(_f(std::move(fields))...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
const auto to_nt =
|
||||
[]<class... NewFields>(std::tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = std::apply(transform_field, std::move(fields()));
|
||||
|
@ -446,8 +453,8 @@ class NamedTuple {
|
|||
// When we add additional fields, it is more intuitive to add
|
||||
// them to the end, that is why we do it like this.
|
||||
using FieldType = typename std::tuple_element<i, Fields>::type;
|
||||
return make_fields<num_additional_fields>(FieldType(std::get<i>(values_)),
|
||||
std::move(_args)...);
|
||||
return make_fields<num_additional_fields>(
|
||||
FieldType(std::get<i>(values_)), std::move(_args)...);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,7 +531,8 @@ class NamedTuple {
|
|||
/// Retrieves the fields from another tuple.
|
||||
template <class... OtherFieldTypes, class... Args>
|
||||
constexpr static Fields retrieve_fields(
|
||||
std::tuple<OtherFieldTypes...>&& _other_fields, Args&&... _args) {
|
||||
std::tuple<OtherFieldTypes...>&& _other_fields,
|
||||
Args&&... _args) {
|
||||
constexpr auto size = sizeof...(Args);
|
||||
|
||||
constexpr bool retrieved_all_fields = size == std::tuple_size_v<Fields>;
|
||||
|
@ -532,7 +540,8 @@ class NamedTuple {
|
|||
if constexpr (retrieved_all_fields) {
|
||||
return std::make_tuple(std::forward<Args>(_args)...);
|
||||
} else {
|
||||
constexpr auto field_name = std::tuple_element<size, Fields>::type::name_;
|
||||
constexpr auto field_name =
|
||||
std::tuple_element<size, Fields>::type::name_;
|
||||
|
||||
constexpr auto index =
|
||||
internal::find_index<field_name, std::tuple<OtherFieldTypes...>>();
|
||||
|
@ -594,7 +603,8 @@ class NamedTuple<> {
|
|||
/// Template specialization for NamedTuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(NamedTuple<TupContent...> _named_tuple, const Tail&... _tail) const {
|
||||
auto add(NamedTuple<TupContent...> _named_tuple,
|
||||
const Tail&... _tail) const {
|
||||
return add(_named_tuple.fields(), _tail...);
|
||||
}
|
||||
|
||||
|
@ -626,8 +636,10 @@ class NamedTuple<> {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <internal::StringLiteral _name1, class Type1,
|
||||
internal::StringLiteral _name2, class Type2>
|
||||
template <internal::StringLiteral _name1,
|
||||
class Type1,
|
||||
internal::StringLiteral _name2,
|
||||
class Type2>
|
||||
inline auto operator*(const rfl::Field<_name1, Type1>& _f1,
|
||||
const rfl::Field<_name2, Type2>& _f2) {
|
||||
return NamedTuple(_f1, _f2);
|
||||
|
@ -651,8 +663,10 @@ inline auto operator*(const NamedTuple<FieldTypes1...>& _tup1,
|
|||
return _tup1.add(_tup2);
|
||||
}
|
||||
|
||||
template <internal::StringLiteral _name1, class Type1,
|
||||
internal::StringLiteral _name2, class Type2>
|
||||
template <internal::StringLiteral _name1,
|
||||
class Type1,
|
||||
internal::StringLiteral _name2,
|
||||
class Type2>
|
||||
inline auto operator*(rfl::Field<_name1, Type1>&& _f1,
|
||||
rfl::Field<_name2, Type2>&& _f2) {
|
||||
return NamedTuple(std::forward<Field<_name1, Type1>>(_f1),
|
||||
|
|
|
@ -51,9 +51,7 @@ struct OneOf {
|
|||
_r.or_else(push_back);
|
||||
|
||||
if constexpr (sizeof...(Tail) == 0) {
|
||||
if (_errors.size() == sizeof...(Cs)) {
|
||||
return _value;
|
||||
}
|
||||
if (_errors.size() == sizeof...(Cs)) { return _value; }
|
||||
return make_error_message(_errors);
|
||||
} else {
|
||||
return validate_impl<T, Tail...>(
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
namespace rfl {
|
||||
|
||||
/// The Ref class behaves very similarly to the shared_ptr, but unlike the
|
||||
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user
|
||||
/// tries to access it after calling std::move does something else that is
|
||||
/// clearly bad practice).
|
||||
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the
|
||||
/// user tries to access it after calling std::move does something else that
|
||||
/// is clearly bad practice).
|
||||
template <class T>
|
||||
class Ref {
|
||||
public:
|
||||
|
@ -25,18 +25,14 @@ class Ref {
|
|||
/// You can generate them from shared_ptrs as well, in which case it will
|
||||
/// return an Error, if the shared_ptr is not set.
|
||||
static Result<Ref<T>> make(std::shared_ptr<T>&& _ptr) {
|
||||
if (!_ptr) {
|
||||
return Error("std::shared_ptr was a nullptr.");
|
||||
}
|
||||
if (!_ptr) { return Error("std::shared_ptr was a nullptr."); }
|
||||
return Ref<T>(std::move(_ptr));
|
||||
}
|
||||
|
||||
/// You can generate them from shared_ptrs as well, in which case it will
|
||||
/// return an Error, if the shared_ptr is not set.
|
||||
static Result<Ref<T>> make(const std::shared_ptr<T>& _ptr) {
|
||||
if (!_ptr) {
|
||||
return Error("std::shared_ptr was a nullptr.");
|
||||
}
|
||||
if (!_ptr) { return Error("std::shared_ptr was a nullptr."); }
|
||||
return Ref<T>(_ptr);
|
||||
}
|
||||
|
||||
|
@ -121,7 +117,8 @@ inline auto operator<=>(const Ref<T1>& _t1, const Ref<T2>& _t2) {
|
|||
|
||||
template <class CharT, class Traits, class T>
|
||||
inline std::basic_ostream<CharT, Traits>& operator<<(
|
||||
std::basic_ostream<CharT, Traits>& _os, const Ref<T>& _b) {
|
||||
std::basic_ostream<CharT, Traits>& _os,
|
||||
const Ref<T>& _b) {
|
||||
_os << _b.get();
|
||||
return _os;
|
||||
}
|
||||
|
@ -145,4 +142,3 @@ inline void swap(rfl::Ref<T>& _r1, rfl::Ref<T>& _r2) {
|
|||
} // namespace std
|
||||
|
||||
#endif // RFL_REF_HPP_
|
||||
|
||||
|
|
|
@ -39,15 +39,18 @@ struct Rename {
|
|||
template <class U>
|
||||
Rename(Rename<_name, U>&& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Rename(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Rename(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Rename(const Rename<_name, U>& _field) : value_(_field.value()) {}
|
||||
|
||||
|
@ -84,7 +87,8 @@ struct Rename {
|
|||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
|
|
|
@ -40,9 +40,11 @@ struct Nothing {};
|
|||
/// The Result class is used for monadic error handling.
|
||||
template <class T>
|
||||
class Result {
|
||||
static_assert(!std::is_same<T, Error>(), "The result type cannot be Error.");
|
||||
static_assert(!std::is_same<T, Error>(),
|
||||
"The result type cannot be Error.");
|
||||
|
||||
using TOrErr = std::array<unsigned char, std::max(sizeof(T), sizeof(Error))>;
|
||||
using TOrErr =
|
||||
std::array<unsigned char, std::max(sizeof(T), sizeof(Error))>;
|
||||
|
||||
public:
|
||||
using Type = T;
|
||||
|
@ -53,7 +55,9 @@ class Result {
|
|||
new (&get_t()) T(std::move(_val));
|
||||
}
|
||||
|
||||
Result(const Error& _err) : success_(false) { new (&get_err()) Error(_err); }
|
||||
Result(const Error& _err) : success_(false) {
|
||||
new (&get_err()) Error(_err);
|
||||
}
|
||||
|
||||
Result(Error&& _err) noexcept : success_(false) {
|
||||
new (&get_err()) Error(std::move(_err));
|
||||
|
@ -67,16 +71,18 @@ class Result {
|
|||
copy_from_other(_other);
|
||||
}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
template <
|
||||
class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
||||
Result(Result<U>&& _other) : success_(_other && true) {
|
||||
auto temp = std::forward<Result<U>>(_other).transform(
|
||||
[](U&& _u) { return T(std::forward<U>(_u)); });
|
||||
move_from_other(temp);
|
||||
}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
template <
|
||||
class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
||||
Result(const Result<U>& _other) : success_(_other && true) {
|
||||
auto temp = _other.transform([](const U& _u) { return T(_u); });
|
||||
move_from_other(temp);
|
||||
|
@ -179,9 +185,7 @@ class Result {
|
|||
|
||||
/// Assigns the underlying object.
|
||||
Result<T>& operator=(const Result<T>& _other) {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
if (this == &_other) { return *this; }
|
||||
destroy();
|
||||
success_ = _other.success_;
|
||||
copy_from_other(_other);
|
||||
|
@ -190,9 +194,7 @@ class Result {
|
|||
|
||||
/// Assigns the underlying object.
|
||||
Result<T>& operator=(Result<T>&& _other) noexcept {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
if (this == &_other) { return *this; }
|
||||
destroy();
|
||||
success_ = _other.success_;
|
||||
move_from_other(_other);
|
||||
|
@ -200,8 +202,9 @@ class Result {
|
|||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
template <
|
||||
class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
||||
auto& operator=(const Result<U>& _other) {
|
||||
const auto to_t = [](const U& _u) -> T { return _u; };
|
||||
t_or_err_ = _other.transform(to_t).t_or_err_;
|
||||
|
@ -310,7 +313,8 @@ class Result {
|
|||
|
||||
void destroy() {
|
||||
if (success_) {
|
||||
if constexpr (std::is_destructible_v<T> /*&& !internal::is_array_v<T>*/) {
|
||||
if constexpr (std::is_destructible_v<
|
||||
T> /*&& !internal::is_array_v<T>*/) {
|
||||
get_t().~T();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -17,4 +17,3 @@ using SkipDeserialization = internal::Skip<T, false, true>;
|
|||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ struct TaggedUnion {
|
|||
using VariantType = std::variant<Ts...>;
|
||||
|
||||
/// A literal containing all the tags that are possible
|
||||
using PossibleTags = define_literal_t<internal::tag_t<_discriminator, Ts>...>;
|
||||
using PossibleTags =
|
||||
define_literal_t<internal::tag_t<_discriminator, Ts>...>;
|
||||
|
||||
TaggedUnion(const VariantType& _variant) : variant_(_variant) {}
|
||||
|
||||
|
@ -113,8 +114,8 @@ struct Getter<TaggedUnion<_discriminator, NamedTupleTypes...>> {
|
|||
template <StringLiteral _field_name>
|
||||
static inline auto& get(
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
|
||||
return Getter<std::variant<NamedTupleTypes...>>::template get<_field_name>(
|
||||
_tu.variant_);
|
||||
return Getter<std::variant<NamedTupleTypes...>>::template get<
|
||||
_field_name>(_tu.variant_);
|
||||
}
|
||||
|
||||
/// Gets a field by the field type.
|
||||
|
@ -129,8 +130,8 @@ struct Getter<TaggedUnion<_discriminator, NamedTupleTypes...>> {
|
|||
template <int _index>
|
||||
static inline const auto& get_const(
|
||||
const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
|
||||
return Getter<std::variant<NamedTupleTypes...>>::template get_const<_index>(
|
||||
_tu.variant_);
|
||||
return Getter<std::variant<NamedTupleTypes...>>::template get_const<
|
||||
_index>(_tu.variant_);
|
||||
}
|
||||
|
||||
/// Gets a field by name.
|
||||
|
@ -145,8 +146,8 @@ struct Getter<TaggedUnion<_discriminator, NamedTupleTypes...>> {
|
|||
template <class Field>
|
||||
static inline const auto& get_const(
|
||||
const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
|
||||
return Getter<std::variant<NamedTupleTypes...>>::template get_const<Field>(
|
||||
_tu.variant_);
|
||||
return Getter<std::variant<NamedTupleTypes...>>::template get_const<
|
||||
Field>(_tu.variant_);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -45,9 +45,7 @@ class Timestamp {
|
|||
static Result<Timestamp> from_string(const char* _str) noexcept {
|
||||
try {
|
||||
return Timestamp(_str);
|
||||
} catch (std::exception& e) {
|
||||
return Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return Error(e.what()); }
|
||||
}
|
||||
|
||||
/// Returns a result containing the timestamp when successful or an Error
|
||||
|
@ -79,9 +77,7 @@ class Timestamp {
|
|||
std::istringstream input(_s);
|
||||
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
||||
input >> std::get_time(_tm, _f);
|
||||
if (input.fail()) {
|
||||
return NULL;
|
||||
}
|
||||
if (input.fail()) { return NULL; }
|
||||
return (char*)(_s + input.tellg());
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -28,9 +28,7 @@ struct Validator {
|
|||
static Result<Validator<T, V, Vs...>> from_value(const T& _value) noexcept {
|
||||
try {
|
||||
return Validator<T, V, Vs...>(_value);
|
||||
} catch (std::exception& e) {
|
||||
return Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return Error(e.what()); }
|
||||
}
|
||||
|
||||
Validator() : value_(ValidationType::validate(T()).value()) {}
|
||||
|
@ -44,13 +42,16 @@ struct Validator {
|
|||
Validator(const T& _value)
|
||||
: value_(ValidationType::validate(_value).value()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
template <
|
||||
class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
||||
Validator(U&& _value)
|
||||
: value_(ValidationType::validate(T(std::forward<U>(_value))).value()) {}
|
||||
: value_(ValidationType::validate(T(std::forward<U>(_value))).value()) {
|
||||
}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
template <
|
||||
class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
||||
Validator(const U& _value)
|
||||
: value_(ValidationType::validate(T(_value)).value()) {}
|
||||
|
||||
|
@ -73,20 +74,22 @@ struct Validator {
|
|||
default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Validator<T, V, Vs...>& operator=(Validator<T, V, Vs...>&& _other) noexcept =
|
||||
default;
|
||||
Validator<T, V, Vs...>& operator=(
|
||||
Validator<T, V, Vs...>&& _other) noexcept = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
template <
|
||||
class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
||||
auto& operator=(U&& _value) noexcept {
|
||||
value_ = ValidationType::validate(T(std::forward<U>(_value))).value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
template <
|
||||
class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = ValidationType::validate(T(_value)).value();
|
||||
return *this;
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
namespace rfl::parsing {
|
||||
|
||||
/// bson_oid_t needs to be treated as a special case, otherwise it will be read
|
||||
/// as a struct.
|
||||
/// bson_oid_t needs to be treated as a special case, otherwise it will be
|
||||
/// read as a struct.
|
||||
template <class R, class W, class ProcessorsType>
|
||||
requires AreReaderAndWriter<R, W, bson_oid_t>
|
||||
struct Parser<R, W, ProcessorsType, bson_oid_t> {
|
||||
|
@ -25,7 +25,8 @@ struct Parser<R, W, ProcessorsType, bson_oid_t> {
|
|||
}
|
||||
|
||||
template <class P>
|
||||
static void write(const W& _w, const bson_oid_t& _oid,
|
||||
static void write(const W& _w,
|
||||
const bson_oid_t& _oid,
|
||||
const P& _parent) noexcept {
|
||||
ParentType::add_value(_w, _oid, _parent);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef RFL_BSON_READER_HPP_
|
||||
#define RFL_BSON_READER_HPP_
|
||||
|
||||
#include <bson/bson.h>
|
||||
|
||||
#include <array>
|
||||
#include <bson/bson.h>
|
||||
#include <concepts>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
|
@ -47,12 +46,12 @@ struct Reader {
|
|||
using InputVarType = BSONInputVar;
|
||||
|
||||
template <class T>
|
||||
static constexpr bool has_custom_constructor = (requires(InputVarType var) {
|
||||
T::from_bson_obj(var);
|
||||
});
|
||||
static constexpr bool has_custom_constructor =
|
||||
(requires(InputVarType var) { T::from_bson_obj(var); });
|
||||
|
||||
rfl::Result<InputVarType> get_field(
|
||||
const std::string& _name, const InputObjectType& _obj) const noexcept {
|
||||
const std::string& _name,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
bson_t b;
|
||||
bson_iter_t iter;
|
||||
const auto doc = _obj.val_->val_.value.v_doc;
|
||||
|
@ -60,9 +59,7 @@ struct Reader {
|
|||
if (bson_iter_init(&iter, &b)) {
|
||||
while (bson_iter_next(&iter)) {
|
||||
auto key = std::string(bson_iter_key(&iter));
|
||||
if (key == _name) {
|
||||
return to_input_var(&iter);
|
||||
}
|
||||
if (key == _name) { return to_input_var(&iter); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +111,8 @@ struct Reader {
|
|||
"Could not cast to numeric value. The type must be double, "
|
||||
"int32, int64 or date_time.");
|
||||
}
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bson_oid_t>()) {
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>,
|
||||
bson_oid_t>()) {
|
||||
if (btype != BSON_TYPE_OID) {
|
||||
return rfl::Error("Could not cast to OID.");
|
||||
}
|
||||
|
@ -134,7 +132,8 @@ struct Reader {
|
|||
}
|
||||
|
||||
template <class ArrayReader>
|
||||
std::optional<Error> read_array(const ArrayReader& _array_reader,
|
||||
std::optional<Error> read_array(
|
||||
const ArrayReader& _array_reader,
|
||||
const InputArrayType& _arr) const noexcept {
|
||||
bson_t b;
|
||||
bson_iter_t iter;
|
||||
|
@ -143,9 +142,7 @@ struct Reader {
|
|||
if (bson_iter_init(&iter, &b)) {
|
||||
while (bson_iter_next(&iter)) {
|
||||
const auto err = _array_reader.read(to_input_var(&iter));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (err) { return err; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +150,8 @@ struct Reader {
|
|||
}
|
||||
|
||||
template <class ObjectReader>
|
||||
std::optional<Error> read_object(const ObjectReader& _object_reader,
|
||||
std::optional<Error> read_object(
|
||||
const ObjectReader& _object_reader,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
bson_t b;
|
||||
bson_iter_t iter;
|
||||
|
@ -183,18 +181,14 @@ struct Reader {
|
|||
const InputVarType& _var) const noexcept {
|
||||
try {
|
||||
return T::from_bson_obj(_var);
|
||||
} catch (std::exception& e) {
|
||||
return rfl::Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return rfl::Error(e.what()); }
|
||||
}
|
||||
|
||||
private:
|
||||
struct BSONValues {
|
||||
std::vector<rfl::Box<BSONValue>> vec_;
|
||||
~BSONValues() {
|
||||
for (auto& v : vec_) {
|
||||
bson_value_destroy(&(v->val_));
|
||||
}
|
||||
for (auto& v : vec_) { bson_value_destroy(&(v->val_)); }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define RFL_BSON_WRITER_HPP_
|
||||
|
||||
#include <bson/bson.h>
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
@ -85,7 +84,8 @@ class Writer {
|
|||
return OutputVarType {};
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_array(const size_t _size,
|
||||
OutputArrayType add_array_to_array(
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
bson_array_builder_t* val;
|
||||
bson_array_builder_append_array_builder_begin(_parent->val_, &val);
|
||||
|
@ -93,7 +93,8 @@ class Writer {
|
|||
}
|
||||
|
||||
OutputArrayType add_array_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
bson_array_builder_t* val;
|
||||
bson_append_array_builder_begin(_parent->val_, _name.data(),
|
||||
|
@ -102,26 +103,30 @@ class Writer {
|
|||
}
|
||||
|
||||
OutputObjectType add_object_to_array(
|
||||
const size_t _size, OutputArrayType* _parent) const noexcept {
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
subdocs_->emplace_back(rfl::Box<BSONType>());
|
||||
bson_array_builder_append_document_begin(_parent->val_,
|
||||
&(subdocs_->back()->val_));
|
||||
return OutputObjectType(&subdocs_->back()->val_, IsArray{_parent->val_});
|
||||
return OutputObjectType(&subdocs_->back()->val_,
|
||||
IsArray {_parent->val_});
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
subdocs_->emplace_back(rfl::Box<BSONType>());
|
||||
bson_append_document_begin(_parent->val_, _name.data(),
|
||||
static_cast<int>(_name.size()),
|
||||
&(subdocs_->back()->val_));
|
||||
return OutputObjectType(&subdocs_->back()->val_, IsObject{_parent->val_});
|
||||
return OutputObjectType(&subdocs_->back()->val_,
|
||||
IsObject {_parent->val_});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_array(const T& _var,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
OutputVarType add_value_to_array(const T& _var, OutputArrayType* _parent)
|
||||
const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
bson_array_builder_append_utf8(_parent->val_, _var.c_str(),
|
||||
static_cast<int>(_var.size()));
|
||||
|
@ -133,7 +138,8 @@ class Writer {
|
|||
} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
bson_array_builder_append_int64(_parent->val_,
|
||||
static_cast<std::int64_t>(_var));
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bson_oid_t>()) {
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>,
|
||||
bson_oid_t>()) {
|
||||
bson_array_builder_append_oid(_parent->val_, &_var);
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
|
@ -142,7 +148,8 @@ class Writer {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_object(const std::string_view& _name,
|
||||
OutputVarType add_value_to_object(
|
||||
const std::string_view& _name,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
|
@ -160,7 +167,8 @@ class Writer {
|
|||
bson_append_int64(_parent->val_, _name.data(),
|
||||
static_cast<int>(_name.size()),
|
||||
static_cast<std::int64_t>(_var));
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bson_oid_t>()) {
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>,
|
||||
bson_oid_t>()) {
|
||||
bson_append_oid(_parent->val_, _name.data(),
|
||||
static_cast<int>(_name.size()), &_var);
|
||||
} else {
|
||||
|
@ -174,7 +182,8 @@ class Writer {
|
|||
return OutputVarType {};
|
||||
}
|
||||
|
||||
OutputVarType add_null_to_object(const std::string_view& _name,
|
||||
OutputVarType add_null_to_object(
|
||||
const std::string_view& _name,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
bson_append_null(_parent->val_, _name.data(),
|
||||
static_cast<int>(_name.size()));
|
||||
|
@ -185,7 +194,8 @@ class Writer {
|
|||
const auto handle = [&](const auto _parent) {
|
||||
using Type = std::remove_cvref_t<decltype(_parent)>;
|
||||
if constexpr (std::is_same<Type, IsArray>()) {
|
||||
bson_array_builder_append_array_builder_end(_parent.ptr_, _arr->val_);
|
||||
bson_array_builder_append_array_builder_end(_parent.ptr_,
|
||||
_arr->val_);
|
||||
} else if constexpr (std::is_same<Type, IsObject>()) {
|
||||
bson_append_array_builder_end(_parent.ptr_, _arr->val_);
|
||||
} else if constexpr (std::is_same<Type, IsRoot>()) {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define RFL_BSON_READ_HPP_
|
||||
|
||||
#include <bson/bson.h>
|
||||
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define RFL_BSON_WRITE_HPP_
|
||||
|
||||
#include <bson/bson.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -15,8 +14,8 @@
|
|||
namespace rfl {
|
||||
namespace bson {
|
||||
|
||||
/// Returns BSON bytes. Careful: It is the responsibility of the caller to call
|
||||
/// bson_free on the returned pointer.
|
||||
/// Returns BSON bytes. Careful: It is the responsibility of the caller to
|
||||
/// call bson_free on the returned pointer.
|
||||
template <class... Ps>
|
||||
std::pair<uint8_t*, size_t> to_buffer(const auto& _obj) noexcept {
|
||||
using T = std::remove_cvref_t<decltype(_obj)>;
|
||||
|
|
|
@ -8,27 +8,33 @@
|
|||
namespace rfl {
|
||||
namespace parsing {
|
||||
|
||||
/// CBOR requires us to explicitly set the number of fields in advance. Because
|
||||
/// of that, we require all of the fields and then set them to nullptr, if
|
||||
/// necessary.
|
||||
/// CBOR requires us to explicitly set the number of fields in advance.
|
||||
/// Because of that, we require all of the fields and then set them to
|
||||
/// nullptr, if necessary.
|
||||
template <class ProcessorsType, class... FieldTypes>
|
||||
requires AreReaderAndWriter<cbor::Reader, cbor::Writer,
|
||||
requires AreReaderAndWriter<cbor::Reader,
|
||||
cbor::Writer,
|
||||
NamedTuple<FieldTypes...>>
|
||||
struct Parser<cbor::Reader, cbor::Writer, NamedTuple<FieldTypes...>,
|
||||
struct Parser<cbor::Reader,
|
||||
cbor::Writer,
|
||||
NamedTuple<FieldTypes...>,
|
||||
ProcessorsType>
|
||||
: public NamedTupleParser<cbor::Reader, cbor::Writer,
|
||||
: public NamedTupleParser<cbor::Reader,
|
||||
cbor::Writer,
|
||||
/*_ignore_empty_containers=*/false,
|
||||
/*_all_required=*/true, ProcessorsType,
|
||||
FieldTypes...> {
|
||||
};
|
||||
/*_all_required=*/true,
|
||||
ProcessorsType,
|
||||
FieldTypes...> {};
|
||||
|
||||
template <class ProcessorsType, class... Ts>
|
||||
requires AreReaderAndWriter<cbor::Reader, cbor::Writer, std::tuple<Ts...>>
|
||||
struct Parser<cbor::Reader, cbor::Writer, std::tuple<Ts...>, ProcessorsType>
|
||||
: public TupleParser<cbor::Reader, cbor::Writer,
|
||||
: public TupleParser<cbor::Reader,
|
||||
cbor::Writer,
|
||||
/*_ignore_empty_containers=*/false,
|
||||
/*_all_required=*/true, ProcessorsType, Ts...> {
|
||||
};
|
||||
/*_all_required=*/true,
|
||||
ProcessorsType,
|
||||
Ts...> {};
|
||||
|
||||
} // namespace parsing
|
||||
} // namespace rfl
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef RFL_CBOR_READER_HPP_
|
||||
#define RFL_CBOR_READER_HPP_
|
||||
|
||||
#include <cbor.h>
|
||||
|
||||
#include <array>
|
||||
#include <cbor.h>
|
||||
#include <concepts>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
|
@ -43,42 +42,30 @@ struct Reader {
|
|||
using InputVarType = CBORInputVar;
|
||||
|
||||
template <class T>
|
||||
static constexpr bool has_custom_constructor = (requires(InputVarType var) {
|
||||
T::from_cbor_obj(var);
|
||||
});
|
||||
static constexpr bool has_custom_constructor =
|
||||
(requires(InputVarType var) { T::from_cbor_obj(var); });
|
||||
|
||||
rfl::Result<InputVarType> get_field(
|
||||
const std::string& _name, const InputObjectType& _obj) const noexcept {
|
||||
const std::string& _name,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
CborValue val;
|
||||
auto buffer = std::vector<char>();
|
||||
auto err = cbor_value_enter_container(_obj.val_, &val);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
size_t length = 0;
|
||||
err = cbor_value_get_map_length(_obj.val_, &length);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (!cbor_value_is_text_string(&val)) {
|
||||
return Error("Expected the key to be a string value.");
|
||||
}
|
||||
err = get_string(&val, &buffer);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
err = cbor_value_advance(&val);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (_name == buffer.data()) {
|
||||
return to_input_var(&val);
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
if (_name == buffer.data()) { return to_input_var(&val); }
|
||||
err = cbor_value_advance(&val);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
}
|
||||
return Error("No field named '" + _name + "' was found.");
|
||||
}
|
||||
|
@ -95,9 +82,7 @@ struct Reader {
|
|||
}
|
||||
std::vector<char> buffer;
|
||||
const auto err = get_string(_var.val_, &buffer);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
return std::string(buffer.data());
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
if (!cbor_value_is_boolean(_var.val_)) {
|
||||
|
@ -105,36 +90,29 @@ struct Reader {
|
|||
}
|
||||
bool result = false;
|
||||
const auto err = cbor_value_get_boolean(_var.val_, &result);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
return result;
|
||||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>() ||
|
||||
std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
if (cbor_value_is_integer(_var.val_)) {
|
||||
std::int64_t result = 0;
|
||||
const auto err = cbor_value_get_int64(_var.val_, &result);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
return static_cast<T>(result);
|
||||
} else if (cbor_value_is_float(_var.val_)) {
|
||||
float result = 0.0;
|
||||
const auto err = cbor_value_get_float(_var.val_, &result);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
return static_cast<T>(result);
|
||||
} else if (cbor_value_is_double(_var.val_)) {
|
||||
double result = 0.0;
|
||||
const auto err = cbor_value_get_double(_var.val_, &result);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
return static_cast<T>(result);
|
||||
}
|
||||
return rfl::Error(
|
||||
"Could not cast to numeric value. The type must be integral, float "
|
||||
"Could not cast to numeric value. The type must be integral, "
|
||||
"float "
|
||||
"or double.");
|
||||
|
||||
} else {
|
||||
|
@ -159,7 +137,8 @@ struct Reader {
|
|||
}
|
||||
|
||||
template <class ArrayReader>
|
||||
std::optional<Error> read_array(const ArrayReader& _array_reader,
|
||||
std::optional<Error> read_array(
|
||||
const ArrayReader& _array_reader,
|
||||
const InputArrayType& _arr) const noexcept {
|
||||
CborValue val;
|
||||
auto buffer = std::vector<char>();
|
||||
|
@ -174,9 +153,7 @@ struct Reader {
|
|||
}
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
const auto err2 = _array_reader.read(to_input_var(&val));
|
||||
if (err2) {
|
||||
return err2;
|
||||
}
|
||||
if (err2) { return err2; }
|
||||
err = cbor_value_advance(&val);
|
||||
if (err != CborNoError && err != CborErrorOutOfMemory) {
|
||||
return Error(cbor_error_string(err));
|
||||
|
@ -186,31 +163,24 @@ struct Reader {
|
|||
}
|
||||
|
||||
template <class ObjectReader>
|
||||
std::optional<Error> read_object(const ObjectReader& _object_reader,
|
||||
std::optional<Error> read_object(
|
||||
const ObjectReader& _object_reader,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
size_t length = 0;
|
||||
auto err = cbor_value_get_map_length(_obj.val_, &length);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
|
||||
CborValue val;
|
||||
err = cbor_value_enter_container(_obj.val_, &val);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
|
||||
auto buffer = std::vector<char>();
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
err = get_string(&val, &buffer);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
err = cbor_value_advance(&val);
|
||||
if (err != CborNoError) {
|
||||
return Error(cbor_error_string(err));
|
||||
}
|
||||
if (err != CborNoError) { return Error(cbor_error_string(err)); }
|
||||
const auto name = std::string_view(buffer.data(), buffer.size() - 1);
|
||||
_object_reader.read(name, InputVarType {&val});
|
||||
cbor_value_advance(&val);
|
||||
|
@ -224,9 +194,7 @@ struct Reader {
|
|||
const InputVarType& _var) const noexcept {
|
||||
try {
|
||||
return T::from_cbor_obj(_var);
|
||||
} catch (std::exception& e) {
|
||||
return rfl::Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return rfl::Error(e.what()); }
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -234,12 +202,11 @@ struct Reader {
|
|||
std::vector<char>* _buffer) const noexcept {
|
||||
size_t length = 0;
|
||||
auto err = cbor_value_get_string_length(_ptr, &length);
|
||||
if (err != CborNoError && err != CborErrorOutOfMemory) {
|
||||
return err;
|
||||
}
|
||||
if (err != CborNoError && err != CborErrorOutOfMemory) { return err; }
|
||||
_buffer->resize(length + 1);
|
||||
(*_buffer)[length] = '\0';
|
||||
return cbor_value_copy_text_string(_ptr, _buffer->data(), &length, NULL);
|
||||
return cbor_value_copy_text_string(_ptr, _buffer->data(), &length,
|
||||
NULL);
|
||||
}
|
||||
|
||||
InputVarType to_input_var(CborValue* _ptr) const noexcept {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define RFL_CBOR_WRITER_HPP_
|
||||
|
||||
#include <cbor.h>
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
@ -61,38 +60,43 @@ class Writer {
|
|||
return new_value(_var, encoder_);
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_array(const size_t _size,
|
||||
OutputArrayType add_array_to_array(
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
return new_array(_size, _parent->encoder_);
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size());
|
||||
return new_array(_size, _parent->encoder_);
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_array(
|
||||
const size_t _size, OutputArrayType* _parent) const noexcept {
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
return new_object(_size, _parent->encoder_);
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size());
|
||||
return new_object(_size, _parent->encoder_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_array(const T& _var,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
OutputVarType add_value_to_array(const T& _var, OutputArrayType* _parent)
|
||||
const noexcept {
|
||||
return new_value(_var, _parent->encoder_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_object(const std::string_view& _name,
|
||||
OutputVarType add_value_to_object(
|
||||
const std::string_view& _name,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size());
|
||||
|
@ -104,7 +108,8 @@ class Writer {
|
|||
return OutputVarType {};
|
||||
}
|
||||
|
||||
OutputVarType add_null_to_object(const std::string_view& _name,
|
||||
OutputVarType add_null_to_object(
|
||||
const std::string_view& _name,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size());
|
||||
cbor_encode_null(_parent->encoder_);
|
||||
|
@ -135,7 +140,8 @@ class Writer {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType new_value(const T& _var, CborEncoder* _parent) const noexcept {
|
||||
OutputVarType new_value(const T& _var,
|
||||
CborEncoder* _parent) const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
cbor_encode_text_string(_parent, _var.c_str(), _var.size());
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define RFL_CBOR_READ_HPP_
|
||||
|
||||
#include <cbor.h>
|
||||
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
|
@ -30,8 +29,8 @@ Result<internal::wrap_in_rfl_array_t<T>> read(const char* _bytes,
|
|||
const size_t _size) {
|
||||
CborParser parser;
|
||||
CborValue value;
|
||||
cbor_parser_init(reinterpret_cast<const uint8_t*>(_bytes), _size, 0, &parser,
|
||||
&value);
|
||||
cbor_parser_init(reinterpret_cast<const uint8_t*>(_bytes), _size, 0,
|
||||
&parser, &value);
|
||||
auto doc = InputVarType {&value};
|
||||
auto result = read<T, Ps...>(doc);
|
||||
return result;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define RFL_CBOR_WRITE_HPP_
|
||||
|
||||
#include <cbor.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
@ -16,7 +15,8 @@ namespace rfl {
|
|||
namespace cbor {
|
||||
|
||||
template <class... Ps>
|
||||
void write_into_buffer(const auto& _obj, CborEncoder* _encoder,
|
||||
void write_into_buffer(const auto& _obj,
|
||||
CborEncoder* _encoder,
|
||||
std::vector<char>* _buffer) noexcept {
|
||||
using T = std::remove_cvref_t<decltype(_obj)>;
|
||||
using ParentType = parsing::Parent<Writer>;
|
||||
|
|
|
@ -76,7 +76,8 @@ struct ExclusiveMinimum {
|
|||
std::is_floating_point_v<T>
|
||||
? std::variant<double, int>(static_cast<double>(_threshold))
|
||||
: std::variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::ExclusiveMinimum{.value_ = value}};
|
||||
return ValidationType {
|
||||
ValidationType::ExclusiveMinimum {.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -124,7 +125,8 @@ struct ExclusiveMaximum {
|
|||
std::is_floating_point_v<T>
|
||||
? std::variant<double, int>(static_cast<double>(_threshold))
|
||||
: std::variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::ExclusiveMaximum{.value_ = value}};
|
||||
return ValidationType {
|
||||
ValidationType::ExclusiveMaximum {.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,17 +14,19 @@ namespace rfl {
|
|||
// Converts an enum value to a string.
|
||||
template <internal::enums::is_scoped_enum EnumType>
|
||||
std::string enum_to_string(EnumType _enum) {
|
||||
return rfl::internal::enums::StringConverter<EnumType>::enum_to_string(_enum);
|
||||
return rfl::internal::enums::StringConverter<EnumType>::enum_to_string(
|
||||
_enum);
|
||||
}
|
||||
|
||||
// Converts a string to a value of the given enum type.
|
||||
template <internal::enums::is_scoped_enum EnumType>
|
||||
rfl::Result<EnumType> string_to_enum(const std::string& _str) {
|
||||
return rfl::internal::enums::StringConverter<EnumType>::string_to_enum(_str);
|
||||
return rfl::internal::enums::StringConverter<EnumType>::string_to_enum(
|
||||
_str);
|
||||
}
|
||||
|
||||
// Returns a named tuple mapping names of enumerators of the given enum type to
|
||||
// their values.
|
||||
// Returns a named tuple mapping names of enumerators of the given enum type
|
||||
// to their values.
|
||||
template <internal::enums::is_scoped_enum EnumType>
|
||||
auto get_enumerators() {
|
||||
constexpr auto names = internal::enums::get_enum_names<
|
||||
|
@ -32,8 +34,8 @@ auto get_enumerators() {
|
|||
return internal::enums::names_to_enumerator_named_tuple(names);
|
||||
}
|
||||
|
||||
// Returns a named tuple mapping names of enumerators of the given enum type to
|
||||
// their underlying values.
|
||||
// Returns a named tuple mapping names of enumerators of the given enum type
|
||||
// to their underlying values.
|
||||
template <internal::enums::is_scoped_enum EnumType>
|
||||
auto get_underlying_enumerators() {
|
||||
constexpr auto names = internal::enums::get_enum_names<
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
namespace rfl {
|
||||
|
||||
/// Extracts a Literal containing all of the discriminators from a TaggedUnion.
|
||||
/// Extracts a Literal containing all of the discriminators from a
|
||||
/// TaggedUnion.
|
||||
template <class TaggedUnionType>
|
||||
using extract_discriminators_t =
|
||||
typename internal::extract_discriminators<TaggedUnionType>::type;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef FLEXBUF_READER_HPP_
|
||||
#define FLEXBUF_READER_HPP_
|
||||
|
||||
#include <flatbuffers/flexbuffers.h>
|
||||
|
||||
#include <exception>
|
||||
#include <flatbuffers/flexbuffers.h>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
@ -28,26 +27,29 @@ struct Reader {
|
|||
|
||||
template <class T>
|
||||
struct has_from_flexbuf<
|
||||
T, std::enable_if_t<std::is_invocable_r<T, decltype(T::from_flexbuf),
|
||||
T,
|
||||
std::enable_if_t<std::is_invocable_r<T,
|
||||
decltype(T::from_flexbuf),
|
||||
InputVarType>::value>>
|
||||
: std::true_type {};
|
||||
|
||||
template <class T>
|
||||
struct has_from_flexbuf<
|
||||
T, std::enable_if_t<std::is_invocable_r<
|
||||
rfl::Result<T>, decltype(T::from_flexbuf), InputVarType>::value>>
|
||||
T,
|
||||
std::enable_if_t<std::is_invocable_r<rfl::Result<T>,
|
||||
decltype(T::from_flexbuf),
|
||||
InputVarType>::value>>
|
||||
: std::true_type {};
|
||||
|
||||
template <class T>
|
||||
static constexpr bool has_custom_constructor = has_from_flexbuf<T>::value;
|
||||
|
||||
rfl::Result<InputVarType> get_field(
|
||||
const std::string& _name, const InputObjectType& _obj) const noexcept {
|
||||
const std::string& _name,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
const auto keys = _obj.Keys();
|
||||
for (size_t i = 0; i < keys.size(); ++i) {
|
||||
if (_name == keys[i].AsString().c_str()) {
|
||||
return _obj.Values()[i];
|
||||
}
|
||||
if (_name == keys[i].AsString().c_str()) { return _obj.Values()[i]; }
|
||||
}
|
||||
return rfl::Error("Map does not contain any element called '" + _name +
|
||||
"'.");
|
||||
|
@ -85,20 +87,20 @@ struct Reader {
|
|||
}
|
||||
|
||||
template <class ArrayReader>
|
||||
std::optional<Error> read_array(const ArrayReader& _array_reader,
|
||||
std::optional<Error> read_array(
|
||||
const ArrayReader& _array_reader,
|
||||
const InputArrayType& _arr) const noexcept {
|
||||
const auto size = _arr.size();
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
const auto err = _array_reader.read(InputVarType(_arr[i]));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (err) { return err; }
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <class ObjectReader>
|
||||
std::optional<Error> read_object(const ObjectReader& _object_reader,
|
||||
std::optional<Error> read_object(
|
||||
const ObjectReader& _object_reader,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
const auto keys = _obj.Keys();
|
||||
const auto values = _obj.Values();
|
||||
|
@ -122,9 +124,7 @@ struct Reader {
|
|||
|
||||
rfl::Result<InputObjectType> to_object(
|
||||
const InputVarType& _var) const noexcept {
|
||||
if (!_var.IsMap()) {
|
||||
return rfl::Error("Could not cast to Map!");
|
||||
}
|
||||
if (!_var.IsMap()) { return rfl::Error("Could not cast to Map!"); }
|
||||
return _var.AsMap();
|
||||
}
|
||||
|
||||
|
@ -133,9 +133,7 @@ struct Reader {
|
|||
const InputVarType& _var) const noexcept {
|
||||
try {
|
||||
return T::from_flexbuf(_var);
|
||||
} catch (std::exception& e) {
|
||||
return rfl::Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return rfl::Error(e.what()); }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef FLEXBUF_WRITER_HPP_
|
||||
#define FLEXBUF_WRITER_HPP_
|
||||
|
||||
#include <flatbuffers/flexbuffers.h>
|
||||
|
||||
#include <exception>
|
||||
#include <flatbuffers/flexbuffers.h>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
@ -58,36 +57,41 @@ struct Writer {
|
|||
return insert_value(_var);
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_array(const size_t _size,
|
||||
OutputArrayType add_array_to_array(
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
return new_array();
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
return new_array(_name);
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_array(
|
||||
const size_t _size, OutputArrayType* _parent) const noexcept {
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
return new_object();
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
return new_object(_name);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_array(const T& _var,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
OutputVarType add_value_to_array(const T& _var, OutputArrayType* _parent)
|
||||
const noexcept {
|
||||
return insert_value(_var);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_object(const std::string_view& _name,
|
||||
OutputVarType add_value_to_object(
|
||||
const std::string_view& _name,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
return insert_value(_name, _var);
|
||||
|
@ -98,7 +102,8 @@ struct Writer {
|
|||
return OutputVarType {};
|
||||
}
|
||||
|
||||
OutputVarType add_null_to_object(const std::string_view& _name,
|
||||
OutputVarType add_null_to_object(
|
||||
const std::string_view& _name,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
fbb_->Null(_name.data());
|
||||
return OutputVarType {};
|
||||
|
@ -156,7 +161,8 @@ struct Writer {
|
|||
return OutputArrayType {start};
|
||||
}
|
||||
|
||||
OutputObjectType new_object(const std::string_view& _name) const noexcept {
|
||||
OutputObjectType new_object(
|
||||
const std::string_view& _name) const noexcept {
|
||||
const auto start = fbb_->StartMap(_name.data());
|
||||
return OutputObjectType {start};
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define FLEXBUF_READ_HPP_
|
||||
|
||||
#include <flatbuffers/flexbuffers.h>
|
||||
|
||||
#include <istream>
|
||||
#include <vector>
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef FLEXBUF_WRITE_HPP_
|
||||
#define FLEXBUF_WRITE_HPP_
|
||||
|
||||
#include <flatbuffers/flexbuffers.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <flatbuffers/flexbuffers.h>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
@ -22,7 +21,8 @@ std::vector<uint8_t> to_buffer(const auto& _obj) {
|
|||
using ParentType = parsing::Parent<Writer>;
|
||||
const auto fbb = Ref<flexbuffers::Builder>::make();
|
||||
auto w = Writer(fbb);
|
||||
Parser<T, Processors<Ps...>>::write(w, _obj, typename ParentType::Root{});
|
||||
Parser<T, Processors<Ps...>>::write(w, _obj,
|
||||
typename ParentType::Root {});
|
||||
fbb->Finish();
|
||||
return fbb->GetBuffer();
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ auto from_named_tuple(NamedTupleType&& _n) {
|
|||
using RequiredType = std::remove_cvref_t<rfl::named_tuple_t<T>>;
|
||||
if constexpr (!std::is_same<std::remove_cvref_t<NamedTupleType>,
|
||||
RequiredType>()) {
|
||||
return from_named_tuple<T>(RequiredType(std::forward<NamedTupleType>(_n)));
|
||||
return from_named_tuple<T>(
|
||||
RequiredType(std::forward<NamedTupleType>(_n)));
|
||||
} else if constexpr (internal::has_fields<T>()) {
|
||||
if constexpr (std::is_lvalue_reference<NamedTupleType> {}) {
|
||||
return internal::copy_from_named_tuple<T>(_n);
|
||||
|
|
|
@ -19,15 +19,11 @@ class Memoization {
|
|||
/// Returns the underlying value.
|
||||
template <class F>
|
||||
const T& value(const F& _f) {
|
||||
if (flag_.test()) {
|
||||
return value_;
|
||||
}
|
||||
if (flag_.test()) { return value_; }
|
||||
|
||||
std::lock_guard<std::mutex> guard(mtx_);
|
||||
|
||||
if (flag_.test()) {
|
||||
return value_;
|
||||
}
|
||||
if (flag_.test()) { return value_; }
|
||||
|
||||
_f(&value_);
|
||||
|
||||
|
|
|
@ -39,15 +39,19 @@ class Skip {
|
|||
template <class U, bool _skip_s, bool _skip_d>
|
||||
Skip(Skip<U, _skip_s, _skip_d>&& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Skip(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Skip(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, bool _skip_s, bool _skip_d,
|
||||
template <class U,
|
||||
bool _skip_s,
|
||||
bool _skip_d,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Skip(const Skip<U, _skip_s, _skip_d>& _skip) : value_(_skip.value()) {}
|
||||
|
@ -85,7 +89,8 @@ class Skip {
|
|||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
|
|
|
@ -36,9 +36,7 @@ struct StringLiteral {
|
|||
template <size_t N1, size_t N2>
|
||||
constexpr inline bool operator==(const StringLiteral<N1>& _first,
|
||||
const StringLiteral<N2>& _second) {
|
||||
if constexpr (N1 != N2) {
|
||||
return false;
|
||||
}
|
||||
if constexpr (N1 != N2) { return false; }
|
||||
return _first.string_view() == _second.string_view();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ namespace internal {
|
|||
struct VisitTree {
|
||||
/// Evaluates a visitor pattern using a tree-like structure.
|
||||
template <int _begin, int _end, class Visitor, class... Args>
|
||||
static inline auto visit(const auto& _v, const int _i,
|
||||
static inline auto visit(const auto& _v,
|
||||
const int _i,
|
||||
const Args&... _args) {
|
||||
static_assert(_end > _begin, "_end needs to be greater than _begin.");
|
||||
if constexpr (_end - _begin == 1) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -6,8 +6,8 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "../Field.hpp"
|
||||
#include "lit_name.hpp"
|
||||
#include "../make_named_tuple.hpp"
|
||||
#include "lit_name.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
|
|
@ -11,8 +11,12 @@ template <class... LiteralTypes>
|
|||
struct define_literal;
|
||||
|
||||
/// General case
|
||||
template <StringLiteral... _content1, StringLiteral... _content2, class... Tail>
|
||||
struct define_literal<Literal<_content1...>, Literal<_content2...>, Tail...> {
|
||||
template <StringLiteral... _content1,
|
||||
StringLiteral... _content2,
|
||||
class... Tail>
|
||||
struct define_literal<Literal<_content1...>,
|
||||
Literal<_content2...>,
|
||||
Tail...> {
|
||||
using type = typename define_literal<Literal<_content1..., _content2...>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
|
|
@ -25,9 +25,11 @@ struct define_named_tuple<NamedTuple<TupContent...>, Head, Tail...> {
|
|||
};
|
||||
|
||||
/// Allows you to combine several named tuples and/or additional fields.
|
||||
/// Recursive case - first type is NamedTuple, second type is also NamedTuple.
|
||||
/// Recursive case - first type is NamedTuple, second type is also
|
||||
/// NamedTuple.
|
||||
template <class... TupContent, class... TupContent2, class... Tail>
|
||||
struct define_named_tuple<NamedTuple<TupContent...>, NamedTuple<TupContent2...>,
|
||||
struct define_named_tuple<NamedTuple<TupContent...>,
|
||||
NamedTuple<TupContent2...>,
|
||||
Tail...> {
|
||||
using type =
|
||||
typename define_named_tuple<NamedTuple<TupContent..., TupContent2...>,
|
||||
|
|
|
@ -12,11 +12,14 @@ template <StringLiteral _discriminator, class... TaggedUnionTypes>
|
|||
struct define_tagged_union;
|
||||
|
||||
/// Recursive case - both tagged union.
|
||||
template <StringLiteral _discriminator, class... NamedTupleTypes1,
|
||||
class... NamedTupleTypes2, class... Tail>
|
||||
struct define_tagged_union<
|
||||
_discriminator, TaggedUnion<_discriminator, NamedTupleTypes1...>,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes2...>, Tail...> {
|
||||
template <StringLiteral _discriminator,
|
||||
class... NamedTupleTypes1,
|
||||
class... NamedTupleTypes2,
|
||||
class... Tail>
|
||||
struct define_tagged_union<_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes1...>,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes2...>,
|
||||
Tail...> {
|
||||
using type = typename define_tagged_union<
|
||||
_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes1..., NamedTupleTypes2...>,
|
||||
|
@ -24,29 +27,37 @@ struct define_tagged_union<
|
|||
};
|
||||
|
||||
/// Recursive case - tagged union plus named tuple.
|
||||
template <StringLiteral _discriminator, class... NamedTupleTypes,
|
||||
class... FieldTypes, class... Tail>
|
||||
template <StringLiteral _discriminator,
|
||||
class... NamedTupleTypes,
|
||||
class... FieldTypes,
|
||||
class... Tail>
|
||||
struct define_tagged_union<_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...>,
|
||||
NamedTuple<FieldTypes...>, Tail...> {
|
||||
using type = typename define_tagged_union<
|
||||
_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...,
|
||||
NamedTuple<FieldTypes...>,
|
||||
Tail...> {
|
||||
using type =
|
||||
typename define_tagged_union<_discriminator,
|
||||
TaggedUnion<_discriminator,
|
||||
NamedTupleTypes...,
|
||||
NamedTuple<FieldTypes...>>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Recursive case - named tuple.
|
||||
template <StringLiteral _discriminator, class... FieldTypes, class... Tail>
|
||||
struct define_tagged_union<_discriminator, NamedTuple<FieldTypes...>, Tail...> {
|
||||
struct define_tagged_union<_discriminator,
|
||||
NamedTuple<FieldTypes...>,
|
||||
Tail...> {
|
||||
using type = typename define_tagged_union<
|
||||
_discriminator, TaggedUnion<_discriminator, NamedTuple<FieldTypes...>>,
|
||||
_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTuple<FieldTypes...>>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Special case - only a single TaggedUnion is left.
|
||||
template <StringLiteral _discriminator, class... NamedTupleTypes>
|
||||
struct define_tagged_union<_discriminator,
|
||||
struct define_tagged_union<
|
||||
_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...>> {
|
||||
using type = TaggedUnion<_discriminator, NamedTupleTypes...>;
|
||||
};
|
||||
|
|
|
@ -12,7 +12,9 @@ struct define_variant;
|
|||
|
||||
/// Recursive case - both variants.
|
||||
template <class... Vars1, class... Vars2, class... Tail>
|
||||
struct define_variant<std::variant<Vars1...>, std::variant<Vars2...>, Tail...> {
|
||||
struct define_variant<std::variant<Vars1...>,
|
||||
std::variant<Vars2...>,
|
||||
Tail...> {
|
||||
using type = typename define_variant<std::variant<Vars1..., Vars2...>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
|
|
@ -33,39 +33,58 @@ struct Names {
|
|||
"Size of literal and enum do not match.");
|
||||
|
||||
template <class NewLiteral, auto _new_enum>
|
||||
using AddOneType = std::conditional_t<
|
||||
N == 0, Names<EnumType, NewLiteral, 1, _new_enum>,
|
||||
Names<EnumType, define_literal_t<LiteralType, NewLiteral>, N + 1,
|
||||
_enums..., _new_enum>>;
|
||||
using AddOneType =
|
||||
std::conditional_t<N == 0,
|
||||
Names<EnumType, NewLiteral, 1, _new_enum>,
|
||||
Names<EnumType,
|
||||
define_literal_t<LiteralType, NewLiteral>,
|
||||
N + 1,
|
||||
_enums...,
|
||||
_new_enum>>;
|
||||
};
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
auto names_to_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return make_named_tuple(Field<_names, EnumType> {_enums}...);
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
auto names_to_underlying_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return make_named_tuple(Field<_names, std::underlying_type_t<EnumType>>{
|
||||
return make_named_tuple(
|
||||
Field<_names, std::underlying_type_t<EnumType>> {
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums)}...);
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
constexpr std::array<std::pair<std::string_view, EnumType>, N>
|
||||
names_to_enumerator_array(Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return {
|
||||
std::make_pair(LiteralHelper<_names>::field_.string_view(), _enums)...};
|
||||
names_to_enumerator_array(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return {std::make_pair(LiteralHelper<_names>::field_.string_view(),
|
||||
_enums)...};
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
|
||||
template <class EnumType,
|
||||
size_t N,
|
||||
StringLiteral... _names,
|
||||
auto... _enums>
|
||||
constexpr std::array<
|
||||
std::pair<std::string_view, std::underlying_type_t<EnumType>>, N>
|
||||
std::pair<std::string_view, std::underlying_type_t<EnumType>>,
|
||||
N>
|
||||
names_to_underlying_enumerator_array(
|
||||
Names<EnumType, Literal<_names...>, N, _enums...>) {
|
||||
return {
|
||||
std::make_pair(LiteralHelper<_names>::field_.string_view(),
|
||||
return {std::make_pair(
|
||||
LiteralHelper<_names>::field_.string_view(),
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums))...};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ class StringConverter {
|
|||
public:
|
||||
static constexpr bool is_flag_enum_ = is_flag_enum<EnumType>;
|
||||
|
||||
static constexpr auto names_ = get_enum_names<EnumType, is_flag_enum_>();
|
||||
static constexpr auto names_ =
|
||||
get_enum_names<EnumType, is_flag_enum_>();
|
||||
|
||||
using NamesLiteral = typename decltype(names_)::Literal;
|
||||
|
||||
|
@ -39,7 +40,8 @@ class StringConverter {
|
|||
|
||||
/// Transforms a string to the matching enum.
|
||||
static Result<EnumType> string_to_enum(const std::string& _str) {
|
||||
static_assert(names_.size != 0,
|
||||
static_assert(
|
||||
names_.size != 0,
|
||||
"No enum could be identified. Please choose enum values "
|
||||
"between 0 to 127 or for flag enums choose 1,2,4,8,16,...");
|
||||
if constexpr (is_flag_enum_) {
|
||||
|
@ -50,7 +52,8 @@ class StringConverter {
|
|||
}
|
||||
|
||||
private:
|
||||
/// Iterates through the enum bit by bit and matches it against the flags.
|
||||
/// Iterates through the enum bit by bit and matches it against the
|
||||
/// flags.
|
||||
static std::string flag_enum_to_string(const EnumType _e) {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
auto val = static_cast<T>(_e);
|
||||
|
@ -69,8 +72,8 @@ class StringConverter {
|
|||
return strings::join("|", flags);
|
||||
}
|
||||
|
||||
/// This assumes that _enum can be exactly matched to one of the names and
|
||||
/// does not have to be combined using |.
|
||||
/// This assumes that _enum can be exactly matched to one of the names
|
||||
/// and does not have to be combined using |.
|
||||
static std::string enum_to_single_string(const EnumType _enum) {
|
||||
const auto to_str = [](const auto _l) { return _l.str(); };
|
||||
|
||||
|
@ -83,7 +86,8 @@ class StringConverter {
|
|||
}
|
||||
}
|
||||
|
||||
return std::to_string(static_cast<std::underlying_type_t<EnumType>>(_enum));
|
||||
return std::to_string(
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enum));
|
||||
}
|
||||
|
||||
/// Finds the enum matching the literal.
|
||||
|
@ -91,23 +95,22 @@ class StringConverter {
|
|||
return names_.enums_[_lit.value()];
|
||||
}
|
||||
|
||||
/// This assumes that _enum can be exactly matched to one of the names and
|
||||
/// does not have to be combined using |.
|
||||
/// This assumes that _enum can be exactly matched to one of the names
|
||||
/// and does not have to be combined using |.
|
||||
static Result<EnumType> single_string_to_enum(const std::string& _str) {
|
||||
const auto r = NamesLiteral::from_string(_str).transform(literal_to_enum);
|
||||
const auto r =
|
||||
NamesLiteral::from_string(_str).transform(literal_to_enum);
|
||||
if (r) {
|
||||
return r;
|
||||
} else {
|
||||
try {
|
||||
return static_cast<EnumType>(std::stoi(_str));
|
||||
} catch (std::exception& exp) {
|
||||
return Error(exp.what());
|
||||
}
|
||||
} catch (std::exception& exp) { return Error(exp.what()); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Only relevant if this is a flag enum - combines the different matches
|
||||
/// using |.
|
||||
/// Only relevant if this is a flag enum - combines the different
|
||||
/// matches using |.
|
||||
static Result<EnumType> string_to_flag_enum(
|
||||
const std::string& _str) noexcept {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
|
|
|
@ -41,8 +41,9 @@ namespace enums {
|
|||
|
||||
template <auto e>
|
||||
consteval auto get_enum_name_str_view() {
|
||||
// Unfortunately, we cannot avoid the use of a compiler-specific macro for
|
||||
// Clang on Windows. For all other compilers, function_name works as intended.
|
||||
// Unfortunately, we cannot avoid the use of a compiler-specific macro
|
||||
// for Clang on Windows. For all other compilers, function_name works as
|
||||
// intended.
|
||||
#if defined(__clang__) && defined(_MSC_VER)
|
||||
const auto func_name = std::string_view {__PRETTY_FUNCTION__};
|
||||
#else
|
||||
|
@ -59,7 +60,8 @@ consteval auto get_enum_name_str_view() {
|
|||
const auto split = func_name.substr(0, func_name.size() - 7);
|
||||
return split.substr(split.find("get_enum_name_str_view<") + 23);
|
||||
#else
|
||||
static_assert(false,
|
||||
static_assert(
|
||||
false,
|
||||
"You are using an unsupported compiler. Please use GCC, Clang "
|
||||
"or MSVC or use rfl::Literal.");
|
||||
#endif
|
||||
|
@ -88,7 +90,8 @@ consteval T get_max() {
|
|||
if constexpr (_is_flag) {
|
||||
return calc_greatest_power_of_two<T>();
|
||||
} else {
|
||||
return std::numeric_limits<T>::max() > 127 ? static_cast<T>(127)
|
||||
return std::numeric_limits<T>::max() > 127
|
||||
? static_cast<T>(127)
|
||||
: std::numeric_limits<T>::max();
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +105,11 @@ consteval T calc_j() {
|
|||
}
|
||||
}
|
||||
|
||||
template <class EnumType, class NamesType, auto _max, bool _is_flag, int _i>
|
||||
template <class EnumType,
|
||||
class NamesType,
|
||||
auto _max,
|
||||
bool _is_flag,
|
||||
int _i>
|
||||
consteval auto get_enum_names_impl() {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
|
||||
|
@ -114,7 +121,8 @@ consteval auto get_enum_names_impl() {
|
|||
if constexpr (j == _max) {
|
||||
return NamesType {};
|
||||
} else {
|
||||
return get_enum_names_impl<EnumType, NamesType, _max, _is_flag, _i + 1>();
|
||||
return get_enum_names_impl<EnumType, NamesType, _max, _is_flag,
|
||||
_i + 1>();
|
||||
}
|
||||
} else {
|
||||
using NewNames = typename NamesType::template AddOneType<
|
||||
|
@ -123,21 +131,24 @@ consteval auto get_enum_names_impl() {
|
|||
if constexpr (j == _max) {
|
||||
return NewNames {};
|
||||
} else {
|
||||
return get_enum_names_impl<EnumType, NewNames, _max, _is_flag, _i + 1>();
|
||||
return get_enum_names_impl<EnumType, NewNames, _max, _is_flag,
|
||||
_i + 1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class EnumType, bool _is_flag>
|
||||
consteval auto get_enum_names() {
|
||||
static_assert(is_scoped_enum<EnumType>,
|
||||
static_assert(
|
||||
is_scoped_enum<EnumType>,
|
||||
"You must use scoped enums (using class or struct) for the "
|
||||
"parsing to work!");
|
||||
|
||||
static_assert(std::is_integral_v<std::underlying_type_t<EnumType>>,
|
||||
"The underlying type of any Enum must be integral!");
|
||||
|
||||
constexpr auto max = get_max<std::underlying_type_t<EnumType>, _is_flag>();
|
||||
constexpr auto max =
|
||||
get_max<std::underlying_type_t<EnumType>, _is_flag>();
|
||||
|
||||
using EmptyNames = Names<EnumType, rfl::Literal<"">, 0>;
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ namespace internal {
|
|||
namespace enums {
|
||||
|
||||
template <class EnumType>
|
||||
concept is_flag_enum = is_scoped_enum<EnumType> &&
|
||||
requires(EnumType e1, EnumType e2) {
|
||||
concept is_flag_enum =
|
||||
is_scoped_enum<EnumType> && requires(EnumType e1, EnumType e2) {
|
||||
{ e1 | e2 } -> std::same_as<EnumType>;
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ namespace internal {
|
|||
namespace enums {
|
||||
|
||||
template <class EnumType>
|
||||
concept is_scoped_enum = std::is_enum_v<EnumType> &&
|
||||
concept is_scoped_enum =
|
||||
std::is_enum_v<EnumType> &&
|
||||
!std::is_convertible_v<EnumType, std::underlying_type_t<EnumType>>;
|
||||
|
||||
} // namespace enums
|
||||
|
|
|
@ -14,7 +14,8 @@ template <class TaggedUnionType>
|
|||
struct extract_discriminators;
|
||||
|
||||
template <StringLiteral _discriminator, class... NamedTupleType>
|
||||
struct extract_discriminators<TaggedUnion<_discriminator, NamedTupleType...>> {
|
||||
struct extract_discriminators<
|
||||
TaggedUnion<_discriminator, NamedTupleType...>> {
|
||||
using type = define_literal_t<
|
||||
std::remove_cvref_t<field_type_t<_discriminator, NamedTupleType>>...>;
|
||||
};
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#include "../NamedTuple.hpp"
|
||||
#include "../TaggedUnion.hpp"
|
||||
#include "../named_tuple_t.hpp"
|
||||
#include "StringLiteral.hpp"
|
||||
#include "find_index.hpp"
|
||||
#include "../named_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
@ -29,15 +29,17 @@ struct FieldType {
|
|||
static constexpr int field_ix_ =
|
||||
internal::find_index<_field_name, typename NamedTupleType::Fields>();
|
||||
|
||||
using Type = typename std::tuple_element<
|
||||
field_ix_, typename NamedTupleType::Fields>::type::Type;
|
||||
using Type = typename std::
|
||||
tuple_element<field_ix_, typename NamedTupleType::Fields>::type::Type;
|
||||
};
|
||||
|
||||
/// For variants - in this case the FieldType returned by all options must be
|
||||
/// the same.
|
||||
template <StringLiteral _field_name, class FirstAlternativeType,
|
||||
/// For variants - in this case the FieldType returned by all options must
|
||||
/// be the same.
|
||||
template <StringLiteral _field_name,
|
||||
class FirstAlternativeType,
|
||||
class... OtherAlternativeTypes>
|
||||
struct FieldType<_field_name,
|
||||
struct FieldType<
|
||||
_field_name,
|
||||
std::variant<FirstAlternativeType, OtherAlternativeTypes...>> {
|
||||
constexpr static bool all_types_match = std::conjunction_v<std::is_same<
|
||||
typename FieldType<_field_name, FirstAlternativeType>::Type,
|
||||
|
@ -49,11 +51,14 @@ struct FieldType<_field_name,
|
|||
};
|
||||
|
||||
/// For tagged union - just defers to the variant.
|
||||
template <StringLiteral _field_name, StringLiteral _discriminator_name,
|
||||
template <StringLiteral _field_name,
|
||||
StringLiteral _discriminator_name,
|
||||
class... VarTypes>
|
||||
struct FieldType<_field_name, TaggedUnion<_discriminator_name, VarTypes...>> {
|
||||
struct FieldType<_field_name,
|
||||
TaggedUnion<_discriminator_name, VarTypes...>> {
|
||||
using Type = typename FieldType<
|
||||
_field_name, typename TaggedUnion<_discriminator_name,
|
||||
_field_name,
|
||||
typename TaggedUnion<_discriminator_name,
|
||||
VarTypes...>::VariantType>::Type;
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ namespace internal {
|
|||
|
||||
template <class T>
|
||||
using flattened_ptr_tuple_t =
|
||||
typename std::invoke_result<decltype(to_flattened_ptr_tuple<T>), T>::type;
|
||||
typename std::invoke_result<decltype(to_flattened_ptr_tuple<T>),
|
||||
T>::type;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../to_named_tuple.hpp"
|
||||
#include "flattened_ptr_tuple_t.hpp"
|
||||
#include "remove_ptrs_tup.hpp"
|
||||
#include "../to_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
|
|
@ -43,7 +43,8 @@ constexpr auto wrap(const T& arg) noexcept {
|
|||
template <class T, auto ptr>
|
||||
consteval auto get_field_name_str_view() {
|
||||
// Unfortunately, we cannot avoid the use of a compiler-specific macro for
|
||||
// Clang on Windows. For all other compilers, function_name works as intended.
|
||||
// Clang on Windows. For all other compilers, function_name works as
|
||||
// intended.
|
||||
#if defined(__clang__) && defined(_MSC_VER)
|
||||
const auto func_name = std::string_view {__PRETTY_FUNCTION__};
|
||||
#else
|
||||
|
@ -60,7 +61,8 @@ consteval auto get_field_name_str_view() {
|
|||
const auto split = func_name.substr(0, func_name.size() - 7);
|
||||
return split.substr(split.rfind("->") + 2);
|
||||
#else
|
||||
static_assert(false,
|
||||
static_assert(
|
||||
false,
|
||||
"You are using an unsupported compiler. Please use GCC, Clang "
|
||||
"or MSVC or switch to the rfl::Field-syntax.");
|
||||
#endif
|
||||
|
|
|
@ -17,7 +17,8 @@ auto get_meta_fields(AlreadyExtracted&&... _already_extracted) {
|
|||
if constexpr (NamedTupleType::size() == i) {
|
||||
return std::array<MetaField, i> {std::move(_already_extracted)...};
|
||||
} else {
|
||||
using FieldType = std::tuple_element_t<i, typename NamedTupleType::Fields>;
|
||||
using FieldType =
|
||||
std::tuple_element_t<i, typename NamedTupleType::Fields>;
|
||||
auto name = typename FieldType::Name().str();
|
||||
auto type = type_name_t<typename FieldType::Type>().str();
|
||||
return get_meta_fields<NamedTupleType>(
|
||||
|
|
|
@ -11,7 +11,8 @@ namespace internal {
|
|||
template <class T>
|
||||
consteval auto get_type_name_str_view() {
|
||||
// Unfortunately, we cannot avoid the use of a compiler-specific macro for
|
||||
// Clang on Windows. For all other compilers, function_name works as intended.
|
||||
// Clang on Windows. For all other compilers, function_name works as
|
||||
// intended.
|
||||
#if defined(__clang__) && defined(_MSC_VER)
|
||||
const auto func_name = std::string_view {__PRETTY_FUNCTION__};
|
||||
#else
|
||||
|
@ -28,9 +29,7 @@ consteval auto get_type_name_str_view() {
|
|||
auto split = func_name.substr(0, func_name.size() - 7);
|
||||
split = split.substr(split.find("get_type_name_str_view<") + 23);
|
||||
auto pos = split.find(" ");
|
||||
if (pos != std::string_view::npos) {
|
||||
return split.substr(pos + 1);
|
||||
}
|
||||
if (pos != std::string_view::npos) { return split.substr(pos + 1); }
|
||||
return split;
|
||||
#else
|
||||
static_assert(
|
||||
|
|
|
@ -7,7 +7,8 @@ namespace rfl {
|
|||
namespace internal {
|
||||
|
||||
template <typename Wrapper>
|
||||
using to_class_method_t = decltype(std::declval<const Wrapper>().to_class());
|
||||
using to_class_method_t =
|
||||
decltype(std::declval<const Wrapper>().to_class());
|
||||
|
||||
template <typename Wrapper, typename = std::void_t<>>
|
||||
struct has_to_class_m : std::false_type {};
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../named_tuple_t.hpp"
|
||||
#include "is_field.hpp"
|
||||
#include "is_named_tuple.hpp"
|
||||
#include "nt_to_ptr_named_tuple.hpp"
|
||||
#include "ptr_field_tuple_t.hpp"
|
||||
#include "../named_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
@ -25,7 +25,8 @@ auto make_ptr_fields(PtrNamedTupleType& _n, Args... _args) {
|
|||
} else {
|
||||
using Field =
|
||||
std::remove_cvref_t<std::tuple_element_t<i, PtrFieldTupleType>>;
|
||||
using T = std::remove_cvref_t<std::remove_pointer_t<typename Field::Type>>;
|
||||
using T =
|
||||
std::remove_cvref_t<std::remove_pointer_t<typename Field::Type>>;
|
||||
|
||||
if constexpr (is_named_tuple_v<T>) {
|
||||
using SubPtrNamedTupleType =
|
||||
|
@ -36,7 +37,8 @@ auto make_ptr_fields(PtrNamedTupleType& _n, Args... _args) {
|
|||
_n, _args..., SubPtrNamedTupleType(_n).fields());
|
||||
|
||||
} else if constexpr (is_flatten_field<Field>::value) {
|
||||
using SubPtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
using SubPtrFieldTupleType =
|
||||
std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
|
||||
return make_ptr_fields<PtrFieldTupleType>(
|
||||
_n, _args..., make_ptr_fields<SubPtrFieldTupleType>(_n));
|
||||
|
@ -54,7 +56,8 @@ auto move_from_ptr_fields(Pointers& _ptrs, Args&&... _args) {
|
|||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<Pointers>>) {
|
||||
return T {std::move(_args)...};
|
||||
} else {
|
||||
using FieldType = std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
using FieldType =
|
||||
std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
|
||||
if constexpr (is_field_v<FieldType>) {
|
||||
return move_from_ptr_fields<T>(
|
||||
|
@ -95,7 +98,8 @@ T move_from_named_tuple(NamedTupleType&& _n) {
|
|||
return move_from_ptr_fields<T>(pointers);
|
||||
|
||||
} else {
|
||||
return move_from_named_tuple<T, RequiredType>(RequiredType(std::move(_n)));
|
||||
return move_from_named_tuple<T, RequiredType>(
|
||||
RequiredType(std::move(_n)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,11 +29,15 @@ constexpr int calc_flattened_size() {
|
|||
}
|
||||
}
|
||||
|
||||
template <class TargetTupleType, class PtrTupleType, int _j = 0, class... Args>
|
||||
template <class TargetTupleType,
|
||||
class PtrTupleType,
|
||||
int _j = 0,
|
||||
class... Args>
|
||||
auto unflatten_ptr_tuple(PtrTupleType& _t, Args... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
|
||||
constexpr auto size = std::tuple_size_v<std::remove_cvref_t<TargetTupleType>>;
|
||||
constexpr auto size =
|
||||
std::tuple_size_v<std::remove_cvref_t<TargetTupleType>>;
|
||||
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(_args...);
|
||||
|
@ -45,7 +49,8 @@ auto unflatten_ptr_tuple(PtrTupleType& _t, Args... _args) {
|
|||
using SubTargetTupleType =
|
||||
ptr_tuple_t<std::remove_pointer_t<typename T::Type>>;
|
||||
|
||||
constexpr int flattened_size = calc_flattened_size<SubTargetTupleType>();
|
||||
constexpr int flattened_size =
|
||||
calc_flattened_size<SubTargetTupleType>();
|
||||
|
||||
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType,
|
||||
_j + flattened_size>(
|
||||
|
@ -65,7 +70,8 @@ auto move_from_pointers(Pointers& _ptrs, Args&&... _args) {
|
|||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<Pointers>>) {
|
||||
return std::remove_cvref_t<T> {std::move(_args)...};
|
||||
} else {
|
||||
using FieldType = std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
using FieldType =
|
||||
std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
|
||||
if constexpr (std::is_pointer_v<FieldType>) {
|
||||
return move_from_pointers<T>(_ptrs, std::move(_args)...,
|
||||
|
@ -77,7 +83,8 @@ auto move_from_pointers(Pointers& _ptrs, Args&&... _args) {
|
|||
using U = std::remove_cvref_t<typename std::remove_pointer_t<
|
||||
typename std::tuple_element_t<i, PtrTupleType>>::Type>;
|
||||
|
||||
return move_from_pointers<T>(_ptrs, std::move(_args)...,
|
||||
return move_from_pointers<T>(
|
||||
_ptrs, std::move(_args)...,
|
||||
move_from_pointers<U>(std::get<i>(_ptrs)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,10 @@ constexpr inline bool no_duplicate_field_names() {
|
|||
} else if constexpr (_j == -1) {
|
||||
return no_duplicate_field_names<Fields, _i + 1, _i>();
|
||||
} else {
|
||||
using FieldType1 =
|
||||
std::remove_cvref_t<typename std::tuple_element<_i, Fields>::type>;
|
||||
using FieldType2 =
|
||||
std::remove_cvref_t<typename std::tuple_element<_j, Fields>::type>;
|
||||
using FieldType1 = std::remove_cvref_t<
|
||||
typename std::tuple_element<_i, Fields>::type>;
|
||||
using FieldType2 = std::remove_cvref_t<
|
||||
typename std::tuple_element<_j, Fields>::type>;
|
||||
|
||||
constexpr auto field_name_i = FieldType1::name_;
|
||||
constexpr auto field_name_j = FieldType2::name_;
|
||||
|
|
|
@ -24,14 +24,16 @@ auto nt_to_ptr_named_tuple(NamedTupleType& _nt, AlreadyExtracted... _a) {
|
|||
using FieldType = typename std::tuple_element<i, Fields>::type;
|
||||
using T = std::remove_cvref_t<typename FieldType::Type>;
|
||||
return nt_to_ptr_named_tuple(
|
||||
_nt, _a..., Field<FieldType::name_, T*>(&std::get<i>(_nt.values())));
|
||||
_nt, _a...,
|
||||
Field<FieldType::name_, T*>(&std::get<i>(_nt.values())));
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct from a named tuple.
|
||||
template <class NamedTupleType, class... AlreadyExtracted>
|
||||
auto nt_to_ptr_named_tuple(const NamedTupleType& _nt, AlreadyExtracted... _a) {
|
||||
auto nt_to_ptr_named_tuple(const NamedTupleType& _nt,
|
||||
AlreadyExtracted... _a) {
|
||||
using Fields = typename NamedTupleType::Fields;
|
||||
|
||||
constexpr auto i = sizeof...(AlreadyExtracted);
|
||||
|
|
|
@ -53,11 +53,11 @@ template <class Derived>
|
|||
struct any_empty_base {
|
||||
any_empty_base(std::size_t);
|
||||
template <class Base>
|
||||
requires(
|
||||
std::is_empty_v<std::remove_cvref_t<Base>> &&
|
||||
requires(std::is_empty_v<std::remove_cvref_t<Base>> &&
|
||||
std::is_base_of_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>> &&
|
||||
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
|
||||
!std::is_same_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>>)
|
||||
constexpr operator Base&() const noexcept;
|
||||
};
|
||||
|
||||
|
@ -65,10 +65,10 @@ template <class Derived>
|
|||
struct any_base {
|
||||
any_base(std::size_t);
|
||||
template <class Base>
|
||||
requires(
|
||||
std::is_base_of_v<std::remove_cvref_t<Base>,
|
||||
requires(std::is_base_of_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>> &&
|
||||
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
|
||||
!std::is_same_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>>)
|
||||
constexpr operator Base&() const noexcept;
|
||||
};
|
||||
|
||||
|
@ -84,8 +84,7 @@ struct CountFieldsHelper {
|
|||
static consteval bool constructible() {
|
||||
return []<std::size_t... is>(std::index_sequence<is...>) {
|
||||
return requires { T {any(is)...}; };
|
||||
}
|
||||
(std::make_index_sequence<n>());
|
||||
}(std::make_index_sequence<n>());
|
||||
}
|
||||
|
||||
template <std::size_t l, std::size_t nested, std::size_t r>
|
||||
|
@ -94,8 +93,7 @@ struct CountFieldsHelper {
|
|||
std::index_sequence<i...>, std::index_sequence<j...>,
|
||||
std::index_sequence<k...>) {
|
||||
return requires { T {any(i)..., {any(j)...}, any(k)...}; };
|
||||
}
|
||||
(std::make_index_sequence<l>(), std::make_index_sequence<nested>(),
|
||||
}(std::make_index_sequence<l>(), std::make_index_sequence<nested>(),
|
||||
std::make_index_sequence<r>());
|
||||
}
|
||||
|
||||
|
@ -114,7 +112,8 @@ struct CountFieldsHelper {
|
|||
if constexpr (size < 1) {
|
||||
return 1;
|
||||
} else if constexpr (constructible_with_nested<index, size, rest>() &&
|
||||
!constructible_with_nested<index, size, rest + 1>()) {
|
||||
!constructible_with_nested<index, size,
|
||||
rest + 1>()) {
|
||||
return size;
|
||||
} else {
|
||||
return get_nested_array_size<index, size - 1, rest + 1>();
|
||||
|
@ -128,7 +127,8 @@ struct CountFieldsHelper {
|
|||
std::index_sequence<l...>,
|
||||
std::index_sequence<r...>) {
|
||||
return requires {
|
||||
T{any_empty_base<T>(l)..., any_base<T>(0), any_empty_base<T>(r)...};
|
||||
T {any_empty_base<T>(l)..., any_base<T>(0),
|
||||
any_empty_base<T>(r)...};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -154,8 +154,8 @@ struct CountFieldsHelper {
|
|||
template <std::size_t n, std::size_t max_arg_num>
|
||||
static consteval bool has_n_base_param() {
|
||||
constexpr auto right_len = max_arg_num >= n ? max_arg_num - n : 0;
|
||||
return []<std::size_t... l, std::size_t... r>(std::index_sequence<l...>,
|
||||
std::index_sequence<r...>) {
|
||||
return []<std::size_t... l, std::size_t... r>(
|
||||
std::index_sequence<l...>, std::index_sequence<r...>) {
|
||||
return requires { T {any_base<T>(l)..., any(r)...}; };
|
||||
}(std::make_index_sequence<n>(), std::make_index_sequence<right_len>());
|
||||
}
|
||||
|
@ -175,9 +175,9 @@ struct CountFieldsHelper {
|
|||
if constexpr (index == max) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1 +
|
||||
constructible_no_brace_elision<
|
||||
index + get_nested_array_size<index, max - index, 0>(), max>();
|
||||
return 1 + constructible_no_brace_elision<
|
||||
index + get_nested_array_size<index, max - index, 0>(),
|
||||
max>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,8 @@ struct CountFieldsHelper {
|
|||
constexpr std::size_t max_agg_args = count_max_args_in_agg_init();
|
||||
constexpr std::size_t no_brace_ellison_args =
|
||||
constructible_no_brace_elision<0, max_agg_args>();
|
||||
constexpr std::size_t base_args = base_param_num<no_brace_ellison_args>();
|
||||
constexpr std::size_t base_args =
|
||||
base_param_num<no_brace_ellison_args>();
|
||||
if constexpr (no_brace_ellison_args == 0 && base_args == 0) {
|
||||
// Empty struct
|
||||
return 0;
|
||||
|
|
|
@ -15,7 +15,8 @@ template <class StructType, class... Ps>
|
|||
struct Processed<StructType, Processors<Ps...>> {
|
||||
using NamedTupleType = named_tuple_t<StructType>;
|
||||
using type = typename std::invoke_result<
|
||||
decltype(Processors<Ps...>::template process<StructType, NamedTupleType>),
|
||||
decltype(Processors<Ps...>::template process<StructType,
|
||||
NamedTupleType>),
|
||||
NamedTupleType>::type;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,22 +12,30 @@
|
|||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Recursively builds a new NamedTuple type from the FieldTypes, leaving out
|
||||
/// the field signified by _name.
|
||||
template <class _OldNamedTupleType, StringLiteral _name,
|
||||
class _NewNamedTupleType, int _i>
|
||||
/// Recursively builds a new NamedTuple type from the FieldTypes, leaving
|
||||
/// out the field signified by _name.
|
||||
template <class _OldNamedTupleType,
|
||||
StringLiteral _name,
|
||||
class _NewNamedTupleType,
|
||||
int _i>
|
||||
struct remove_single_field;
|
||||
|
||||
/// Special case - _i == 0
|
||||
template <class _OldNamedTupleType, StringLiteral _name,
|
||||
template <class _OldNamedTupleType,
|
||||
StringLiteral _name,
|
||||
class _NewNamedTupleType>
|
||||
struct remove_single_field<_OldNamedTupleType, _name, _NewNamedTupleType, 0> {
|
||||
struct remove_single_field<_OldNamedTupleType,
|
||||
_name,
|
||||
_NewNamedTupleType,
|
||||
0> {
|
||||
using type = _NewNamedTupleType;
|
||||
};
|
||||
|
||||
/// General case.
|
||||
template <class _OldNamedTupleType, StringLiteral _name,
|
||||
class _NewNamedTupleType, int _i>
|
||||
template <class _OldNamedTupleType,
|
||||
StringLiteral _name,
|
||||
class _NewNamedTupleType,
|
||||
int _i>
|
||||
struct remove_single_field {
|
||||
using OldNamedTupleType = std::remove_cvref_t<_OldNamedTupleType>;
|
||||
|
||||
|
@ -35,19 +43,25 @@ struct remove_single_field {
|
|||
std::tuple_size_v<typename OldNamedTupleType::Fields>;
|
||||
|
||||
using FieldType = std::remove_cvref_t<typename std::tuple_element<
|
||||
num_fields - _i, typename OldNamedTupleType::Fields>::type>;
|
||||
num_fields - _i,
|
||||
typename OldNamedTupleType::Fields>::type>;
|
||||
|
||||
using NewNamedTupleType =
|
||||
std::conditional_t<_name == FieldType::name_, _NewNamedTupleType,
|
||||
using NewNamedTupleType = std::conditional_t<
|
||||
_name == FieldType::name_,
|
||||
_NewNamedTupleType,
|
||||
define_named_tuple_t<_NewNamedTupleType, FieldType>>;
|
||||
|
||||
using type = typename remove_single_field<OldNamedTupleType, _name,
|
||||
NewNamedTupleType, _i - 1>::type;
|
||||
using type = typename remove_single_field<OldNamedTupleType,
|
||||
_name,
|
||||
NewNamedTupleType,
|
||||
_i - 1>::type;
|
||||
};
|
||||
|
||||
/// Recursively removes all of the fields signified by _head and _tail from the
|
||||
/// NamedTupleType.
|
||||
template <class _NamedTupleType, StringLiteral _head, StringLiteral... _tail>
|
||||
/// Recursively removes all of the fields signified by _head and _tail from
|
||||
/// the NamedTupleType.
|
||||
template <class _NamedTupleType,
|
||||
StringLiteral _head,
|
||||
StringLiteral... _tail>
|
||||
struct remove_fields;
|
||||
|
||||
/// Special case - only head is left.
|
||||
|
@ -58,20 +72,25 @@ struct remove_fields<_NamedTupleType, _head> {
|
|||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename NamedTupleType::Fields>;
|
||||
|
||||
using type = typename remove_single_field<NamedTupleType, _head, NamedTuple<>,
|
||||
using type = typename remove_single_field<NamedTupleType,
|
||||
_head,
|
||||
NamedTuple<>,
|
||||
num_fields>::type;
|
||||
};
|
||||
|
||||
/// General case.
|
||||
template <class _NamedTupleType, StringLiteral _head, StringLiteral... _tail>
|
||||
template <class _NamedTupleType,
|
||||
StringLiteral _head,
|
||||
StringLiteral... _tail>
|
||||
struct remove_fields {
|
||||
using NamedTupleType = std::remove_cvref_t<_NamedTupleType>;
|
||||
|
||||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename NamedTupleType::Fields>;
|
||||
|
||||
using NewNamedTupleType =
|
||||
typename remove_single_field<NamedTupleType, _head, NamedTuple<>,
|
||||
using NewNamedTupleType = typename remove_single_field<NamedTupleType,
|
||||
_head,
|
||||
NamedTuple<>,
|
||||
num_fields>::type;
|
||||
|
||||
using type = typename remove_fields<NewNamedTupleType, _tail...>::type;
|
||||
|
|
|
@ -14,9 +14,7 @@ template <StringLiteral _name>
|
|||
consteval auto remove_namespaces() {
|
||||
constexpr auto name = _name.string_view();
|
||||
constexpr size_t pos = name.find_last_of(":");
|
||||
if constexpr (pos == std::string_view::npos) {
|
||||
return _name;
|
||||
}
|
||||
if constexpr (pos == std::string_view::npos) { return _name; }
|
||||
constexpr auto substr = name.substr(pos + 1);
|
||||
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
|
||||
return StringLiteral<sizeof...(Ns) + 1> {substr[Ns]...};
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "ptr_tuple_t.hpp"
|
||||
#include "../to_named_tuple.hpp"
|
||||
#include "ptr_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
|
|
@ -11,9 +11,7 @@ namespace strings {
|
|||
/// Joins a string using the delimiter
|
||||
inline std::string join(const std::string& _delimiter,
|
||||
const std::vector<std::string>& _strings) {
|
||||
if (_strings.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
if (_strings.size() == 0) { return ""; }
|
||||
auto res = _strings[0];
|
||||
for (size_t i = 1; i < _strings.size(); ++i) {
|
||||
res += _delimiter + _strings[i];
|
||||
|
|
|
@ -10,7 +10,8 @@ namespace rfl::internal {
|
|||
|
||||
template <internal::StringLiteral _discriminator, class T>
|
||||
using tag_t =
|
||||
typename std::invoke_result<decltype(make_tag<_discriminator, T>), T>::type;
|
||||
typename std::invoke_result<decltype(make_tag<_discriminator, T>),
|
||||
T>::type;
|
||||
|
||||
} // namespace rfl::internal
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ auto flatten_ptr_tuple(PtrTuple&& _t, Args... _args) {
|
|||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == 0 && !has_flatten_fields<PtrTuple>()) {
|
||||
return std::forward<PtrTuple>(_t);
|
||||
} else if constexpr (i == std::tuple_size_v<std::remove_cvref_t<PtrTuple>>) {
|
||||
} else if constexpr (i ==
|
||||
std::tuple_size_v<std::remove_cvref_t<PtrTuple>>) {
|
||||
return std::tuple_cat(std::forward<Args>(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<PtrTuple>>;
|
||||
|
|
|
@ -22,7 +22,8 @@ namespace internal {
|
|||
template <class PtrFieldTuple, class... Args>
|
||||
auto flatten_ptr_field_tuple(PtrFieldTuple& _t, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<PtrFieldTuple>>) {
|
||||
if constexpr (i ==
|
||||
std::tuple_size_v<std::remove_cvref_t<PtrFieldTuple>>) {
|
||||
return std::tuple_cat(std::forward<Args>(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<PtrFieldTuple>>;
|
||||
|
@ -69,7 +70,8 @@ auto to_ptr_named_tuple(T&& _t) {
|
|||
} else {
|
||||
using FieldNames = rfl::field_names_t<T>;
|
||||
auto flattened_ptr_tuple = to_flattened_ptr_tuple(_t);
|
||||
return copy_flattened_tuple_to_named_tuple<FieldNames>(flattened_ptr_tuple);
|
||||
return copy_flattened_tuple_to_named_tuple<FieldNames>(
|
||||
flattened_ptr_tuple);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,9 @@ consteval char to_upper() {
|
|||
}
|
||||
|
||||
/// Transforms the field name from snake case to camel case.
|
||||
template <internal::StringLiteral _name, bool _capitalize, size_t _i = 0,
|
||||
template <internal::StringLiteral _name,
|
||||
bool _capitalize,
|
||||
size_t _i = 0,
|
||||
char... chars>
|
||||
consteval auto transform_snake_case() {
|
||||
if constexpr (_i == _name.arr_.size()) {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../to_named_tuple.hpp"
|
||||
#include "ptr_tuple_t.hpp"
|
||||
#include "remove_ptrs_tup.hpp"
|
||||
#include "../to_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
|
|
@ -20,10 +20,11 @@ auto wrap_in_fields(auto&& _tuple, Fields&&... _fields) {
|
|||
return std::make_tuple(std::move(_fields)...);
|
||||
} else {
|
||||
auto value = std::move(std::get<i>(_tuple));
|
||||
using Type = std::remove_cvref_t<std::remove_pointer_t<decltype(value)>>;
|
||||
using Type =
|
||||
std::remove_cvref_t<std::remove_pointer_t<decltype(value)>>;
|
||||
if constexpr (is_flatten_field_v<Type>) {
|
||||
// The problem here is that the FieldNames are already flattened, but this
|
||||
// is not, so we need to determine how many field names to skip.
|
||||
// The problem here is that the FieldNames are already flattened, but
|
||||
// this is not, so we need to determine how many field names to skip.
|
||||
constexpr auto n_skip = std::tuple_size_v<
|
||||
std::remove_cvref_t<flattened_ptr_tuple_t<typename Type::Type>>>;
|
||||
return wrap_in_fields<FieldNames, j + n_skip>(
|
||||
|
|
|
@ -12,15 +12,14 @@ namespace rfl {
|
|||
namespace io {
|
||||
|
||||
template <class T, class WriteFunction>
|
||||
Result<Nothing> save_bytes(const std::string& _fname, const T& _obj,
|
||||
Result<Nothing> save_bytes(const std::string& _fname,
|
||||
const T& _obj,
|
||||
const WriteFunction& _write) {
|
||||
try {
|
||||
std::ofstream output(_fname, std::ios::out | std::ios::binary);
|
||||
_write(_obj, output);
|
||||
output.close();
|
||||
} catch (std::exception& e) {
|
||||
return Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return Error(e.what()); }
|
||||
return Nothing {};
|
||||
}
|
||||
|
||||
|
|
|
@ -11,16 +11,15 @@ namespace rfl {
|
|||
namespace io {
|
||||
|
||||
template <class T, class WriteFunction>
|
||||
Result<Nothing> save_string(const std::string& _fname, const T& _obj,
|
||||
Result<Nothing> save_string(const std::string& _fname,
|
||||
const T& _obj,
|
||||
const WriteFunction& _write) {
|
||||
try {
|
||||
std::ofstream outfile;
|
||||
outfile.open(_fname);
|
||||
_write(_obj, outfile);
|
||||
outfile.close();
|
||||
} catch (std::exception& e) {
|
||||
return Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return Error(e.what()); }
|
||||
return Nothing {};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef RFL_JSON_READER_HPP_
|
||||
#define RFL_JSON_READER_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <exception>
|
||||
|
@ -15,6 +13,7 @@
|
|||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Result.hpp"
|
||||
#include "../always_false.hpp"
|
||||
|
@ -44,12 +43,12 @@ struct Reader {
|
|||
using InputVarType = YYJSONInputVar;
|
||||
|
||||
template <class T>
|
||||
static constexpr bool has_custom_constructor = (requires(InputVarType var) {
|
||||
T::from_json_obj(var);
|
||||
});
|
||||
static constexpr bool has_custom_constructor =
|
||||
(requires(InputVarType var) { T::from_json_obj(var); });
|
||||
|
||||
rfl::Result<InputVarType> get_field(
|
||||
const std::string& _name, const InputObjectType _obj) const noexcept {
|
||||
const std::string& _name,
|
||||
const InputObjectType _obj) const noexcept {
|
||||
const auto var = InputVarType(yyjson_obj_get(_obj.val_, _name.c_str()));
|
||||
if (!var.val_) {
|
||||
return rfl::Error("Object contains no field named '" + _name + "'.");
|
||||
|
@ -62,22 +61,22 @@ struct Reader {
|
|||
}
|
||||
|
||||
template <class ArrayReader>
|
||||
std::optional<Error> read_array(const ArrayReader& _array_reader,
|
||||
std::optional<Error> read_array(
|
||||
const ArrayReader& _array_reader,
|
||||
const InputArrayType& _arr) const noexcept {
|
||||
yyjson_val* val;
|
||||
yyjson_arr_iter iter;
|
||||
yyjson_arr_iter_init(_arr.val_, &iter);
|
||||
while ((val = yyjson_arr_iter_next(&iter))) {
|
||||
const auto err = _array_reader.read(InputVarType(val));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (err) { return err; }
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <class ObjectReader>
|
||||
std::optional<Error> read_object(const ObjectReader& _object_reader,
|
||||
std::optional<Error> read_object(
|
||||
const ObjectReader& _object_reader,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
yyjson_obj_iter iter;
|
||||
yyjson_obj_iter_init(_obj.val_, &iter);
|
||||
|
@ -93,9 +92,7 @@ struct Reader {
|
|||
rfl::Result<T> to_basic_type(const InputVarType _var) const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
const auto r = yyjson_get_str(_var.val_);
|
||||
if (r == NULL) {
|
||||
return rfl::Error("Could not cast to string.");
|
||||
}
|
||||
if (r == NULL) { return rfl::Error("Could not cast to string."); }
|
||||
return std::string(r);
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
if (!yyjson_is_bool(_var.val_)) {
|
||||
|
@ -122,7 +119,8 @@ struct Reader {
|
|||
}
|
||||
}
|
||||
|
||||
rfl::Result<InputArrayType> to_array(const InputVarType _var) const noexcept {
|
||||
rfl::Result<InputArrayType> to_array(
|
||||
const InputVarType _var) const noexcept {
|
||||
if (!yyjson_is_arr(_var.val_)) {
|
||||
return rfl::Error("Could not cast to array!");
|
||||
}
|
||||
|
@ -142,9 +140,7 @@ struct Reader {
|
|||
const InputVarType _var) const noexcept {
|
||||
try {
|
||||
return T::from_json_obj(_var);
|
||||
} catch (std::exception& e) {
|
||||
return rfl::Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return rfl::Error(e.what()); }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef RFL_JSON_WRITER_HPP_
|
||||
#define RFL_JSON_WRITER_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
@ -11,6 +9,7 @@
|
|||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Result.hpp"
|
||||
#include "../always_false.hpp"
|
||||
|
@ -73,7 +72,8 @@ class Writer {
|
|||
return OutputVarType(val);
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_array(const size_t _size,
|
||||
OutputArrayType add_array_to_array(
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
const auto arr = yyjson_mut_arr(doc_);
|
||||
yyjson_mut_arr_add_val(_parent->val_, arr);
|
||||
|
@ -81,7 +81,8 @@ class Writer {
|
|||
}
|
||||
|
||||
OutputArrayType add_array_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto arr = yyjson_mut_arr(doc_);
|
||||
yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()),
|
||||
|
@ -90,14 +91,16 @@ class Writer {
|
|||
}
|
||||
|
||||
OutputObjectType add_object_to_array(
|
||||
const size_t _size, OutputArrayType* _parent) const noexcept {
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
const auto obj = yyjson_mut_obj(doc_);
|
||||
yyjson_mut_arr_add_val(_parent->val_, obj);
|
||||
return OutputObjectType(obj);
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto obj = yyjson_mut_obj(doc_);
|
||||
yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()),
|
||||
|
@ -106,15 +109,16 @@ class Writer {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_array(const T& _var,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
OutputVarType add_value_to_array(const T& _var, OutputArrayType* _parent)
|
||||
const noexcept {
|
||||
const auto val = from_basic_type(_var);
|
||||
yyjson_mut_arr_add_val(_parent->val_, val.val_);
|
||||
return OutputVarType(val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_object(const std::string_view& _name,
|
||||
OutputVarType add_value_to_object(
|
||||
const std::string_view& _name,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto val = from_basic_type(_var);
|
||||
|
@ -129,7 +133,8 @@ class Writer {
|
|||
return OutputVarType(null);
|
||||
}
|
||||
|
||||
OutputVarType add_null_to_object(const std::string_view& _name,
|
||||
OutputVarType add_null_to_object(
|
||||
const std::string_view& _name,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto null = yyjson_mut_null(doc_);
|
||||
yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()),
|
||||
|
@ -149,11 +154,14 @@ class Writer {
|
|||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
return OutputVarType(yyjson_mut_bool(doc_, _var));
|
||||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>()) {
|
||||
return OutputVarType(yyjson_mut_real(doc_, static_cast<double>(_var)));
|
||||
return OutputVarType(
|
||||
yyjson_mut_real(doc_, static_cast<double>(_var)));
|
||||
} else if constexpr (std::is_unsigned<std::remove_cvref_t<T>>()) {
|
||||
return OutputVarType(yyjson_mut_uint(doc_, static_cast<uint64_t>(_var)));
|
||||
return OutputVarType(
|
||||
yyjson_mut_uint(doc_, static_cast<uint64_t>(_var)));
|
||||
} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
return OutputVarType(yyjson_mut_int(doc_, static_cast<int64_t>(_var)));
|
||||
return OutputVarType(
|
||||
yyjson_mut_int(doc_, static_cast<int64_t>(_var)));
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#ifndef RFL_JSON_READ_HPP_
|
||||
#define RFL_JSON_READ_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Processors.hpp"
|
||||
#include "../internal/wrap_in_rfl_array_t.hpp"
|
||||
|
@ -26,11 +25,10 @@ auto read(const InputVarType& _obj) {
|
|||
|
||||
/// Parses an object from JSON using reflection.
|
||||
template <class T, class... Ps>
|
||||
Result<internal::wrap_in_rfl_array_t<T>> read(const std::string& _json_str) {
|
||||
Result<internal::wrap_in_rfl_array_t<T>> read(
|
||||
const std::string& _json_str) {
|
||||
yyjson_doc* doc = yyjson_read(_json_str.c_str(), _json_str.size(), 0);
|
||||
if (!doc) {
|
||||
return Error("Could not parse document");
|
||||
}
|
||||
if (!doc) { return Error("Could not parse document"); }
|
||||
yyjson_val* root = yyjson_doc_get_root(doc);
|
||||
const auto r = Reader();
|
||||
auto res = Parser<T, Processors<Ps...>>::read(r, InputVarType(root));
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#ifndef RFL_JSON_SAVE_HPP_
|
||||
#define RFL_JSON_SAVE_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Result.hpp"
|
||||
#include "../io/save_string.hpp"
|
||||
|
@ -15,9 +14,11 @@ namespace rfl {
|
|||
namespace json {
|
||||
|
||||
template <class... Ps>
|
||||
Result<Nothing> save(const std::string& _fname, const auto& _obj,
|
||||
Result<Nothing> save(const std::string& _fname,
|
||||
const auto& _obj,
|
||||
const yyjson_write_flag _flag = 0) {
|
||||
const auto write_func = [_flag](const auto& _obj, auto& _stream) -> auto& {
|
||||
const auto write_func = [_flag](const auto& _obj,
|
||||
auto& _stream) -> auto& {
|
||||
return write<Ps...>(_obj, _stream, _flag);
|
||||
};
|
||||
return rfl::io::save_string(_fname, _obj, write_func);
|
||||
|
|
|
@ -131,11 +131,26 @@ struct Type {
|
|||
rfl::Ref<Type> items;
|
||||
};
|
||||
|
||||
using ReflectionType =
|
||||
std::variant<AllOf, AnyOf, Boolean, ExclusiveMaximum, ExclusiveMinimum,
|
||||
FixedSizeTypedArray, Integer, Maximum, Minimum, Number, Null,
|
||||
Object, OneOf, Reference, Regex, String, StringEnum,
|
||||
StringMap, Tuple, TypedArray>;
|
||||
using ReflectionType = std::variant<AllOf,
|
||||
AnyOf,
|
||||
Boolean,
|
||||
ExclusiveMaximum,
|
||||
ExclusiveMinimum,
|
||||
FixedSizeTypedArray,
|
||||
Integer,
|
||||
Maximum,
|
||||
Minimum,
|
||||
Number,
|
||||
Null,
|
||||
Object,
|
||||
OneOf,
|
||||
Reference,
|
||||
Regex,
|
||||
String,
|
||||
StringEnum,
|
||||
StringMap,
|
||||
Tuple,
|
||||
TypedArray>;
|
||||
|
||||
const auto& reflection() const { return value; }
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#ifndef RFL_JSON_TOSCHEMA_HPP_
|
||||
#define RFL_JSON_TOSCHEMA_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Literal.hpp"
|
||||
#include "../Processors.hpp"
|
||||
|
@ -32,7 +31,8 @@ inline bool is_optional(const parsing::schema::Type& _t) {
|
|||
return std::visit(handle, _t.variant_);
|
||||
}
|
||||
|
||||
inline std::string numeric_type_to_string(const parsing::schema::Type& _type) {
|
||||
inline std::string numeric_type_to_string(
|
||||
const parsing::schema::Type& _type) {
|
||||
const auto handle_variant = [](const auto& _t) -> std::string {
|
||||
using T = std::remove_cvref_t<decltype(_t)>;
|
||||
using Type = parsing::schema::Type;
|
||||
|
@ -77,17 +77,20 @@ inline schema::Type handle_validation_type(
|
|||
return schema::Type {.value = schema::Type::OneOf {.oneOf = one_of}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Regex>()) {
|
||||
return schema::Type{.value = schema::Type::Regex{.pattern = _v.pattern_}};
|
||||
return schema::Type {.value =
|
||||
schema::Type::Regex {.pattern = _v.pattern_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Size>()) {
|
||||
return type_to_json_schema_type(_type);
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::ExclusiveMaximum>()) {
|
||||
} else if constexpr (std::is_same<T,
|
||||
ValidationType::ExclusiveMaximum>()) {
|
||||
return schema::Type {.value = schema::Type::ExclusiveMaximum {
|
||||
.exclusiveMaximum = _v.value_,
|
||||
.type = numeric_type_to_string(_type)}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::ExclusiveMinimum>()) {
|
||||
} else if constexpr (std::is_same<T,
|
||||
ValidationType::ExclusiveMinimum>()) {
|
||||
return schema::Type {.value = schema::Type::ExclusiveMinimum {
|
||||
.exclusiveMinimum = _v.value_,
|
||||
.type = numeric_type_to_string(_type)}};
|
||||
|
@ -109,8 +112,8 @@ inline schema::Type handle_validation_type(
|
|||
const auto minimum = schema::Type {
|
||||
.value = schema::Type::Minimum {
|
||||
.minimum = _v.value_, .type = numeric_type_to_string(_type)}};
|
||||
return schema::Type{.value =
|
||||
schema::Type::AllOf{.allOf = {maximum, minimum}}};
|
||||
return schema::Type {
|
||||
.value = schema::Type::AllOf {.allOf = {maximum, minimum}}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::NotEqualTo>()) {
|
||||
const auto excl_maximum =
|
||||
|
@ -121,8 +124,8 @@ inline schema::Type handle_validation_type(
|
|||
schema::Type {.value = schema::Type::ExclusiveMinimum {
|
||||
.exclusiveMinimum = _v.value_,
|
||||
.type = numeric_type_to_string(_type)}};
|
||||
return schema::Type{
|
||||
.value = schema::Type::AnyOf{.anyOf = {excl_maximum, excl_minimum}}};
|
||||
return schema::Type {.value = schema::Type::AnyOf {
|
||||
.anyOf = {excl_maximum, excl_minimum}}};
|
||||
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
|
||||
|
@ -177,32 +180,33 @@ inline schema::Type type_to_json_schema_type(
|
|||
.maxContains = _t.size_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Literal>()) {
|
||||
return schema::Type{.value =
|
||||
schema::Type::StringEnum{.values = _t.values_}};
|
||||
return schema::Type {
|
||||
.value = schema::Type::StringEnum {.values = _t.values_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Object>()) {
|
||||
auto properties = std::map<std::string, schema::Type>();
|
||||
auto required = std::vector<std::string>();
|
||||
for (const auto& [k, v] : _t.types_) {
|
||||
properties[k] = type_to_json_schema_type(v);
|
||||
if (!is_optional(v)) {
|
||||
required.push_back(k);
|
||||
if (!is_optional(v)) { required.push_back(k); }
|
||||
}
|
||||
}
|
||||
return schema::Type{.value = schema::Type::Object{
|
||||
.properties = properties, .required = required}};
|
||||
return schema::Type {.value =
|
||||
schema::Type::Object {.properties = properties,
|
||||
.required = required}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Optional>()) {
|
||||
return schema::Type{.value = schema::Type::AnyOf{
|
||||
return schema::Type {
|
||||
.value = schema::Type::AnyOf {
|
||||
.anyOf = {type_to_json_schema_type(*_t.type_),
|
||||
schema::Type {schema::Type::Null {}}}}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Reference>()) {
|
||||
return schema::Type{
|
||||
.value = schema::Type::Reference{.ref = "#/definitions/" + _t.name_}};
|
||||
return schema::Type {.value = schema::Type::Reference {
|
||||
.ref = "#/definitions/" + _t.name_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::StringMap>()) {
|
||||
return schema::Type{.value = schema::Type::StringMap{
|
||||
return schema::Type {
|
||||
.value = schema::Type::StringMap {
|
||||
.additionalProperties = Ref<schema::Type>::make(
|
||||
type_to_json_schema_type(*_t.value_type_))}};
|
||||
|
||||
|
@ -211,7 +215,8 @@ inline schema::Type type_to_json_schema_type(
|
|||
for (const auto& t : _t.types_) {
|
||||
items.emplace_back(type_to_json_schema_type(t));
|
||||
}
|
||||
return schema::Type{.value = schema::Type::Tuple{.prefixItems = items}};
|
||||
return schema::Type {.value =
|
||||
schema::Type::Tuple {.prefixItems = items}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::TypedArray>()) {
|
||||
return schema::Type {.value = schema::Type::TypedArray {
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#ifndef RFL_JSON_WRITE_HPP_
|
||||
#define RFL_JSON_WRITE_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Processors.hpp"
|
||||
#include "../parsing/Parent.hpp"
|
||||
|
@ -23,7 +22,8 @@ std::string write(const auto& _obj, const yyjson_write_flag _flag = 0) {
|
|||
using T = std::remove_cvref_t<decltype(_obj)>;
|
||||
using ParentType = parsing::Parent<Writer>;
|
||||
auto w = Writer(yyjson_mut_doc_new(NULL));
|
||||
Parser<T, Processors<Ps...>>::write(w, _obj, typename ParentType::Root{});
|
||||
Parser<T, Processors<Ps...>>::write(w, _obj,
|
||||
typename ParentType::Root {});
|
||||
const char* json_c_str = yyjson_mut_write(w.doc_, _flag, NULL);
|
||||
const auto json_str = std::string(json_c_str);
|
||||
free((void*)json_c_str);
|
||||
|
@ -33,12 +33,14 @@ std::string write(const auto& _obj, const yyjson_write_flag _flag = 0) {
|
|||
|
||||
/// Writes a JSON into an ostream.
|
||||
template <class... Ps>
|
||||
std::ostream& write(const auto& _obj, std::ostream& _stream,
|
||||
std::ostream& write(const auto& _obj,
|
||||
std::ostream& _stream,
|
||||
const yyjson_write_flag _flag = 0) {
|
||||
using T = std::remove_cvref_t<decltype(_obj)>;
|
||||
using ParentType = parsing::Parent<Writer>;
|
||||
auto w = Writer(yyjson_mut_doc_new(NULL));
|
||||
Parser<T, Processors<Ps...>>::write(w, _obj, typename ParentType::Root{});
|
||||
Parser<T, Processors<Ps...>>::write(w, _obj,
|
||||
typename ParentType::Root {});
|
||||
const char* json_c_str = yyjson_mut_write(w.doc_, _flag, NULL);
|
||||
_stream << json_c_str;
|
||||
free((void*)json_c_str);
|
||||
|
|
|
@ -9,27 +9,37 @@ namespace rfl {
|
|||
namespace parsing {
|
||||
|
||||
/// msgpack-c requires us to explicitly set the number of fields in advance.
|
||||
/// Because of that, we require all of the fields and then set them to nullptr,
|
||||
/// if necessary.
|
||||
/// Because of that, we require all of the fields and then set them to
|
||||
/// nullptr, if necessary.
|
||||
template <class ProcessorsType, class... FieldTypes>
|
||||
requires AreReaderAndWriter<msgpack::Reader, msgpack::Writer,
|
||||
requires AreReaderAndWriter<msgpack::Reader,
|
||||
msgpack::Writer,
|
||||
NamedTuple<FieldTypes...>>
|
||||
struct Parser<msgpack::Reader, msgpack::Writer, NamedTuple<FieldTypes...>,
|
||||
struct Parser<msgpack::Reader,
|
||||
msgpack::Writer,
|
||||
NamedTuple<FieldTypes...>,
|
||||
ProcessorsType>
|
||||
: public NamedTupleParser<msgpack::Reader, msgpack::Writer,
|
||||
: public NamedTupleParser<msgpack::Reader,
|
||||
msgpack::Writer,
|
||||
/*_ignore_empty_containers=*/false,
|
||||
/*_all_required=*/true, ProcessorsType,
|
||||
FieldTypes...> {
|
||||
};
|
||||
/*_all_required=*/true,
|
||||
ProcessorsType,
|
||||
FieldTypes...> {};
|
||||
|
||||
template <class ProcessorsType, class... Ts>
|
||||
requires AreReaderAndWriter<msgpack::Reader, msgpack::Writer, std::tuple<Ts...>>
|
||||
struct Parser<msgpack::Reader, msgpack::Writer, std::tuple<Ts...>,
|
||||
requires AreReaderAndWriter<msgpack::Reader,
|
||||
msgpack::Writer,
|
||||
std::tuple<Ts...>>
|
||||
struct Parser<msgpack::Reader,
|
||||
msgpack::Writer,
|
||||
std::tuple<Ts...>,
|
||||
ProcessorsType>
|
||||
: public TupleParser<msgpack::Reader, msgpack::Writer,
|
||||
: public TupleParser<msgpack::Reader,
|
||||
msgpack::Writer,
|
||||
/*_ignore_empty_containers=*/false,
|
||||
/*_all_required=*/true, ProcessorsType, Ts...> {
|
||||
};
|
||||
/*_all_required=*/true,
|
||||
ProcessorsType,
|
||||
Ts...> {};
|
||||
|
||||
} // namespace parsing
|
||||
} // namespace rfl
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#ifndef RFL_MSGPACK_READER_HPP_
|
||||
#define RFL_MSGPACK_READER_HPP_
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <msgpack.h>
|
||||
#include <source_location>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
@ -30,12 +29,12 @@ struct Reader {
|
|||
using InputVarType = msgpack_object;
|
||||
|
||||
template <class T>
|
||||
static constexpr bool has_custom_constructor = (requires(InputVarType var) {
|
||||
T::from_msgpack_obj(var);
|
||||
});
|
||||
static constexpr bool has_custom_constructor =
|
||||
(requires(InputVarType var) { T::from_msgpack_obj(var); });
|
||||
|
||||
rfl::Result<InputVarType> get_field(
|
||||
const std::string& _name, const InputObjectType& _obj) const noexcept {
|
||||
const std::string& _name,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
for (uint32_t i = 0; i < _obj.size; ++i) {
|
||||
const auto& key = _obj.ptr[i].key;
|
||||
if (key.type != MSGPACK_OBJECT_STR) {
|
||||
|
@ -44,9 +43,7 @@ struct Reader {
|
|||
}
|
||||
const auto current_name =
|
||||
std::string_view(key.via.str.ptr, key.via.str.size);
|
||||
if (_name == current_name) {
|
||||
return _obj.ptr[i].val;
|
||||
}
|
||||
if (_name == current_name) { return _obj.ptr[i].val; }
|
||||
}
|
||||
return Error("No field named '" + _name + "' was found.");
|
||||
}
|
||||
|
@ -71,8 +68,8 @@ struct Reader {
|
|||
return _var.via.boolean;
|
||||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>() ||
|
||||
std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
if (type == MSGPACK_OBJECT_FLOAT32 || type == MSGPACK_OBJECT_FLOAT64 ||
|
||||
type == MSGPACK_OBJECT_FLOAT) {
|
||||
if (type == MSGPACK_OBJECT_FLOAT32 ||
|
||||
type == MSGPACK_OBJECT_FLOAT64 || type == MSGPACK_OBJECT_FLOAT) {
|
||||
return static_cast<T>(_var.via.f64);
|
||||
} else if (type == MSGPACK_OBJECT_POSITIVE_INTEGER) {
|
||||
return static_cast<T>(_var.via.u64);
|
||||
|
@ -80,7 +77,8 @@ struct Reader {
|
|||
return static_cast<T>(_var.via.i64);
|
||||
}
|
||||
return rfl::Error(
|
||||
"Could not cast to numeric value. The type must be integral, float "
|
||||
"Could not cast to numeric value. The type must be integral, "
|
||||
"float "
|
||||
"or double.");
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
|
@ -104,19 +102,19 @@ struct Reader {
|
|||
}
|
||||
|
||||
template <class ArrayReader>
|
||||
std::optional<Error> read_array(const ArrayReader& _array_reader,
|
||||
std::optional<Error> read_array(
|
||||
const ArrayReader& _array_reader,
|
||||
const InputArrayType& _arr) const noexcept {
|
||||
for (uint32_t i = 0; i < _arr.size; ++i) {
|
||||
const auto err = _array_reader.read(_arr.ptr[i]);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (err) { return err; }
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <class ObjectReader>
|
||||
std::optional<Error> read_object(const ObjectReader& _object_reader,
|
||||
std::optional<Error> read_object(
|
||||
const ObjectReader& _object_reader,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
for (uint32_t i = 0; i < _obj.size; ++i) {
|
||||
const auto& key = _obj.ptr[i].key;
|
||||
|
@ -136,9 +134,7 @@ struct Reader {
|
|||
const InputVarType& _var) const noexcept {
|
||||
try {
|
||||
return T::from_msgpack_obj(_var);
|
||||
} catch (std::exception& e) {
|
||||
return rfl::Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return rfl::Error(e.what()); }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#ifndef RFL_MSGPACK_WRITER_HPP_
|
||||
#define RFL_MSGPACK_WRITER_HPP_
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <msgpack.h>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
@ -54,13 +53,15 @@ class Writer {
|
|||
return new_value(_var);
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_array(const size_t _size,
|
||||
OutputArrayType add_array_to_array(
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
return new_array(_size);
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
msgpack_pack_str(pk_, _name.size());
|
||||
msgpack_pack_str_body(pk_, _name.data(), _name.size());
|
||||
|
@ -68,12 +69,14 @@ class Writer {
|
|||
}
|
||||
|
||||
OutputObjectType add_object_to_array(
|
||||
const size_t _size, OutputArrayType* _parent) const noexcept {
|
||||
const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
return new_object(_size);
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
msgpack_pack_str(pk_, _name.size());
|
||||
msgpack_pack_str_body(pk_, _name.data(), _name.size());
|
||||
|
@ -87,7 +90,8 @@ class Writer {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_object(const std::string_view& _name,
|
||||
OutputVarType add_value_to_object(
|
||||
const std::string_view& _name,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
msgpack_pack_str(pk_, _name.size());
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef RFL_MSGPACK_READ_HPP_
|
||||
#define RFL_MSGPACK_READ_HPP_
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include <istream>
|
||||
#include <msgpack.h>
|
||||
#include <string>
|
||||
|
||||
#include "../Processors.hpp"
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef RFL_MSGPACK_WRITE_HPP_
|
||||
#define RFL_MSGPACK_WRITE_HPP_
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <msgpack.h>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
|
|
@ -18,8 +18,8 @@ struct remove_ptr;
|
|||
|
||||
template <internal::StringLiteral _name, class T>
|
||||
struct remove_ptr<Field<_name, T>> {
|
||||
using FieldType =
|
||||
Field<_name, internal::wrap_in_rfl_array_t<
|
||||
using FieldType = Field<_name,
|
||||
internal::wrap_in_rfl_array_t<
|
||||
std::remove_cvref_t<std::remove_pointer_t<T>>>>;
|
||||
};
|
||||
|
||||
|
@ -33,8 +33,8 @@ struct remove_ptrs_nt<NamedTuple<FieldTypes...>> {
|
|||
};
|
||||
|
||||
/// Generates the named tuple that is equivalent to the struct T.
|
||||
/// This is the result you would expect from calling to_named_tuple(my_struct).
|
||||
/// All fields of the struct must be an rfl::Field.
|
||||
/// This is the result you would expect from calling
|
||||
/// to_named_tuple(my_struct). All fields of the struct must be an rfl::Field.
|
||||
template <class T>
|
||||
using named_tuple_t =
|
||||
typename remove_ptrs_nt<internal::ptr_named_tuple_t<T>>::NamedTupleType;
|
||||
|
|
|
@ -12,10 +12,14 @@
|
|||
namespace rfl {
|
||||
namespace parsing {
|
||||
|
||||
template <class R, class W, class ProcessorsType, class OriginalClass,
|
||||
template <class R,
|
||||
class W,
|
||||
class ProcessorsType,
|
||||
class OriginalClass,
|
||||
class HelperStruct>
|
||||
struct CustomParser {
|
||||
static Result<OriginalClass> read(const R& _r, const auto& _var) noexcept {
|
||||
static Result<OriginalClass> read(const R& _r,
|
||||
const auto& _var) noexcept {
|
||||
const auto to_class = [](auto&& _h) -> Result<OriginalClass> {
|
||||
try {
|
||||
if constexpr (internal::has_to_class_method_v<HelperStruct>) {
|
||||
|
@ -27,16 +31,15 @@ struct CustomParser {
|
|||
};
|
||||
return std::apply(class_from_ptrs, ptr_field_tuple);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
return Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return Error(e.what()); }
|
||||
};
|
||||
return Parser<R, W, HelperStruct, ProcessorsType>::read(_r, _var).and_then(
|
||||
to_class);
|
||||
return Parser<R, W, HelperStruct, ProcessorsType>::read(_r, _var)
|
||||
.and_then(to_class);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
static auto write(const W& _w, const OriginalClass& _p,
|
||||
static auto write(const W& _w,
|
||||
const OriginalClass& _p,
|
||||
const P& _parent) noexcept {
|
||||
Parser<R, W, HelperStruct, ProcessorsType>::write(
|
||||
_w, HelperStruct::from_class(_p), _parent);
|
||||
|
|
|
@ -43,9 +43,7 @@ struct FieldVariantParser {
|
|||
FieldVariantReader<R, W, ProcessorsType, FieldTypes...>(
|
||||
&_r, &field_variant);
|
||||
auto err = _r.read_object(reader, _obj);
|
||||
if (err) {
|
||||
return *err;
|
||||
}
|
||||
if (err) { return *err; }
|
||||
if (!field_variant) {
|
||||
return Error(
|
||||
"Could not parse: Expected the object to have "
|
||||
|
@ -58,7 +56,8 @@ struct FieldVariantParser {
|
|||
}
|
||||
|
||||
template <class P>
|
||||
static void write(const W& _w, const std::variant<FieldTypes...>& _v,
|
||||
static void write(const W& _w,
|
||||
const std::variant<FieldTypes...>& _v,
|
||||
const P& _parent) noexcept {
|
||||
static_assert(
|
||||
internal::no_duplicate_field_names<std::tuple<FieldTypes...>>(),
|
||||
|
@ -66,7 +65,8 @@ struct FieldVariantParser {
|
|||
"names.");
|
||||
|
||||
const auto handle = [&](const auto& _field) {
|
||||
const auto named_tuple = make_named_tuple(internal::to_ptr_field(_field));
|
||||
const auto named_tuple =
|
||||
make_named_tuple(internal::to_ptr_field(_field));
|
||||
using NamedTupleType = std::remove_cvref_t<decltype(named_tuple)>;
|
||||
Parser<R, W, NamedTupleType, ProcessorsType>::write(_w, named_tuple,
|
||||
_parent);
|
||||
|
@ -79,7 +79,8 @@ struct FieldVariantParser {
|
|||
std::map<std::string, schema::Type>* _definitions,
|
||||
std::vector<schema::Type> _types = {}) {
|
||||
using VariantType = std::variant<NamedTuple<FieldTypes>...>;
|
||||
return Parser<R, W, VariantType, ProcessorsType>::to_schema(_definitions);
|
||||
return Parser<R, W, VariantType, ProcessorsType>::to_schema(
|
||||
_definitions);
|
||||
}
|
||||
};
|
||||
} // namespace parsing
|
||||
|
|
|
@ -30,7 +30,9 @@ struct MockObjectReader {
|
|||
};
|
||||
|
||||
template <class R, class T>
|
||||
concept IsReader = requires(R r, std::string name,
|
||||
concept IsReader = requires(
|
||||
R r,
|
||||
std::string name,
|
||||
std::function<std::int16_t(std::string_view)> fct,
|
||||
MockArrayReader<R> array_reader,
|
||||
MockObjectReader<R> object_reader,
|
||||
|
@ -60,10 +62,12 @@ concept IsReader = requires(R r, std::string name,
|
|||
/// an array reader.
|
||||
{ r.read_array(array_reader, arr) } -> std::same_as<std::optional<Error>>;
|
||||
|
||||
/// Iterates through an object and writes the key-value pairs into an object
|
||||
/// reader. This is what we use to handle structs and named tuples, making it
|
||||
/// a very important function.
|
||||
{ r.read_object(object_reader, obj) } -> std::same_as<std::optional<Error>>;
|
||||
/// Iterates through an object and writes the key-value pairs into an
|
||||
/// object reader. This is what we use to handle structs and named tuples,
|
||||
/// making it a very important function.
|
||||
{
|
||||
r.read_object(object_reader, obj)
|
||||
} -> std::same_as<std::optional<Error>>;
|
||||
|
||||
/// Transforms var to a basic type (bool, integral,
|
||||
/// floating point, std::string)
|
||||
|
@ -72,7 +76,9 @@ concept IsReader = requires(R r, std::string name,
|
|||
} -> std::same_as<rfl::Result<internal::wrap_in_rfl_array_t<T>>>;
|
||||
|
||||
/// Casts var as an InputArrayType.
|
||||
{ r.to_array(var) } -> std::same_as<rfl::Result<typename R::InputArrayType>>;
|
||||
{
|
||||
r.to_array(var)
|
||||
} -> std::same_as<rfl::Result<typename R::InputArrayType>>;
|
||||
|
||||
/// Casts var as an InputObjectType.
|
||||
{
|
||||
|
|
|
@ -11,11 +11,14 @@ namespace rfl {
|
|||
namespace parsing {
|
||||
|
||||
template <class W, class T>
|
||||
concept IsWriter = requires(W w, T t, std::string_view name,
|
||||
concept IsWriter = requires(W w,
|
||||
T t,
|
||||
std::string_view name,
|
||||
std::string basic_value,
|
||||
typename W::OutputArrayType arr,
|
||||
typename W::OutputObjectType obj,
|
||||
typename W::OutputVarType var, size_t size) {
|
||||
typename W::OutputVarType var,
|
||||
size_t size) {
|
||||
/// Sets an empty array 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
|
||||
|
@ -35,7 +38,9 @@ concept IsWriter = requires(W w, T t, std::string_view name,
|
|||
|
||||
/// Sets a basic value (bool, numeric, string) as the root element of the
|
||||
/// document. Returns an OutputVarType containing the new value.
|
||||
{ w.value_as_root(basic_value) } -> std::same_as<typename W::OutputVarType>;
|
||||
{
|
||||
w.value_as_root(basic_value)
|
||||
} -> std::same_as<typename W::OutputVarType>;
|
||||
|
||||
/// Adds an empty array to an existing array. Returns the new
|
||||
/// array for further modification.
|
||||
|
@ -49,14 +54,16 @@ concept IsWriter = requires(W w, T t, std::string_view name,
|
|||
w.add_object_to_array(size, &arr)
|
||||
} -> std::same_as<typename W::OutputObjectType>;
|
||||
|
||||
/// Adds an empty array to an existing object. The key or name of the field is
|
||||
/// signified by `name`. Returns the new array for further modification.
|
||||
/// Adds an empty array to an existing object. The key or name of the
|
||||
/// field is signified by `name`. Returns the new array for further
|
||||
/// modification.
|
||||
{
|
||||
w.add_array_to_object(name, size, &obj)
|
||||
} -> std::same_as<typename W::OutputArrayType>;
|
||||
|
||||
/// Adds an empty object to an existing object. The key or name of the field
|
||||
/// is signified by `name`. Returns the new object for further modification.
|
||||
/// Adds an empty object to an existing object. The key or name of the
|
||||
/// field is signified by `name`. Returns the new object for further
|
||||
/// modification.
|
||||
{
|
||||
w.add_object_to_object(name, size, &obj)
|
||||
} -> std::same_as<typename W::OutputObjectType>;
|
||||
|
@ -67,8 +74,8 @@ concept IsWriter = requires(W w, T t, std::string_view name,
|
|||
w.add_value_to_array(basic_value, &arr)
|
||||
} -> std::same_as<typename W::OutputVarType>;
|
||||
|
||||
/// Adds a basic value (bool, numeric, string) to an existing object. The key
|
||||
/// or name of the field is signified by `name`. Returns an
|
||||
/// Adds a basic value (bool, numeric, string) to an existing object. The
|
||||
/// key or name of the field is signified by `name`. Returns an
|
||||
/// OutputVarType containing the new value.
|
||||
{
|
||||
w.add_value_to_object(name, basic_value, &obj)
|
||||
|
@ -85,14 +92,16 @@ concept IsWriter = requires(W w, T t, std::string_view name,
|
|||
w.add_null_to_object(name, &obj)
|
||||
} -> std::same_as<typename W::OutputVarType>;
|
||||
|
||||
/// Signifies to the writer that we do not want to add any further elements to
|
||||
/// this array. Some serialization formats require this. If you are working
|
||||
/// with a serialization format that doesn't, just leave the function empty.
|
||||
/// Signifies to the writer that we do not want to add any further
|
||||
/// elements to this array. Some serialization formats require this. If
|
||||
/// you are working with a serialization format that doesn't, just leave
|
||||
/// the function empty.
|
||||
{ w.end_array(&arr) } -> std::same_as<void>;
|
||||
|
||||
/// Signifies to the writer that we do not want to add any further elements to
|
||||
/// this object. Some serialization formats require this. If you are working
|
||||
/// with a serialization format that doesn't, just leave the function empty.
|
||||
/// Signifies to the writer that we do not want to add any further
|
||||
/// elements to this object. Some serialization formats require this. If
|
||||
/// you are working with a serialization format that doesn't, just leave
|
||||
/// the function empty.
|
||||
{ w.end_object(&obj) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
|
|
|
@ -28,13 +28,15 @@ struct MapParser {
|
|||
using OutputObjectType = typename W::OutputObjectType;
|
||||
using OutputVarType = typename W::OutputVarType;
|
||||
|
||||
using KeyType = std::remove_cvref_t<typename MapType::value_type::first_type>;
|
||||
using KeyType =
|
||||
std::remove_cvref_t<typename MapType::value_type::first_type>;
|
||||
using ValueType =
|
||||
std::remove_cvref_t<typename MapType::value_type::second_type>;
|
||||
|
||||
using ParentType = Parent<W>;
|
||||
|
||||
static Result<MapType> read(const R& _r, const InputVarType& _var) noexcept {
|
||||
static Result<MapType> read(const R& _r,
|
||||
const InputVarType& _var) noexcept {
|
||||
const auto to_map = [&](auto obj) -> Result<MapType> {
|
||||
return make_map(_r, obj);
|
||||
};
|
||||
|
@ -42,7 +44,9 @@ struct MapParser {
|
|||
}
|
||||
|
||||
template <class P>
|
||||
static void write(const W& _w, const MapType& _m, const P& _parent) noexcept {
|
||||
static void write(const W& _w,
|
||||
const MapType& _m,
|
||||
const P& _parent) noexcept {
|
||||
auto obj = ParentType::add_object(_w, _m.size(), _parent);
|
||||
for (const auto& [k, v] : _m) {
|
||||
if constexpr (internal::has_reflection_type_v<KeyType>) {
|
||||
|
@ -52,13 +56,13 @@ struct MapParser {
|
|||
std::is_floating_point_v<ReflT>) {
|
||||
const auto name = std::to_string(k.reflection());
|
||||
const auto new_parent = typename ParentType::Object {name, &obj};
|
||||
Parser<R, W, std::remove_cvref_t<ValueType>, ProcessorsType>::write(
|
||||
_w, v, new_parent);
|
||||
Parser<R, W, std::remove_cvref_t<ValueType>,
|
||||
ProcessorsType>::write(_w, v, new_parent);
|
||||
} else {
|
||||
const auto name = k.reflection();
|
||||
const auto new_parent = typename ParentType::Object {name, &obj};
|
||||
Parser<R, W, std::remove_cvref_t<ValueType>, ProcessorsType>::write(
|
||||
_w, v, new_parent);
|
||||
Parser<R, W, std::remove_cvref_t<ValueType>,
|
||||
ProcessorsType>::write(_w, v, new_parent);
|
||||
}
|
||||
|
||||
} else if constexpr (std::is_integral_v<KeyType> ||
|
||||
|
@ -83,18 +87,15 @@ struct MapParser {
|
|||
}
|
||||
|
||||
private:
|
||||
static Result<MapType> make_map(const R& _r, const InputObjectType& _obj) {
|
||||
static Result<MapType> make_map(const R& _r,
|
||||
const InputObjectType& _obj) {
|
||||
MapType map;
|
||||
std::vector<Error> errors;
|
||||
const auto map_reader =
|
||||
MapReader<R, W, MapType, ProcessorsType>(&_r, &map, &errors);
|
||||
const auto err = _r.read_object(map_reader, _obj);
|
||||
if (err) {
|
||||
return *err;
|
||||
}
|
||||
if (errors.size() != 0) {
|
||||
return to_single_error_message(errors);
|
||||
}
|
||||
if (err) { return *err; }
|
||||
if (errors.size() != 0) { return to_single_error_message(errors); }
|
||||
return map;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,7 +16,8 @@ template <class R, class W, class MapType, class ProcessorsType>
|
|||
class MapReader {
|
||||
private:
|
||||
using InputVarType = typename R::InputVarType;
|
||||
using KeyType = std::remove_cvref_t<typename MapType::value_type::first_type>;
|
||||
using KeyType =
|
||||
std::remove_cvref_t<typename MapType::value_type::first_type>;
|
||||
using ValueType =
|
||||
std::remove_cvref_t<typename MapType::value_type::second_type>;
|
||||
|
||||
|
@ -32,7 +33,8 @@ class MapReader {
|
|||
if (res) {
|
||||
map_->emplace(std::move(*res));
|
||||
} else {
|
||||
errors_->push_back(Error("Failed to parse field '" + std::string(_name) +
|
||||
errors_->push_back(Error("Failed to parse field '" +
|
||||
std::string(_name) +
|
||||
"': " + res.error()->what()));
|
||||
}
|
||||
}
|
||||
|
@ -50,9 +52,7 @@ class MapReader {
|
|||
} else {
|
||||
static_assert(always_false_v<T>, "Unsupported type");
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
return Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return Error(e.what()); }
|
||||
}
|
||||
|
||||
Result<std::pair<KeyType, ValueType>> make_key(auto& _pair) const noexcept {
|
||||
|
@ -61,9 +61,7 @@ class MapReader {
|
|||
try {
|
||||
return std::make_pair(KeyType(std::move(_key)),
|
||||
std::move(_pair.second));
|
||||
} catch (std::exception& e) {
|
||||
return Error(e.what());
|
||||
}
|
||||
} catch (std::exception& e) { return Error(e.what()); }
|
||||
};
|
||||
|
||||
if constexpr (std::is_integral_v<KeyType> ||
|
||||
|
@ -86,7 +84,8 @@ class MapReader {
|
|||
}
|
||||
|
||||
Result<std::pair<KeyType, ValueType>> get_pair(
|
||||
const std::string_view& _name, const InputVarType& _var) const noexcept {
|
||||
const std::string_view& _name,
|
||||
const InputVarType& _var) const noexcept {
|
||||
const auto to_pair = [&](ValueType&& _val) {
|
||||
auto pair = std::make_pair(std::string(_name), std::move(_val));
|
||||
return make_key(pair);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue