// // json_binder.h // json // // Created by Sam Jaffe on 1/31/16. // Copyright © 2016 Sam Jaffe. All rights reserved. // #ifndef json_binder_h #define json_binder_h #pragma once namespace json { namespace binder { template class binder_impl { public: virtual binder_impl* clone() const = 0; virtual ~binder_impl() {} virtual void parse(T&, char const*&) const = 0; }; template class binder { public: binder() : impl(nullptr), owned(false) {} binder(binder const& other) : impl(other.impl->clone()), owned(true) {} binder(binder_impl const* p) : impl(p), owned(true) {} binder(binder_impl const& r) : impl(&r), owned(false) {} ~binder() { if (impl && owned) delete impl; } void parse(T& object, char const*& data) const { if (!impl) return; impl->parse(object, data); } private: binder_impl const* impl; bool owned; }; template class direct_binder : public binder_impl { public: direct_binder(E T::*p, binder const& i) : ptr(p), impl(i) {} virtual binder_impl* clone() const override { return new direct_binder(*this); } virtual void parse(T& val, char const*& data) const override { impl.parse(val.*ptr, data); } private: E T::*ptr; binder impl; }; template class direct_binder : public binder_impl { public: direct_binder(bool T::*p) : ptr(p) {} virtual binder_impl* clone() const override { return new direct_binder(*this); } virtual void parse(T& val, char const*& data) override { if (!strncmp(data, "true", 4)) { val.*ptr = true; } else if (!strncmp(data, "false", 5)) { val.*ptr = false; } else { throw json::malformed_json_exception("Expected a boolean type here"); } } private: bool T::*ptr; }; template class direct_binder : public binder_impl { public: direct_binder(int T::*p) : ptr(p) {} virtual binder_impl* clone() const override { return new direct_binder(*this); } virtual void parse(T& val, char const*& data) const override { // if (false) { json::helper::parse_numeric(val.*ptr, data); // } else { // throw json::malformed_json_exception("Expected an integral type here"); // } } private: int T::*ptr; }; template class direct_binder : public binder_impl { public: direct_binder(double T::*p) : ptr(p) {} virtual binder_impl* clone() const override { return new direct_binder(*this); } virtual void parse(T& val, char const*& data) const override { // if (false) { json::helper::parse_numeric(val.*ptr, data); // } else { // throw json::malformed_json_exception("Expected a floating point type here"); // } } private: double T::*ptr; }; template class direct_binder : public binder_impl { public: direct_binder(std::string T::*p) : ptr(p) {} virtual binder_impl* clone() const override { return new direct_binder(*this); } virtual void parse(T& val, char const*& data) const override { json::helper::parse_string(val.*ptr, data); } private: std::string T::*ptr; }; template class direct_binder > : public binder_impl { public: direct_binder(std::vector T::*p, binder const&i); virtual binder_impl* clone() const override { return new direct_binder(*this); } virtual void parse(T& val, char const*& data) const override { const char ch = json::helper::get_next_element(data); if (ch != '[') { throw json::malformed_json_exception("Expected an array type"); } ++data; V to_make; std::vector& vec = val.*ptr; while (*data && *data != ']') { impl.parse(to_make, data); vec.emplace_back(to_make); json::helper::advance_to_boundary<']'>(data); } if (*data) ++data; else throw json::malformed_json_exception("Reached end of parse string without finding array end"); } private: std::vector T::*ptr; binder impl; }; template class direct_binder > : public binder_impl { public: direct_binder(std::vector T::*p, binder const&i); virtual binder_impl* clone() const override { return new direct_binder(*this); } virtual void parse(T& val, char const*& data) const override { const char ch = json::helper::get_next_element(data); if (ch != '{') { throw json::malformed_json_exception("Expected an array type"); } ++data; V to_make; std::map& vec = val.*ptr; std::string key; while (*data && *data != '}') { json::helper::parse_string(key, data); if (json::helper::get_next_element(data) != ':') { throw json::malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead"); } impl.parse(to_make, ++data); vec.emplace(key, to_make); json::helper::advance_to_boundary<'}'>(data); } if (*data) ++data; else throw json::malformed_json_exception("Reached end of parse string without finding object end"); } private: std::map T::*ptr; binder impl; }; template class object_binder : public binder_impl { public: object_binder() {} virtual binder_impl* clone() const override { return new object_binder(*this); } template object_binder& operator()(std::string const&k, V T::*ptr, binder_impl const&v) { return (*this)(k, binder(new direct_binder(ptr, binder(v) ))); } object_binder& operator()(std::string const&k, binder const&v) { mapping.emplace(k, v); return *this; } virtual void parse(T& object, char const*& data) const override { const char ch = json::helper::get_next_element(data); if (ch == '{') { parse_object(object, ++data); } else { throw json::malformed_json_exception(std::string("Expected an object type for binding to ") + typeid(T).name()); } } void parse_object(T& object, char const*& data) const { std::string key; while (*data && *data != '}') { json::helper::parse_string(key, data); if (json::helper::get_next_element(data) != ':') { throw json::malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead"); } auto it = mapping.find(key); if (it != mapping.end()) { it->second.parse(object, ++data); } else { throw json::malformed_json_exception("Unexpected key " + key); } json::helper::advance_to_boundary<'}'>(data); } if (*data) ++data; else throw json::malformed_json_exception("Reached end of parse string without finding object end"); } template object_binder& operator()(std::string const& s, E T::*p) { return operator()(s, binder(new direct_binder(p))); } private: std::map> mapping; }; template class tuple_binder : public binder_impl { public: virtual binder_impl* clone() const override { return new tuple_binder(*this); } tuple_binder& operator()(binder const&b) { members.push_back(b); return *this; } virtual void parse(T& object, char const*& data) const override { const char ch = json::helper::get_next_element(data); if (ch == '[') { parse_tuple(object, ++data); } else { throw json::malformed_json_exception(std::string("Expected an object type for binding to ") + typeid(T).name()); } } void parse_tuple(T& object, char const*& data) const { auto it = members.begin(); while (*data && *data != ']' && it != members.end()) { it->parse(object, data); json::helper::advance_to_boundary<']'>(data); ++it; } if (it != members.end()) { throw json::malformed_json_exception("Failed to parse every member of tuple"); } if (*data) ++data; else throw json::malformed_json_exception("Reached end of parse string without finding array end"); } template tuple_binder& operator()(E T::*p) { return operator()(binder(new direct_binder(p))); } private: std::vector> members; }; template class visitor { public: visitor(T& o, binder_impl& b) : obj(o), b(b) {} void parse(char const* data) { b.parse(obj, data); } private: T& obj; binder_impl& b; }; template visitor bind(T& object, binder_impl& b) { return visitor{object, b}; } } namespace parser { template void parse(binder::visitor& visitor, char const* data) { visitor.parse(data); } } } #endif /* json_binder_h */