#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