:3
This commit is contained in:
parent
a743cdabe5
commit
bd402f57f5
276 changed files with 37936 additions and 22932 deletions
|
@ -7,9 +7,9 @@
|
|||
|
||||
namespace rfl::json {
|
||||
|
||||
template <class T, class ProcessorsType>
|
||||
using Parser = parsing::Parser<Reader, Writer, T, ProcessorsType>;
|
||||
template <class T, class ProcessorsType>
|
||||
using Parser = parsing::Parser<Reader, Writer, T, ProcessorsType>;
|
||||
|
||||
} // namespace rfl::json
|
||||
} // namespace rfl::json
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef RFL_JSON_READER_HPP_
|
||||
#define RFL_JSON_READER_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <exception>
|
||||
|
@ -15,140 +13,138 @@
|
|||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Result.hpp"
|
||||
#include "../always_false.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace json {
|
||||
namespace json {
|
||||
|
||||
struct Reader {
|
||||
struct YYJSONInputArray {
|
||||
YYJSONInputArray(yyjson_val* _val) : val_(_val) {}
|
||||
yyjson_val* val_;
|
||||
};
|
||||
struct Reader {
|
||||
struct YYJSONInputArray {
|
||||
YYJSONInputArray(yyjson_val* _val) : val_(_val) {}
|
||||
yyjson_val* val_;
|
||||
};
|
||||
|
||||
struct YYJSONInputObject {
|
||||
YYJSONInputObject(yyjson_val* _val) : val_(_val) {}
|
||||
yyjson_val* val_;
|
||||
};
|
||||
struct YYJSONInputObject {
|
||||
YYJSONInputObject(yyjson_val* _val) : val_(_val) {}
|
||||
yyjson_val* val_;
|
||||
};
|
||||
|
||||
struct YYJSONInputVar {
|
||||
YYJSONInputVar() : val_(nullptr) {}
|
||||
YYJSONInputVar(yyjson_val* _val) : val_(_val) {}
|
||||
yyjson_val* val_;
|
||||
};
|
||||
struct YYJSONInputVar {
|
||||
YYJSONInputVar() : val_(nullptr) {}
|
||||
YYJSONInputVar(yyjson_val* _val) : val_(_val) {}
|
||||
yyjson_val* val_;
|
||||
};
|
||||
|
||||
using InputArrayType = YYJSONInputArray;
|
||||
using InputObjectType = YYJSONInputObject;
|
||||
using InputVarType = YYJSONInputVar;
|
||||
using InputArrayType = YYJSONInputArray;
|
||||
using InputObjectType = YYJSONInputObject;
|
||||
using InputVarType = YYJSONInputVar;
|
||||
|
||||
template <class T>
|
||||
static constexpr bool has_custom_constructor = (requires(InputVarType var) {
|
||||
T::from_json_obj(var);
|
||||
});
|
||||
template <class T>
|
||||
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 auto var = InputVarType(yyjson_obj_get(_obj.val_, _name.c_str()));
|
||||
if (!var.val_) {
|
||||
return rfl::Error("Object contains no field named '" + _name + "'.");
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
bool is_empty(const InputVarType _var) const noexcept {
|
||||
return !_var.val_ || yyjson_is_null(_var.val_);
|
||||
}
|
||||
|
||||
template <class ArrayReader>
|
||||
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;
|
||||
rfl::Result<InputVarType> get_field(
|
||||
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 + "'.");
|
||||
}
|
||||
return var;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <class ObjectReader>
|
||||
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);
|
||||
yyjson_val* key;
|
||||
while ((key = yyjson_obj_iter_next(&iter))) {
|
||||
const auto name = std::string_view(yyjson_get_str(key));
|
||||
_object_reader.read(name, InputVarType(yyjson_obj_iter_get_val(key)));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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.");
|
||||
bool is_empty(const InputVarType _var) const noexcept {
|
||||
return !_var.val_ || yyjson_is_null(_var.val_);
|
||||
}
|
||||
return std::string(r);
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
if (!yyjson_is_bool(_var.val_)) {
|
||||
return rfl::Error("Could not cast to boolean.");
|
||||
|
||||
template <class ArrayReader>
|
||||
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; }
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
return yyjson_get_bool(_var.val_);
|
||||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>()) {
|
||||
if (!yyjson_is_num(_var.val_)) {
|
||||
return rfl::Error("Could not cast to double.");
|
||||
|
||||
template <class ObjectReader>
|
||||
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);
|
||||
yyjson_val* key;
|
||||
while ((key = yyjson_obj_iter_next(&iter))) {
|
||||
const auto name = std::string_view(yyjson_get_str(key));
|
||||
_object_reader.read(name, InputVarType(yyjson_obj_iter_get_val(key)));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
return static_cast<T>(yyjson_get_num(_var.val_));
|
||||
} else if constexpr (std::is_unsigned<std::remove_cvref_t<T>>()) {
|
||||
if (!yyjson_is_int(_var.val_)) {
|
||||
return rfl::Error("Could not cast to int.");
|
||||
|
||||
template <class T>
|
||||
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."); }
|
||||
return std::string(r);
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
if (!yyjson_is_bool(_var.val_)) {
|
||||
return rfl::Error("Could not cast to boolean.");
|
||||
}
|
||||
return yyjson_get_bool(_var.val_);
|
||||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>()) {
|
||||
if (!yyjson_is_num(_var.val_)) {
|
||||
return rfl::Error("Could not cast to double.");
|
||||
}
|
||||
return static_cast<T>(yyjson_get_num(_var.val_));
|
||||
} else if constexpr (std::is_unsigned<std::remove_cvref_t<T>>()) {
|
||||
if (!yyjson_is_int(_var.val_)) {
|
||||
return rfl::Error("Could not cast to int.");
|
||||
}
|
||||
return static_cast<T>(yyjson_get_uint(_var.val_));
|
||||
} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
if (!yyjson_is_int(_var.val_)) {
|
||||
return rfl::Error("Could not cast to int.");
|
||||
}
|
||||
return static_cast<T>(yyjson_get_sint(_var.val_));
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
}
|
||||
}
|
||||
return static_cast<T>(yyjson_get_uint(_var.val_));
|
||||
} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
if (!yyjson_is_int(_var.val_)) {
|
||||
return rfl::Error("Could not cast to int.");
|
||||
|
||||
rfl::Result<InputArrayType> to_array(
|
||||
const InputVarType _var) const noexcept {
|
||||
if (!yyjson_is_arr(_var.val_)) {
|
||||
return rfl::Error("Could not cast to array!");
|
||||
}
|
||||
return InputArrayType(_var.val_);
|
||||
}
|
||||
return static_cast<T>(yyjson_get_sint(_var.val_));
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
}
|
||||
}
|
||||
|
||||
rfl::Result<InputArrayType> to_array(const InputVarType _var) const noexcept {
|
||||
if (!yyjson_is_arr(_var.val_)) {
|
||||
return rfl::Error("Could not cast to array!");
|
||||
}
|
||||
return InputArrayType(_var.val_);
|
||||
}
|
||||
rfl::Result<InputObjectType> to_object(
|
||||
const InputVarType _var) const noexcept {
|
||||
if (!yyjson_is_obj(_var.val_)) {
|
||||
return rfl::Error("Could not cast to object!");
|
||||
}
|
||||
return InputObjectType(_var.val_);
|
||||
}
|
||||
|
||||
rfl::Result<InputObjectType> to_object(
|
||||
const InputVarType _var) const noexcept {
|
||||
if (!yyjson_is_obj(_var.val_)) {
|
||||
return rfl::Error("Could not cast to object!");
|
||||
}
|
||||
return InputObjectType(_var.val_);
|
||||
}
|
||||
template <class T>
|
||||
rfl::Result<T> use_custom_constructor(
|
||||
const InputVarType _var) const noexcept {
|
||||
try {
|
||||
return T::from_json_obj(_var);
|
||||
} catch (std::exception& e) { return rfl::Error(e.what()); }
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
rfl::Result<T> use_custom_constructor(
|
||||
const InputVarType _var) const noexcept {
|
||||
try {
|
||||
return T::from_json_obj(_var);
|
||||
} catch (std::exception& e) {
|
||||
return rfl::Error(e.what());
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
|
||||
#endif // JSON_PARSER_HPP_
|
||||
#endif // JSON_PARSER_HPP_
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef RFL_JSON_WRITER_HPP_
|
||||
#define RFL_JSON_WRITER_HPP_
|
||||
|
||||
#include <yyjson.h>
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
@ -11,159 +9,169 @@
|
|||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <yyjson.h>
|
||||
|
||||
#include "../Result.hpp"
|
||||
#include "../always_false.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace json {
|
||||
namespace json {
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
struct YYJSONOutputArray {
|
||||
YYJSONOutputArray(yyjson_mut_val* _val) : val_(_val) {}
|
||||
yyjson_mut_val* val_;
|
||||
};
|
||||
class Writer {
|
||||
public:
|
||||
struct YYJSONOutputArray {
|
||||
YYJSONOutputArray(yyjson_mut_val* _val) : val_(_val) {}
|
||||
yyjson_mut_val* val_;
|
||||
};
|
||||
|
||||
struct YYJSONOutputObject {
|
||||
YYJSONOutputObject(yyjson_mut_val* _val) : val_(_val) {}
|
||||
yyjson_mut_val* val_;
|
||||
};
|
||||
struct YYJSONOutputObject {
|
||||
YYJSONOutputObject(yyjson_mut_val* _val) : val_(_val) {}
|
||||
yyjson_mut_val* val_;
|
||||
};
|
||||
|
||||
struct YYJSONOutputVar {
|
||||
YYJSONOutputVar(yyjson_mut_val* _val) : val_(_val) {}
|
||||
struct YYJSONOutputVar {
|
||||
YYJSONOutputVar(yyjson_mut_val* _val) : val_(_val) {}
|
||||
|
||||
YYJSONOutputVar(YYJSONOutputArray _arr) : val_(_arr.val_) {}
|
||||
YYJSONOutputVar(YYJSONOutputArray _arr) : val_(_arr.val_) {}
|
||||
|
||||
YYJSONOutputVar(YYJSONOutputObject _obj) : val_(_obj.val_) {}
|
||||
YYJSONOutputVar(YYJSONOutputObject _obj) : val_(_obj.val_) {}
|
||||
|
||||
yyjson_mut_val* val_;
|
||||
};
|
||||
yyjson_mut_val* val_;
|
||||
};
|
||||
|
||||
using OutputArrayType = YYJSONOutputArray;
|
||||
using OutputObjectType = YYJSONOutputObject;
|
||||
using OutputVarType = YYJSONOutputVar;
|
||||
using OutputArrayType = YYJSONOutputArray;
|
||||
using OutputObjectType = YYJSONOutputObject;
|
||||
using OutputVarType = YYJSONOutputVar;
|
||||
|
||||
Writer(yyjson_mut_doc* _doc) : doc_(_doc) {}
|
||||
Writer(yyjson_mut_doc* _doc) : doc_(_doc) {}
|
||||
|
||||
~Writer() = default;
|
||||
~Writer() = default;
|
||||
|
||||
OutputArrayType array_as_root(const size_t _size) const noexcept {
|
||||
const auto arr = yyjson_mut_arr(doc_);
|
||||
yyjson_mut_doc_set_root(doc_, arr);
|
||||
return OutputArrayType(arr);
|
||||
}
|
||||
OutputArrayType array_as_root(const size_t _size) const noexcept {
|
||||
const auto arr = yyjson_mut_arr(doc_);
|
||||
yyjson_mut_doc_set_root(doc_, arr);
|
||||
return OutputArrayType(arr);
|
||||
}
|
||||
|
||||
OutputObjectType object_as_root(const size_t _size) const noexcept {
|
||||
const auto obj = yyjson_mut_obj(doc_);
|
||||
yyjson_mut_doc_set_root(doc_, obj);
|
||||
return OutputObjectType(obj);
|
||||
}
|
||||
OutputObjectType object_as_root(const size_t _size) const noexcept {
|
||||
const auto obj = yyjson_mut_obj(doc_);
|
||||
yyjson_mut_doc_set_root(doc_, obj);
|
||||
return OutputObjectType(obj);
|
||||
}
|
||||
|
||||
OutputVarType null_as_root() const noexcept {
|
||||
const auto null = yyjson_mut_null(doc_);
|
||||
yyjson_mut_doc_set_root(doc_, null);
|
||||
return OutputVarType(null);
|
||||
}
|
||||
OutputVarType null_as_root() const noexcept {
|
||||
const auto null = yyjson_mut_null(doc_);
|
||||
yyjson_mut_doc_set_root(doc_, null);
|
||||
return OutputVarType(null);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType value_as_root(const T& _var) const noexcept {
|
||||
const auto val = from_basic_type(_var);
|
||||
yyjson_mut_doc_set_root(doc_, val.val_);
|
||||
return OutputVarType(val);
|
||||
}
|
||||
template <class T>
|
||||
OutputVarType value_as_root(const T& _var) const noexcept {
|
||||
const auto val = from_basic_type(_var);
|
||||
yyjson_mut_doc_set_root(doc_, val.val_);
|
||||
return OutputVarType(val);
|
||||
}
|
||||
|
||||
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);
|
||||
return OutputArrayType(arr);
|
||||
}
|
||||
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);
|
||||
return OutputArrayType(arr);
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_object(
|
||||
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()),
|
||||
arr);
|
||||
return OutputArrayType(arr);
|
||||
}
|
||||
OutputArrayType add_array_to_object(
|
||||
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()),
|
||||
arr);
|
||||
return OutputArrayType(arr);
|
||||
}
|
||||
|
||||
OutputObjectType add_object_to_array(
|
||||
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_array(
|
||||
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,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto obj = yyjson_mut_obj(doc_);
|
||||
yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()),
|
||||
obj);
|
||||
return OutputObjectType(obj);
|
||||
}
|
||||
OutputObjectType add_object_to_object(
|
||||
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()),
|
||||
obj);
|
||||
return OutputObjectType(obj);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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_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,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto val = from_basic_type(_var);
|
||||
yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()),
|
||||
val.val_);
|
||||
return OutputVarType(val);
|
||||
}
|
||||
template <class T>
|
||||
OutputVarType add_value_to_object(
|
||||
const std::string_view& _name,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto val = from_basic_type(_var);
|
||||
yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()),
|
||||
val.val_);
|
||||
return OutputVarType(val);
|
||||
}
|
||||
|
||||
OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept {
|
||||
const auto null = yyjson_mut_null(doc_);
|
||||
yyjson_mut_arr_add_val(_parent->val_, null);
|
||||
return OutputVarType(null);
|
||||
}
|
||||
OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept {
|
||||
const auto null = yyjson_mut_null(doc_);
|
||||
yyjson_mut_arr_add_val(_parent->val_, null);
|
||||
return OutputVarType(null);
|
||||
}
|
||||
|
||||
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()),
|
||||
null);
|
||||
return OutputVarType(null);
|
||||
}
|
||||
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()),
|
||||
null);
|
||||
return OutputVarType(null);
|
||||
}
|
||||
|
||||
void end_array(OutputArrayType* _arr) const noexcept {}
|
||||
void end_array(OutputArrayType* _arr) const noexcept {}
|
||||
|
||||
void end_object(OutputObjectType* _obj) const noexcept {}
|
||||
void end_object(OutputObjectType* _obj) const noexcept {}
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
OutputVarType from_basic_type(const T& _var) const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
return OutputVarType(yyjson_mut_strcpy(doc_, _var.c_str()));
|
||||
} 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)));
|
||||
} else if constexpr (std::is_unsigned<std::remove_cvref_t<T>>()) {
|
||||
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)));
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
}
|
||||
}
|
||||
private:
|
||||
template <class T>
|
||||
OutputVarType from_basic_type(const T& _var) const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
return OutputVarType(yyjson_mut_strcpy(doc_, _var.c_str()));
|
||||
} 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)));
|
||||
} else if constexpr (std::is_unsigned<std::remove_cvref_t<T>>()) {
|
||||
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)));
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
yyjson_mut_doc* doc_;
|
||||
};
|
||||
public:
|
||||
yyjson_mut_doc* doc_;
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
|
||||
#endif // JSON_PARSER_HPP_
|
||||
#endif // JSON_PARSER_HPP_
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
#include "read.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace json {
|
||||
namespace json {
|
||||
|
||||
template <class T, class... Ps>
|
||||
Result<T> load(const std::string& _fname) {
|
||||
const auto read_string = [](const auto& _str) {
|
||||
return read<T, Ps...>(_str);
|
||||
};
|
||||
return rfl::io::load_string(_fname).and_then(read_string);
|
||||
}
|
||||
template <class T, class... Ps>
|
||||
Result<T> load(const std::string& _fname) {
|
||||
const auto read_string = [](const auto& _str) {
|
||||
return read<T, Ps...>(_str);
|
||||
};
|
||||
return rfl::io::load_string(_fname).and_then(read_string);
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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"
|
||||
|
@ -12,41 +11,40 @@
|
|||
#include "Reader.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace json {
|
||||
namespace json {
|
||||
|
||||
using InputObjectType = typename Reader::InputObjectType;
|
||||
using InputVarType = typename Reader::InputVarType;
|
||||
using InputObjectType = typename Reader::InputObjectType;
|
||||
using InputVarType = typename Reader::InputVarType;
|
||||
|
||||
/// Parses an object from a JSON var.
|
||||
template <class T, class... Ps>
|
||||
auto read(const InputVarType& _obj) {
|
||||
const auto r = Reader();
|
||||
return Parser<T, Processors<Ps...>>::read(r, _obj);
|
||||
}
|
||||
/// Parses an object from a JSON var.
|
||||
template <class T, class... Ps>
|
||||
auto read(const InputVarType& _obj) {
|
||||
const auto r = Reader();
|
||||
return Parser<T, Processors<Ps...>>::read(r, _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) {
|
||||
yyjson_doc* doc = yyjson_read(_json_str.c_str(), _json_str.size(), 0);
|
||||
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));
|
||||
yyjson_doc_free(doc);
|
||||
return res;
|
||||
}
|
||||
/// 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) {
|
||||
yyjson_doc* doc = yyjson_read(_json_str.c_str(), _json_str.size(), 0);
|
||||
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));
|
||||
yyjson_doc_free(doc);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Parses an object from a stringstream.
|
||||
template <class T, class... Ps>
|
||||
auto read(std::istream& _stream) {
|
||||
const auto json_str = std::string(std::istreambuf_iterator<char>(_stream),
|
||||
std::istreambuf_iterator<char>());
|
||||
return read<T, Ps...>(json_str);
|
||||
}
|
||||
/// Parses an object from a stringstream.
|
||||
template <class T, class... Ps>
|
||||
auto read(std::istream& _stream) {
|
||||
const auto json_str = std::string(std::istreambuf_iterator<char>(_stream),
|
||||
std::istreambuf_iterator<char>());
|
||||
return read<T, Ps...>(json_str);
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
#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"
|
||||
#include "write.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace json {
|
||||
namespace json {
|
||||
|
||||
template <class... Ps>
|
||||
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& {
|
||||
return write<Ps...>(_obj, _stream, _flag);
|
||||
};
|
||||
return rfl::io::save_string(_fname, _obj, write_func);
|
||||
}
|
||||
template <class... Ps>
|
||||
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& {
|
||||
return write<Ps...>(_obj, _stream, _flag);
|
||||
};
|
||||
return rfl::io::save_string(_fname, _obj, write_func);
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,14 +12,14 @@
|
|||
|
||||
namespace rfl::json::schema {
|
||||
|
||||
template <class T>
|
||||
struct JSONSchema {
|
||||
Rename<"$schema", Literal<"https://json-schema.org/draft/2020-12/schema">>
|
||||
schema;
|
||||
Flatten<T> root;
|
||||
std::map<std::string, Type> definitions;
|
||||
};
|
||||
template <class T>
|
||||
struct JSONSchema {
|
||||
Rename<"$schema", Literal<"https://json-schema.org/draft/2020-12/schema">>
|
||||
schema;
|
||||
Flatten<T> root;
|
||||
std::map<std::string, Type> definitions;
|
||||
};
|
||||
|
||||
} // namespace rfl::json::schema
|
||||
} // namespace rfl::json::schema
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,136 +12,151 @@
|
|||
|
||||
namespace rfl::json::schema {
|
||||
|
||||
/// The JSON representation of internal::schema::Type.
|
||||
struct Type {
|
||||
struct Boolean {
|
||||
std::optional<std::string> description;
|
||||
Literal<"boolean"> type;
|
||||
/// The JSON representation of internal::schema::Type.
|
||||
struct Type {
|
||||
struct Boolean {
|
||||
std::optional<std::string> description;
|
||||
Literal<"boolean"> type;
|
||||
};
|
||||
|
||||
struct Integer {
|
||||
Literal<"integer"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct Number {
|
||||
Literal<"number"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct String {
|
||||
Literal<"string"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
using NumericType = std::variant<Integer, Number>;
|
||||
|
||||
struct AllOf {
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> allOf;
|
||||
};
|
||||
|
||||
struct AnyOf {
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> anyOf;
|
||||
};
|
||||
|
||||
struct ExclusiveMaximum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> exclusiveMaximum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct ExclusiveMinimum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> exclusiveMinimum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct FixedSizeTypedArray {
|
||||
Literal<"array"> type;
|
||||
std::optional<std::string> description;
|
||||
rfl::Ref<Type> items;
|
||||
size_t minContains;
|
||||
size_t maxContains;
|
||||
};
|
||||
|
||||
struct Maximum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> maximum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct Minimum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> minimum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct Null {
|
||||
Literal<"null"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct Object {
|
||||
Literal<"object"> type;
|
||||
std::optional<std::string> description;
|
||||
std::map<std::string, Type> properties;
|
||||
std::vector<std::string> required;
|
||||
};
|
||||
|
||||
struct OneOf {
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> oneOf;
|
||||
};
|
||||
|
||||
struct Reference {
|
||||
Rename<"$ref", std::optional<std::string>> ref;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct Regex {
|
||||
Literal<"string"> type;
|
||||
std::optional<std::string> description;
|
||||
std::string pattern;
|
||||
};
|
||||
|
||||
struct StringEnum {
|
||||
Literal<"string"> type;
|
||||
std::optional<std::string> description;
|
||||
rfl::Rename<"enum", std::vector<std::string>> values;
|
||||
};
|
||||
|
||||
struct StringMap {
|
||||
Literal<"object"> type;
|
||||
std::optional<std::string> description;
|
||||
rfl::Ref<Type> additionalProperties;
|
||||
};
|
||||
|
||||
struct Tuple {
|
||||
Literal<"array"> type;
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> prefixItems;
|
||||
bool items = false;
|
||||
};
|
||||
|
||||
struct TypedArray {
|
||||
Literal<"array"> type;
|
||||
std::optional<std::string> description;
|
||||
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>;
|
||||
|
||||
const auto& reflection() const { return value; }
|
||||
|
||||
ReflectionType value;
|
||||
};
|
||||
|
||||
struct Integer {
|
||||
Literal<"integer"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct Number {
|
||||
Literal<"number"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct String {
|
||||
Literal<"string"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
using NumericType = std::variant<Integer, Number>;
|
||||
|
||||
struct AllOf {
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> allOf;
|
||||
};
|
||||
|
||||
struct AnyOf {
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> anyOf;
|
||||
};
|
||||
|
||||
struct ExclusiveMaximum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> exclusiveMaximum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct ExclusiveMinimum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> exclusiveMinimum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct FixedSizeTypedArray {
|
||||
Literal<"array"> type;
|
||||
std::optional<std::string> description;
|
||||
rfl::Ref<Type> items;
|
||||
size_t minContains;
|
||||
size_t maxContains;
|
||||
};
|
||||
|
||||
struct Maximum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> maximum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct Minimum {
|
||||
std::optional<std::string> description;
|
||||
std::variant<double, int> minimum;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
struct Null {
|
||||
Literal<"null"> type;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct Object {
|
||||
Literal<"object"> type;
|
||||
std::optional<std::string> description;
|
||||
std::map<std::string, Type> properties;
|
||||
std::vector<std::string> required;
|
||||
};
|
||||
|
||||
struct OneOf {
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> oneOf;
|
||||
};
|
||||
|
||||
struct Reference {
|
||||
Rename<"$ref", std::optional<std::string>> ref;
|
||||
std::optional<std::string> description;
|
||||
};
|
||||
|
||||
struct Regex {
|
||||
Literal<"string"> type;
|
||||
std::optional<std::string> description;
|
||||
std::string pattern;
|
||||
};
|
||||
|
||||
struct StringEnum {
|
||||
Literal<"string"> type;
|
||||
std::optional<std::string> description;
|
||||
rfl::Rename<"enum", std::vector<std::string>> values;
|
||||
};
|
||||
|
||||
struct StringMap {
|
||||
Literal<"object"> type;
|
||||
std::optional<std::string> description;
|
||||
rfl::Ref<Type> additionalProperties;
|
||||
};
|
||||
|
||||
struct Tuple {
|
||||
Literal<"array"> type;
|
||||
std::optional<std::string> description;
|
||||
std::vector<Type> prefixItems;
|
||||
bool items = false;
|
||||
};
|
||||
|
||||
struct TypedArray {
|
||||
Literal<"array"> type;
|
||||
std::optional<std::string> description;
|
||||
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>;
|
||||
|
||||
const auto& reflection() const { return value; }
|
||||
|
||||
ReflectionType value;
|
||||
};
|
||||
|
||||
} // namespace rfl::json::schema
|
||||
} // namespace rfl::json::schema
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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"
|
||||
|
@ -21,242 +20,248 @@
|
|||
|
||||
namespace rfl::json {
|
||||
|
||||
inline schema::Type type_to_json_schema_type(
|
||||
const parsing::schema::Type& _type);
|
||||
inline schema::Type type_to_json_schema_type(
|
||||
const parsing::schema::Type& _type);
|
||||
|
||||
inline bool is_optional(const parsing::schema::Type& _t) {
|
||||
const auto handle = [](const auto& _v) -> bool {
|
||||
using T = std::remove_cvref_t<decltype(_v)>;
|
||||
return std::is_same<T, parsing::schema::Type::Optional>();
|
||||
};
|
||||
return std::visit(handle, _t.variant_);
|
||||
}
|
||||
inline bool is_optional(const parsing::schema::Type& _t) {
|
||||
const auto handle = [](const auto& _v) -> bool {
|
||||
using T = std::remove_cvref_t<decltype(_v)>;
|
||||
return std::is_same<T, parsing::schema::Type::Optional>();
|
||||
};
|
||||
return std::visit(handle, _t.variant_);
|
||||
}
|
||||
|
||||
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;
|
||||
if constexpr (std::is_same<T, Type::Int32>() ||
|
||||
std::is_same<T, Type::Int64>() ||
|
||||
std::is_same<T, Type::UInt32>() ||
|
||||
std::is_same<T, Type::UInt64>() ||
|
||||
std::is_same<T, Type::Integer>()) {
|
||||
return schema::Type::Integer{}.type.str();
|
||||
} else {
|
||||
return schema::Type::Number{}.type.str();
|
||||
}
|
||||
};
|
||||
return std::visit(handle_variant, _type.variant_);
|
||||
}
|
||||
|
||||
inline schema::Type handle_validation_type(
|
||||
const parsing::schema::Type& _type,
|
||||
const parsing::schema::ValidationType& _validation_type) {
|
||||
const auto handle_variant = [&](const auto& _v) -> schema::Type {
|
||||
using T = std::remove_cvref_t<decltype(_v)>;
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
if constexpr (std::is_same<T, ValidationType::AllOf>()) {
|
||||
auto all_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _v.types_) {
|
||||
all_of.emplace_back(handle_validation_type(_type, t));
|
||||
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;
|
||||
if constexpr (std::is_same<T, Type::Int32>() ||
|
||||
std::is_same<T, Type::Int64>() ||
|
||||
std::is_same<T, Type::UInt32>() ||
|
||||
std::is_same<T, Type::UInt64>() ||
|
||||
std::is_same<T, Type::Integer>()) {
|
||||
return schema::Type::Integer {}.type.str();
|
||||
} else {
|
||||
return schema::Type::Number {}.type.str();
|
||||
}
|
||||
return schema::Type{.value = schema::Type::AllOf{.allOf = all_of}};
|
||||
};
|
||||
return std::visit(handle_variant, _type.variant_);
|
||||
}
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::AnyOf>()) {
|
||||
auto any_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _v.types_) {
|
||||
any_of.emplace_back(handle_validation_type(_type, t));
|
||||
}
|
||||
return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}};
|
||||
inline schema::Type handle_validation_type(
|
||||
const parsing::schema::Type& _type,
|
||||
const parsing::schema::ValidationType& _validation_type) {
|
||||
const auto handle_variant = [&](const auto& _v) -> schema::Type {
|
||||
using T = std::remove_cvref_t<decltype(_v)>;
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
if constexpr (std::is_same<T, ValidationType::AllOf>()) {
|
||||
auto all_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _v.types_) {
|
||||
all_of.emplace_back(handle_validation_type(_type, t));
|
||||
}
|
||||
return schema::Type {.value = schema::Type::AllOf {.allOf = all_of}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::OneOf>()) {
|
||||
auto one_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _v.types_) {
|
||||
one_of.emplace_back(handle_validation_type(_type, t));
|
||||
}
|
||||
return schema::Type{.value = schema::Type::OneOf{.oneOf = one_of}};
|
||||
} else if constexpr (std::is_same<T, ValidationType::AnyOf>()) {
|
||||
auto any_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _v.types_) {
|
||||
any_of.emplace_back(handle_validation_type(_type, t));
|
||||
}
|
||||
return schema::Type {.value = schema::Type::AnyOf {.anyOf = any_of}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Regex>()) {
|
||||
return schema::Type{.value = schema::Type::Regex{.pattern = _v.pattern_}};
|
||||
} else if constexpr (std::is_same<T, ValidationType::OneOf>()) {
|
||||
auto one_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _v.types_) {
|
||||
one_of.emplace_back(handle_validation_type(_type, t));
|
||||
}
|
||||
return schema::Type {.value = schema::Type::OneOf {.oneOf = one_of}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Size>()) {
|
||||
return type_to_json_schema_type(_type);
|
||||
} else if constexpr (std::is_same<T, ValidationType::Regex>()) {
|
||||
return schema::Type {.value =
|
||||
schema::Type::Regex {.pattern = _v.pattern_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::ExclusiveMaximum>()) {
|
||||
return schema::Type{.value = schema::Type::ExclusiveMaximum{
|
||||
} 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>()) {
|
||||
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>()) {
|
||||
return schema::Type {.value = schema::Type::ExclusiveMinimum {
|
||||
.exclusiveMinimum = _v.value_,
|
||||
.type = numeric_type_to_string(_type)}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Maximum>()) {
|
||||
return schema::Type {
|
||||
.value = schema::Type::Maximum {
|
||||
.maximum = _v.value_, .type = numeric_type_to_string(_type)}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Minimum>()) {
|
||||
return schema::Type {
|
||||
.value = schema::Type::Minimum {
|
||||
.minimum = _v.value_, .type = numeric_type_to_string(_type)}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::EqualTo>()) {
|
||||
const auto maximum = schema::Type {
|
||||
.value = schema::Type::Maximum {
|
||||
.maximum = _v.value_, .type = numeric_type_to_string(_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}}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::NotEqualTo>()) {
|
||||
const auto excl_maximum =
|
||||
schema::Type {.value = schema::Type::ExclusiveMaximum {
|
||||
.exclusiveMaximum = _v.value_,
|
||||
.type = numeric_type_to_string(_type)}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::ExclusiveMinimum>()) {
|
||||
return schema::Type{.value = schema::Type::ExclusiveMinimum{
|
||||
const auto excl_minimum =
|
||||
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}}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Maximum>()) {
|
||||
return schema::Type{
|
||||
.value = schema::Type::Maximum{
|
||||
.maximum = _v.value_, .type = numeric_type_to_string(_type)}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::Minimum>()) {
|
||||
return schema::Type{
|
||||
.value = schema::Type::Minimum{
|
||||
.minimum = _v.value_, .type = numeric_type_to_string(_type)}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::EqualTo>()) {
|
||||
const auto maximum = schema::Type{
|
||||
.value = schema::Type::Maximum{
|
||||
.maximum = _v.value_, .type = numeric_type_to_string(_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}}};
|
||||
|
||||
} else if constexpr (std::is_same<T, ValidationType::NotEqualTo>()) {
|
||||
const auto excl_maximum =
|
||||
schema::Type{.value = schema::Type::ExclusiveMaximum{
|
||||
.exclusiveMaximum = _v.value_,
|
||||
.type = numeric_type_to_string(_type)}};
|
||||
const auto excl_minimum =
|
||||
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}}};
|
||||
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
|
||||
}
|
||||
};
|
||||
|
||||
return std::visit(handle_variant, _validation_type.variant_);
|
||||
}
|
||||
|
||||
inline schema::Type type_to_json_schema_type(
|
||||
const parsing::schema::Type& _type) {
|
||||
const auto handle_variant = [](const auto& _t) -> schema::Type {
|
||||
using T = std::remove_cvref_t<decltype(_t)>;
|
||||
using Type = parsing::schema::Type;
|
||||
if constexpr (std::is_same<T, Type::Boolean>()) {
|
||||
return schema::Type{.value = schema::Type::Boolean{}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Int32>() ||
|
||||
std::is_same<T, Type::Int64>() ||
|
||||
std::is_same<T, Type::UInt32>() ||
|
||||
std::is_same<T, Type::UInt64>() ||
|
||||
std::is_same<T, Type::Integer>()) {
|
||||
return schema::Type{.value = schema::Type::Integer{}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Float>() ||
|
||||
std::is_same<T, Type::Double>()) {
|
||||
return schema::Type{.value = schema::Type::Number{}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::String>()) {
|
||||
return schema::Type{.value = schema::Type::String{}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::AnyOf>()) {
|
||||
auto any_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _t.types_) {
|
||||
any_of.emplace_back(type_to_json_schema_type(t));
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
|
||||
}
|
||||
return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}};
|
||||
};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Description>()) {
|
||||
auto res = type_to_json_schema_type(*_t.type_);
|
||||
const auto update_prediction = [&](auto _v) -> schema::Type {
|
||||
_v.description = _t.description_;
|
||||
return schema::Type{_v};
|
||||
};
|
||||
return std::visit(update_prediction, res.value);
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::FixedSizeTypedArray>()) {
|
||||
return schema::Type{.value = schema::Type::FixedSizeTypedArray{
|
||||
.items = Ref<schema::Type>::make(
|
||||
type_to_json_schema_type(*_t.type_)),
|
||||
.minContains = _t.size_,
|
||||
.maxContains = _t.size_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Literal>()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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{
|
||||
.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_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::StringMap>()) {
|
||||
return schema::Type{.value = schema::Type::StringMap{
|
||||
.additionalProperties = Ref<schema::Type>::make(
|
||||
type_to_json_schema_type(*_t.value_type_))}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Tuple>()) {
|
||||
auto items = std::vector<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}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::TypedArray>()) {
|
||||
return schema::Type{.value = schema::Type::TypedArray{
|
||||
.items = Ref<schema::Type>::make(
|
||||
type_to_json_schema_type(*_t.type_))}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Validated>()) {
|
||||
return handle_validation_type(*_t.type_, _t.validation_);
|
||||
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
|
||||
}
|
||||
};
|
||||
|
||||
return std::visit(handle_variant, _type.variant_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct TypeHelper {};
|
||||
|
||||
template <class... Ts>
|
||||
struct TypeHelper<std::variant<Ts...>> {
|
||||
using JSONSchemaType = std::variant<schema::JSONSchema<Ts>...>;
|
||||
};
|
||||
|
||||
/// Returns the JSON schema for a class.
|
||||
template <class T, class... Ps>
|
||||
std::string to_schema(const yyjson_write_flag _flag = 0) {
|
||||
const auto internal_schema =
|
||||
parsing::schema::make<Reader, Writer, T, Processors<Ps...>>();
|
||||
auto definitions = std::map<std::string, schema::Type>();
|
||||
for (const auto& [k, v] : internal_schema.definitions_) {
|
||||
definitions[k] = type_to_json_schema_type(v);
|
||||
return std::visit(handle_variant, _validation_type.variant_);
|
||||
}
|
||||
using JSONSchemaType =
|
||||
typename TypeHelper<schema::Type::ReflectionType>::JSONSchemaType;
|
||||
const auto to_schema = [&](auto&& _root) -> JSONSchemaType {
|
||||
using U = std::decay_t<decltype(_root)>;
|
||||
return schema::JSONSchema<U>{.root = std::move(_root),
|
||||
.definitions = definitions};
|
||||
|
||||
inline schema::Type type_to_json_schema_type(
|
||||
const parsing::schema::Type& _type) {
|
||||
const auto handle_variant = [](const auto& _t) -> schema::Type {
|
||||
using T = std::remove_cvref_t<decltype(_t)>;
|
||||
using Type = parsing::schema::Type;
|
||||
if constexpr (std::is_same<T, Type::Boolean>()) {
|
||||
return schema::Type {.value = schema::Type::Boolean {}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Int32>() ||
|
||||
std::is_same<T, Type::Int64>() ||
|
||||
std::is_same<T, Type::UInt32>() ||
|
||||
std::is_same<T, Type::UInt64>() ||
|
||||
std::is_same<T, Type::Integer>()) {
|
||||
return schema::Type {.value = schema::Type::Integer {}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Float>() ||
|
||||
std::is_same<T, Type::Double>()) {
|
||||
return schema::Type {.value = schema::Type::Number {}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::String>()) {
|
||||
return schema::Type {.value = schema::Type::String {}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::AnyOf>()) {
|
||||
auto any_of = std::vector<schema::Type>();
|
||||
for (const auto& t : _t.types_) {
|
||||
any_of.emplace_back(type_to_json_schema_type(t));
|
||||
}
|
||||
return schema::Type {.value = schema::Type::AnyOf {.anyOf = any_of}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Description>()) {
|
||||
auto res = type_to_json_schema_type(*_t.type_);
|
||||
const auto update_prediction = [&](auto _v) -> schema::Type {
|
||||
_v.description = _t.description_;
|
||||
return schema::Type {_v};
|
||||
};
|
||||
return std::visit(update_prediction, res.value);
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::FixedSizeTypedArray>()) {
|
||||
return schema::Type {.value = schema::Type::FixedSizeTypedArray {
|
||||
.items = Ref<schema::Type>::make(
|
||||
type_to_json_schema_type(*_t.type_)),
|
||||
.minContains = _t.size_,
|
||||
.maxContains = _t.size_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Literal>()) {
|
||||
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); }
|
||||
}
|
||||
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 {
|
||||
.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_}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::StringMap>()) {
|
||||
return schema::Type {
|
||||
.value = schema::Type::StringMap {
|
||||
.additionalProperties = Ref<schema::Type>::make(
|
||||
type_to_json_schema_type(*_t.value_type_))}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Tuple>()) {
|
||||
auto items = std::vector<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}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::TypedArray>()) {
|
||||
return schema::Type {.value = schema::Type::TypedArray {
|
||||
.items = Ref<schema::Type>::make(
|
||||
type_to_json_schema_type(*_t.type_))}};
|
||||
|
||||
} else if constexpr (std::is_same<T, Type::Validated>()) {
|
||||
return handle_validation_type(*_t.type_, _t.validation_);
|
||||
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
|
||||
}
|
||||
};
|
||||
|
||||
return std::visit(handle_variant, _type.variant_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct TypeHelper {};
|
||||
|
||||
template <class... Ts>
|
||||
struct TypeHelper<std::variant<Ts...>> {
|
||||
using JSONSchemaType = std::variant<schema::JSONSchema<Ts>...>;
|
||||
};
|
||||
auto root = type_to_json_schema_type(internal_schema.root_);
|
||||
const auto json_schema = std::visit(to_schema, std::move(root.value));
|
||||
return write(json_schema, _flag);
|
||||
}
|
||||
} // namespace rfl::json
|
||||
|
||||
/// Returns the JSON schema for a class.
|
||||
template <class T, class... Ps>
|
||||
std::string to_schema(const yyjson_write_flag _flag = 0) {
|
||||
const auto internal_schema =
|
||||
parsing::schema::make<Reader, Writer, T, Processors<Ps...>>();
|
||||
auto definitions = std::map<std::string, schema::Type>();
|
||||
for (const auto& [k, v] : internal_schema.definitions_) {
|
||||
definitions[k] = type_to_json_schema_type(v);
|
||||
}
|
||||
using JSONSchemaType =
|
||||
typename TypeHelper<schema::Type::ReflectionType>::JSONSchemaType;
|
||||
const auto to_schema = [&](auto&& _root) -> JSONSchemaType {
|
||||
using U = std::decay_t<decltype(_root)>;
|
||||
return schema::JSONSchema<U> {.root = std::move(_root),
|
||||
.definitions = definitions};
|
||||
};
|
||||
auto root = type_to_json_schema_type(internal_schema.root_);
|
||||
const auto json_schema = std::visit(to_schema, std::move(root.value));
|
||||
return write(json_schema, _flag);
|
||||
}
|
||||
} // namespace rfl::json
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,52 +1,54 @@
|
|||
#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"
|
||||
#include "Parser.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace json {
|
||||
namespace json {
|
||||
|
||||
/// Convenient alias for the YYJSON pretty flag
|
||||
inline constexpr yyjson_write_flag pretty = YYJSON_WRITE_PRETTY;
|
||||
/// Convenient alias for the YYJSON pretty flag
|
||||
inline constexpr yyjson_write_flag pretty = YYJSON_WRITE_PRETTY;
|
||||
|
||||
/// Returns a JSON string.
|
||||
template <class... Ps>
|
||||
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{});
|
||||
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);
|
||||
yyjson_mut_doc_free(w.doc_);
|
||||
return json_str;
|
||||
}
|
||||
/// Returns a JSON string.
|
||||
template <class... Ps>
|
||||
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 {});
|
||||
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);
|
||||
yyjson_mut_doc_free(w.doc_);
|
||||
return json_str;
|
||||
}
|
||||
|
||||
/// Writes a JSON into an ostream.
|
||||
template <class... Ps>
|
||||
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{});
|
||||
const char* json_c_str = yyjson_mut_write(w.doc_, _flag, NULL);
|
||||
_stream << json_c_str;
|
||||
free((void*)json_c_str);
|
||||
yyjson_mut_doc_free(w.doc_);
|
||||
return _stream;
|
||||
}
|
||||
/// Writes a JSON into an ostream.
|
||||
template <class... Ps>
|
||||
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 {});
|
||||
const char* json_c_str = yyjson_mut_write(w.doc_, _flag, NULL);
|
||||
_stream << json_c_str;
|
||||
free((void*)json_c_str);
|
||||
yyjson_mut_doc_free(w.doc_);
|
||||
return _stream;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
} // namespace json
|
||||
} // namespace rfl
|
||||
|
||||
#endif // JSON_PARSER_HPP_
|
||||
#endif // JSON_PARSER_HPP_
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue