json_object_binder.hpp 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. //
  2. // json_object_binder.hpp
  3. // json
  4. //
  5. // Created by Sam Jaffe on 4/23/16.
  6. //
  7. #pragma once
  8. #include "json_binder_discard.hpp"
  9. namespace json { namespace binder {
  10. template <typename T>
  11. class object_binder : public binder_impl<T> {
  12. public:
  13. object_binder() {}
  14. virtual binder_impl<T>* clone() const override { return new object_binder(*this); }
  15. template <typename V>
  16. object_binder& operator()(std::string const&k, V T::*ptr, binder_impl<V> const&v) {
  17. return (*this)(k, binder<T>(new forward_binder<T, V>(ptr, binder<V>(v) )));
  18. }
  19. object_binder& operator()(std::string const&k, binder<T> const&v) {
  20. mapping.emplace(k, v);
  21. return *this;
  22. }
  23. virtual void parse(T& object, char const*& data, parser::options opts) const override {
  24. const char ch = json::helper::get_next_element(data);
  25. if (ch == '{') {
  26. parse_object(object, ++data, opts);
  27. } else {
  28. throw json::malformed_json_exception(std::string("Expected an object type for binding to ") + typeid(T).name());
  29. }
  30. }
  31. virtual void write(T const& val, std::ostream & data) const override {
  32. data << '{';
  33. typename std::map<std::string, binder<T>>::const_iterator it = mapping.begin(),
  34. end = mapping.end();
  35. if (it != end) {
  36. data << '"' << it->first << '"' << ':';
  37. it->second.write(val, data);
  38. for (++it; it != end; ++it) {
  39. data << ',';
  40. data << '"' << it->first << '"' << ':';
  41. it->second.write(val, data);
  42. }
  43. }
  44. data << '}';
  45. }
  46. void parse_object(T& object, char const*& data, parser::options opts) const {
  47. std::string key;
  48. std::set<std::string> unparsed_keys;
  49. for ( auto & p : mapping ) { unparsed_keys.insert(p.first); }
  50. while (*data && *data != '}') {
  51. if (json::helper::get_next_element(data) != '"') {
  52. throw json::malformed_json_exception(std::string("Expected object key starting with '\"', got '") + *data + "' instead");
  53. }
  54. json::helper::parse_string(key, data);
  55. if (json::helper::get_next_element(data) != ':') {
  56. throw json::malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead");
  57. }
  58. auto it = mapping.find(key);
  59. if (it != mapping.end()) {
  60. unparsed_keys.erase(key);
  61. it->second.parse(object, ++data, opts);
  62. } else if (opts & parser::disable_unknown_keys) {
  63. throw json::malformed_json_exception("Unexpected key " + key);
  64. } else {
  65. parse_discard_token(++data);
  66. }
  67. json::helper::advance_to_boundary('}', data);
  68. }
  69. if (*data) ++data;
  70. else throw json::unterminated_json_exception("Reached end of parse string without finding object end");
  71. if ( !unparsed_keys.empty() && opts & parser::disable_missing_keys ) {
  72. throw json::malformed_json_exception("missing certain keys from object construction TODO");
  73. }
  74. }
  75. template <typename E>
  76. object_binder& operator()(std::string const& s, E T::*p) {
  77. return operator()(s, binder<T>(new direct_binder<T, E>(p)));
  78. }
  79. private:
  80. std::map<std::string, binder<T>> mapping;
  81. };
  82. } }