#pragma once #include <cassert> #include <iostream> #include <vector> namespace nix { void toJSON(std::ostream& str, const char* start, const char* end); void toJSON(std::ostream& str, const char* s); template <typename T> void toJSON(std::ostream& str, const T& n); class JSONWriter { protected: struct JSONState { std::ostream& str; bool indent; size_t depth = 0; size_t stack = 0; JSONState(std::ostream& str, bool indent) : str(str), indent(indent) {} ~JSONState() { assert(stack == 0); } }; JSONState* state; bool first = true; JSONWriter(std::ostream& str, bool indent); JSONWriter(JSONState* state); ~JSONWriter(); void assertActive() { assert(state->stack != 0); } 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(const JSONObject& obj) = delete; JSONObject(JSONObject&& obj) : JSONWriter(obj.state) { obj.state = 0; } ~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(); }; } // namespace nix