| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- //
- // 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 <map>
- #include <set>
- #include <string>
- 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 forward_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 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<std::string> 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 <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;
- };
- }}
|