| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- //
- // 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 <typename T>
- class object_binder : public binder_impl<T> {
- public:
- object_binder() {}
- virtual binder_impl<T>* clone() const override { return new object_binder(*this); }
-
- template <typename V>
- object_binder& operator()(std::string const&k, V T::*ptr, binder_impl<V> const&v) {
- return (*this)(k, binder<T>(new direct_binder<T, V>(ptr, binder<V>(v) )));
- }
- object_binder& operator()(std::string const&k, binder<T> 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<std::string, binder<T>>::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;
- std::set<std::string> unparsed_keys;
- for ( auto & p : mapping ) { unparsed_keys.insert(p.first); }
- 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()) {
- 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 json::unterminated_json_exception("Reached end of parse string without finding object end");
- if ( !unparsed_keys.empty() && opts & parser::disable_missing_keys ) {
- throw json::malformed_json_exception("missing certain keys from object construction TODO");
- }
- }
-
- template <typename E>
- object_binder& operator()(std::string const& s, E T::*p) {
- return operator()(s, binder<T>(new direct_binder<T, E>(p)));
- }
- private:
- std::map<std::string, binder<T>> mapping;
- };
- } }
|