#ifndef REFLECTIVE_RAPIDJSON_REFLECT_H #define REFLECTIVE_RAPIDJSON_REFLECT_H #include #include #include #include #include #include #include #include #include namespace ReflectiveRapidJSON { enum class ErrorFlags : unsigned char { TypeMismatch, MemberMissing }; constexpr ErrorFlags operator&(ErrorFlags lhs, ErrorFlags rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } constexpr ErrorFlags operator|(ErrorFlags lhs, ErrorFlags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } template struct Reflectable; inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::Document &document) { RAPIDJSON_NAMESPACE::StringBuffer buffer; RAPIDJSON_NAMESPACE::Writer writer(buffer); document.Accept(writer); return buffer; } namespace Reflector { // define functions to "push" values to a RapidJSON array or object template , std::is_floating_point, std::is_pointer, Traits::All, Traits::Not>>>...> void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); template , std::is_floating_point, std::is_pointer, Traits::All, Traits::Not>>>...> void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); template , std::is_floating_point, std::is_pointer>...> inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.PushBack(reflectable, allocator); } template <> inline void push( const char *reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); } template <> inline void push( const std::string &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator); } template <> inline void push( const char *const &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); } template , Traits::Not>>...> void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { RAPIDJSON_NAMESPACE::Value arrayValue(RAPIDJSON_NAMESPACE::kArrayType); RAPIDJSON_NAMESPACE::Value::Array array(arrayValue.GetArray()); array.Reserve(reflectable.size(), allocator); for (const auto &item : reflectable) { push(item, array, allocator); } value.PushBack(array, allocator); } template , std::is_floating_point, std::is_pointer, Traits::All, Traits::Not>>>...> inline void push( const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType); RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject()); push(reflectable, object, allocator); value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), object, allocator); } template , std::is_floating_point, std::is_pointer>...> inline void push( Type reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), reflectable, allocator); } template <> inline void push(const std::string &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator); } template <> inline void push( const char *reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); } template <> inline void push(const char *const &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); } template , Traits::Not>>...> void push( const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { RAPIDJSON_NAMESPACE::Value arrayValue(RAPIDJSON_NAMESPACE::kArrayType); RAPIDJSON_NAMESPACE::Value::Array array(arrayValue.GetArray()); array.Reserve(reflectable.size(), allocator); for (const auto &item : reflectable) { push(item, array, allocator); } value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), array, allocator); } template , std::is_floating_point, std::is_pointer, Traits::All, Traits::Not>>>...> void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType); RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject()); push(reflectable, object, allocator); value.PushBack(objectValue, allocator); } // define functions to "pull" values from a RapidJSON array or object template , std::is_floating_point, std::is_pointer, Traits::All, Traits::Not>>>...> void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue>::ValueIterator &value); template , std::is_floating_point, std::is_pointer, Traits::All, Traits::Not>>>...> void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue>::ConstObject &value); template , std::is_floating_point, std::is_pointer, Traits::All, Traits::Not>>>...> void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value) { pull(reflectable, value.GetObject()); } template , std::is_floating_point, std::is_pointer>...> inline void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue>::ValueIterator &value) { reflectable = value->Get(); ++value; } template , std::is_floating_point, std::is_pointer>...> inline void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value) { reflectable = value.Get(); } template <> inline void pull(std::string &reflectable, RAPIDJSON_NAMESPACE::GenericValue>::ValueIterator &value) { reflectable = value->GetString(); ++value; } template <> inline void pull(std::string &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value) { reflectable = value.GetString(); } template , Traits::Not>>...> void pull(Type &reflectable, rapidjson::GenericValue>::ValueIterator &value) { for (const auto &item : value->GetArray()) { reflectable.emplace_back(); pull(reflectable.back(), item); } ++value; } template , Traits::Not>>...> void pull(Type &reflectable, const rapidjson::GenericValue> &value) { for (const auto &item : value.GetArray()) { reflectable.emplace_back(); pull(reflectable.back(), item); } } template inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue>::ConstObject &value) { pull(reflectable, value.FindMember(name)->value); } // define functions providing high-level JSON serialization template , Type>>...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); RAPIDJSON_NAMESPACE::Document::Object object(document.GetObject()); push(reflectable, object, document.GetAllocator()); return documentToString(document); } template , std::is_floating_point>...> RAPIDJSON_NAMESPACE::StringBuffer toJson(Type reflectable) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kNumberType); document.Set(reflectable, document.GetAllocator()); return documentToString(document); } template >...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const std::string &reflectable) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType); document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator()); return documentToString(document); } template >...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const char *reflectable) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType); document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator()); return documentToString(document); } // define functions providing high-level JSON deserialization template , Type>>...> Type fromJson(const char *json, std::size_t jsonSize) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); document.Parse(json, jsonSize); Type res; pull(res, document.GetObject()); return res; } template , std::is_floating_point>...> Type fromJson(const char *json, std::size_t jsonSize) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); document.Parse(json, jsonSize); return document.Get(); } template >...> Type fromJson(const char *json, std::size_t jsonSize) { RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); document.Parse(json, jsonSize); return document.GetString(); } template Type fromJson(const std::string &json) { return fromJson(json.data(), json.size()); } } // namespace Reflector } // namespace ReflectiveRapidJSON #define REFLECT(Type) \ namespace Reflector { \ template <> \ void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); \ template <> \ void add( \ const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); \ template <> std::string toJson(const Type &reflectable); \ template <> Type fromJson(const char *json, std::size_t jsonSize); \ template <> Type fromJson(const std::string &json); \ } #endif // REFLECTIVE_RAPIDJSON_REFLECT_H