// // json_object_binder.hpp // json // // Created by Sam Jaffe on 4/23/16. // #pragma once #include "json_binder.hpp" #include "json_binder_discard.hpp" #include "json_direct_binder.hpp" #include #include #include 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 forward_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 not_an_object_exception(object); } } virtual void write(T const & val, std::ostream & data) const override { data << '{'; auto 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; std::set unparsed_keys; for (auto & p : mapping) { unparsed_keys.insert(p.first); } while (*data && *data != '}') { if (json::helper::get_next_element(data) != '"') { throw malformed_object_key(*data); } json::helper::parse_string(key, data); if (json::helper::get_next_element(data) != ':') { throw malformed_object_association(*data); } auto it = mapping.find(key); if (it != mapping.end()) { unparsed_keys.erase(key); 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 unterminated_json_object(); if (!unparsed_keys.empty() && opts & parser::disable_missing_keys) { throw json::malformed_json_exception{ "missing certain keys from object construction TODO"}; } } template object_binder & operator()(std::string const & s, E T::*p) { return operator()(s, binder(new direct_binder(p))); } private: std::map> mapping; }; }}