#ifndef REFLECTIVE_RAPIDJSON_JSON_ERROR_HANDLING_H #define REFLECTIVE_RAPIDJSON_JSON_ERROR_HANDLING_H /*! * \file errorhandling.h * \brief Contains helper for error handling when deserializing JSON files. */ #include #include #include #include #include #include namespace ReflectiveRapidJSON { /*! * \brief The JsonDeserializationErrorKind enum specifies which kind of error happend when populating variables from parsing results. */ enum class JsonDeserializationErrorKind : byte { TypeMismatch, }; /*! * \brief The JsonType enum specifies the JSON data type. * \remarks This is currently only used for error handling to propagate expected and actual types in case of a mismatch. */ enum class JsonType : byte { Null, Number, Bool, String, Array, Object, }; template >, Traits::Any, std::is_floating_point>>...> constexpr JsonType jsonType() { return JsonType::Number; } template >...> constexpr JsonType jsonType() { return JsonType::Bool; } template , Traits::IsCString>...> constexpr JsonType jsonType() { return JsonType::String; } template , Traits::Not>>...> constexpr JsonType jsonType() { return JsonType::Array; } template , std::is_floating_point, Traits::IsString, Traits::IsCString, Traits::IsIteratable>...> constexpr JsonType jsonType() { return JsonType::Object; } /*! * \brief Maps the type info provided by RapidJSON to JsonType. */ constexpr JsonType jsonType(RAPIDJSON_NAMESPACE::Type type) { switch (type) { case RAPIDJSON_NAMESPACE::kNullType: return JsonType::Null; case RAPIDJSON_NAMESPACE::kFalseType: case RAPIDJSON_NAMESPACE::kTrueType: return JsonType::Bool; case RAPIDJSON_NAMESPACE::kObjectType: return JsonType::Object; case RAPIDJSON_NAMESPACE::kArrayType: return JsonType::Array; case RAPIDJSON_NAMESPACE::kStringType: return JsonType::String; case RAPIDJSON_NAMESPACE::kNumberType: return JsonType::Number; default: return JsonType::Null; } } /*! * \brief The JsonDeserializationError struct describes any errors of fromJson() except such caused by invalid JSON. */ struct JsonDeserializationError { JsonDeserializationError(JsonDeserializationErrorKind kind, JsonType expectedType, JsonType actualType, const char *record, const char *member = nullptr, std::size_t index = noIndex); /// \brief Which kind of error occured. JsonDeserializationErrorKind kind; /// \brief The expected type (might not be relevant for all error kinds). JsonType expectedType; /// \brief The actual type (might not be relevant for all error kinds). JsonType actualType; /// \brief The name of the class or struct which was being processed when the error was ascertained. const char *record; /// \brief The name of the member which was being processed when the error was ascertained. const char *member; /// \brief The index in the array which was being processed when the error was ascertained. std::size_t index; /// \brief Indicates no array was being processed when the error occured. static constexpr std::size_t noIndex = std::numeric_limits::max(); }; /*! * \brief Constructs a new JsonDeserializationError. * \remarks Supposed to be called by JsonDeserializationErrors::reportTypeMismatch() and similar methods of JsonDeserializationErrors. */ inline JsonDeserializationError::JsonDeserializationError( JsonDeserializationErrorKind kind, JsonType expectedType, JsonType actualType, const char *record, const char *member, std::size_t index) : kind(kind) , expectedType(expectedType) , actualType(actualType) , record(record) , member(member) , index(index) { } /*! * \brief The JsonDeserializationErrors struct can be passed to fromJson() for error handling. * * When passed to fromJson() and an error occurs, a JsonDeserializationError is added to this object. * If throwOn is set, the JsonDeserializationError is additionally thrown making the error fatal. * * \remarks Errors due to invalid JSON always lead to a RAPIDJSON_NAMESPACE::ParseResult object being thrown. So this * only concerns errors listed in JsonDeserializationErrorKind. */ struct JsonDeserializationErrors : public std::vector { JsonDeserializationErrors(); template void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType); /// \brief The name of the class or struct which is currently being processed. const char *currentRecord; /// \brief The name of the member (in currentRecord) which is currently being processed. const char *currentMember; /// \brief The index in the array which is currently processed. std::size_t currentIndex; /// \brief The list of fatal error types in form of flags. enum class ThrowOn : unsigned char { None = 0, TypeMismatch = 0x1 } throwOn; }; /*! * \brief Creates an empty JsonDeserializationErrors object with default context and no errors considered fatal. */ inline JsonDeserializationErrors::JsonDeserializationErrors() : currentRecord("[document]") , currentMember(nullptr) , currentIndex(JsonDeserializationError::noIndex) , throwOn(ThrowOn::None) { } /*! * \brief Combines to ThrowOn values. */ constexpr JsonDeserializationErrors::ThrowOn operator|(JsonDeserializationErrors::ThrowOn lhs, JsonDeserializationErrors::ThrowOn rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } /*! * \brief Reports a type missmatch between \tparam ExpectedType and \a presentType within the current context. */ template inline void JsonDeserializationErrors::reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType) { emplace_back( JsonDeserializationErrorKind::TypeMismatch, jsonType(), jsonType(presentType), currentRecord, currentMember, currentIndex); if (static_cast(throwOn) & static_cast(ThrowOn::TypeMismatch)) { throw back(); } } } // namespace ReflectiveRapidJSON #endif // REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H