|
|
@@ -10,6 +10,12 @@
|
|
|
#define json_binder_h
|
|
|
#pragma once
|
|
|
|
|
|
+#include "json_common.h"
|
|
|
+
|
|
|
+#include <map>
|
|
|
+#include <string>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
namespace json {
|
|
|
namespace binder {
|
|
|
template <typename T>
|
|
|
@@ -18,6 +24,7 @@ namespace json {
|
|
|
virtual binder_impl<T>* clone() const = 0;
|
|
|
virtual ~binder_impl() {}
|
|
|
virtual void parse(T&, char const*&) const = 0;
|
|
|
+ virtual void write(T const&, std::string &) const = 0;
|
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
|
@@ -33,6 +40,11 @@ namespace json {
|
|
|
if (!impl) return;
|
|
|
impl->parse(object, data);
|
|
|
}
|
|
|
+
|
|
|
+ void write(T const& object, std::string & data) const {
|
|
|
+ if (!impl) return;
|
|
|
+ impl->write(object, data);
|
|
|
+ }
|
|
|
private:
|
|
|
binder_impl<T> const* impl;
|
|
|
bool owned;
|
|
|
@@ -47,6 +59,10 @@ namespace json {
|
|
|
virtual void parse(T& val, char const*& data) const override {
|
|
|
impl.parse(val.*ptr, data);
|
|
|
}
|
|
|
+
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ impl.write(val.*ptr, data);
|
|
|
+ }
|
|
|
private:
|
|
|
E T::*ptr;
|
|
|
binder<E> impl;
|
|
|
@@ -58,7 +74,7 @@ namespace json {
|
|
|
direct_binder(bool T::*p) : ptr(p) {}
|
|
|
virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
|
|
|
- virtual void parse(T& val, char const*& data) override {
|
|
|
+ virtual void parse(T& val, char const*& data) const override {
|
|
|
if (!strncmp(data, "true", 4)) {
|
|
|
val.*ptr = true;
|
|
|
} else if (!strncmp(data, "false", 5)) {
|
|
|
@@ -68,6 +84,10 @@ namespace json {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ data += (val.*ptr ? "true" : "false");
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
bool T::*ptr;
|
|
|
};
|
|
|
@@ -85,6 +105,12 @@ namespace json {
|
|
|
// throw json::malformed_json_exception("Expected an integral type here");
|
|
|
// }
|
|
|
}
|
|
|
+
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ char buffer[16] = { '\0' };
|
|
|
+ snprintf(buffer, sizeof(buffer), "%d", val.*ptr);
|
|
|
+ data += buffer;
|
|
|
+ }
|
|
|
private:
|
|
|
int T::*ptr;
|
|
|
};
|
|
|
@@ -102,6 +128,12 @@ namespace json {
|
|
|
// throw json::malformed_json_exception("Expected a floating point type here");
|
|
|
// }
|
|
|
}
|
|
|
+
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ char buffer[32] = { '\0' };
|
|
|
+ snprintf(buffer, sizeof(buffer), "%lf", val.*ptr);
|
|
|
+ data += buffer;
|
|
|
+ }
|
|
|
private:
|
|
|
double T::*ptr;
|
|
|
};
|
|
|
@@ -115,6 +147,10 @@ namespace json {
|
|
|
virtual void parse(T& val, char const*& data) const override {
|
|
|
json::helper::parse_string(val.*ptr, data);
|
|
|
}
|
|
|
+
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ data += "\"" + val.*ptr + "\"";
|
|
|
+ }
|
|
|
private:
|
|
|
std::string T::*ptr;
|
|
|
};
|
|
|
@@ -142,6 +178,17 @@ namespace json {
|
|
|
if (*data) ++data;
|
|
|
else throw json::malformed_json_exception("Reached end of parse string without finding array end");
|
|
|
}
|
|
|
+
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ data += "[";
|
|
|
+ std::vector<V> const & vec = val.*ptr;
|
|
|
+ for (typename std::vector<V>::const_iterator it = vec.begin(),
|
|
|
+ end = vec.end(); it != end; ++it) {
|
|
|
+ impl.write(*it, data);
|
|
|
+ data += ",";
|
|
|
+ }
|
|
|
+ data.back() = ']';
|
|
|
+ }
|
|
|
private:
|
|
|
std::vector<V> T::*ptr;
|
|
|
binder<V> impl;
|
|
|
@@ -175,6 +222,18 @@ namespace json {
|
|
|
if (*data) ++data;
|
|
|
else throw json::malformed_json_exception("Reached end of parse string without finding object end");
|
|
|
}
|
|
|
+
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ data += "{";
|
|
|
+ std::map<std::string, V> const & map = val.*ptr;
|
|
|
+ for (typename std::map<std::string, V>::const_iterator it = map.begin(),
|
|
|
+ end = map.end(); it != end; ++it) {
|
|
|
+ data += "\"" + it->first + "\":";
|
|
|
+ impl.write(it->second, data);
|
|
|
+ data += ",";
|
|
|
+ }
|
|
|
+ data.back() = '}';
|
|
|
+ }
|
|
|
private:
|
|
|
std::map<std::string, V> T::*ptr;
|
|
|
binder<V> impl;
|
|
|
@@ -205,6 +264,17 @@ namespace json {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ data += "{";
|
|
|
+ for (typename std::map<std::string, binder<T>>::const_iterator it = mapping.begin(),
|
|
|
+ end = mapping.end(); it != end; ++it) {
|
|
|
+ data += "\"" + it->first + "\":";
|
|
|
+ it->second.write(val, data);
|
|
|
+ data += ",";
|
|
|
+ }
|
|
|
+ data.back() = '}';
|
|
|
+ }
|
|
|
+
|
|
|
void parse_object(T& object, char const*& data) const {
|
|
|
std::string key;
|
|
|
while (*data && *data != '}') {
|
|
|
@@ -251,6 +321,16 @@ namespace json {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ virtual void write(T const& val, std::string & data) const override {
|
|
|
+ data += "[";
|
|
|
+ for (typename std::vector<binder<T>>::const_iterator it = members.begin(),
|
|
|
+ end = members.end(); it != end; ++it) {
|
|
|
+ it->write(val, data);
|
|
|
+ data += ",";
|
|
|
+ }
|
|
|
+ data.back() = ']';
|
|
|
+ }
|
|
|
+
|
|
|
void parse_tuple(T& object, char const*& data) const {
|
|
|
auto it = members.begin();
|
|
|
while (*data && *data != ']' && it != members.end()) {
|
|
|
@@ -274,17 +354,21 @@ namespace json {
|
|
|
std::vector<binder<T>> members;
|
|
|
};
|
|
|
|
|
|
- template <typename T>
|
|
|
+ template <typename T, typename S = T>
|
|
|
class visitor {
|
|
|
public:
|
|
|
- visitor(T& o, binder_impl<T>& b) : obj(o), b(b) {}
|
|
|
+ visitor(S& o, binder_impl<T>& b) : obj(o), b(b) {}
|
|
|
|
|
|
void parse(char const* data) {
|
|
|
b.parse(obj, data);
|
|
|
}
|
|
|
|
|
|
+ void write(std::string & data) const {
|
|
|
+ b.write(obj, data);
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
- T& obj;
|
|
|
+ S& obj;
|
|
|
binder_impl<T>& b;
|
|
|
};
|
|
|
|
|
|
@@ -298,7 +382,12 @@ namespace json {
|
|
|
template <typename T>
|
|
|
void parse(binder::visitor<T>& visitor, char const* data) {
|
|
|
visitor.parse(data);
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename T, typename S>
|
|
|
+ void write(binder::visitor<T, S> const & visitor, std::string & data) {
|
|
|
+ visitor.write(data);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|