#pragma once #include <iostream> #include <vector> #include <cassert> namespace nix { void toJSON(std::ostream & str, const char * start, const char * end); void toJSON(std::ostream & str, const std::string & s); void toJSON(std::ostream & str, const char * s); void toJSON(std::ostream & str, unsigned long long n); void toJSON(std::ostream & str, unsigned long n); void toJSON(std::ostream & str, long n); void toJSON(std::ostream & str, unsigned int n); void toJSON(std::ostream & str, int n); void toJSON(std::ostream & str, double f); void toJSON(std::ostream & str, bool b); class JSONWriter { protected: struct JSONState { std::ostream & str; bool indent; size_t depth = 0; std::vector<JSONWriter *> stack; JSONState(std::ostream & str, bool indent) : str(str), indent(indent) { } ~JSONState() { assert(stack.empty()); } }; JSONState * state; bool first = true; JSONWriter(std::ostream & str, bool indent); JSONWriter(JSONState * state); ~JSONWriter(); void assertActive() { assert(!state->stack.empty() && state->stack.back() == this); } void comma(); void indent(); }; class JSONObject; class JSONPlaceholder; class JSONList : JSONWriter { private: friend class JSONObject; friend class JSONPlaceholder; void open(); JSONList(JSONState * state) : JSONWriter(state) { open(); } public: JSONList(std::ostream & str, bool indent = false) : JSONWriter(str, indent) { open(); } ~JSONList(); template<typename T> JSONList & elem(const T & v) { comma(); toJSON(state->str, v); return *this; } JSONList list(); JSONObject object(); JSONPlaceholder placeholder(); }; class JSONObject : JSONWriter { private: friend class JSONList; friend class JSONPlaceholder; void open(); JSONObject(JSONState * state) : JSONWriter(state) { open(); } void attr(const std::string & s); public: JSONObject(std::ostream & str, bool indent = false) : JSONWriter(str, indent) { open(); } ~JSONObject(); template<typename T> JSONObject & attr(const std::string & name, const T & v) { attr(name); toJSON(state->str, v); return *this; } JSONList list(const std::string & name); JSONObject object(const std::string & name); JSONPlaceholder placeholder(const std::string & name); }; class JSONPlaceholder : JSONWriter { private: friend class JSONList; friend class JSONObject; JSONPlaceholder(JSONState * state) : JSONWriter(state) { } void assertValid() { assertActive(); assert(first); } public: JSONPlaceholder(std::ostream & str, bool indent = false) : JSONWriter(str, indent) { } ~JSONPlaceholder() { assert(!first || std::uncaught_exception()); } template<typename T> void write(const T & v) { assertValid(); first = false; toJSON(state->str, v); } JSONList list(); JSONObject object(); }; }