// // json_object_binder.hpp // json // // Created by Sam Jaffe on 4/23/16. // #pragma once #include "json_binder_discard.hpp" namespace json { namespace binder { 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, parser::options opts) const override { const char ch = json::helper::get_next_element(data); if (ch == '{') { parse_object(object, ++data, opts); } else { throw json::malformed_json_exception(std::string("Expected an object type for binding to ") + typeid(T).name()); } } virtual void write(T const& val, std::ostream & data) const override { data << '{'; typename std::map>::const_iterator it = mapping.begin(), end = mapping.end(); if (it != end) { data << '"' << it->first << '"' << ':'; it->second.write(val, data); for (++it; it != end; ++it) { data << ','; data << '"' << it->first << '"' << ':'; it->second.write(val, data); } } data << '}'; } void parse_object(T& object, char const*& data, parser::options opts) const { std::string key; while (*data && *data != '}') { if (json::helper::get_next_element(data) != '"') { throw json::malformed_json_exception(std::string("Expected object key starting with '\"', got '") + *data + "' instead"); } 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, opts); } else if (opts & parser::disable_unknown_keys) { throw json::malformed_json_exception("Unexpected key " + key); } else { parse_discard_token(++data); } json::helper::advance_to_boundary('}', data); } if (*data) ++data; else throw json::unterminated_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; }; } }