#include "json.hh" #include #include #include namespace nix { template<> void toJSON(std::ostream & str, const std::string_view & s) { constexpr size_t BUF_SIZE = 4096; char buf[BUF_SIZE + 7]; // BUF_SIZE + largest single sequence of puts size_t bufPos = 0; const auto flush = [&] { str.write(buf, bufPos); bufPos = 0; }; const auto put = [&] (char c) { buf[bufPos++] = c; }; put('"'); for (auto i = s.begin(); i != s.end(); i++) { if (bufPos >= BUF_SIZE) flush(); if (*i == '\"' || *i == '\\') { put('\\'); put(*i); } else if (*i == '\n') { put('\\'); put('n'); } else if (*i == '\r') { put('\\'); put('r'); } else if (*i == '\t') { put('\\'); put('t'); } else if (*i >= 0 && *i < 32) { const char hex[17] = "0123456789abcdef"; put('\\'); put('u'); put(hex[(uint16_t(*i) >> 12) & 0xf]); put(hex[(uint16_t(*i) >> 8) & 0xf]); put(hex[(uint16_t(*i) >> 4) & 0xf]); put(hex[(uint16_t(*i) >> 0) & 0xf]); } else put(*i); } put('"'); flush(); } void toJSON(std::ostream & str, const char * s) { if (!s) str << "null"; else toJSON(str, std::string_view(s)); } template<> void toJSON(std::ostream & str, const int & n) { str << n; } template<> void toJSON(std::ostream & str, const unsigned int & n) { str << n; } template<> void toJSON(std::ostream & str, const long & n) { str << n; } template<> void toJSON(std::ostream & str, const unsigned long & n) { str << n; } template<> void toJSON(std::ostream & str, const long long & n) { str << n; } template<> void toJSON(std::ostream & str, const unsigned long long & n) { str << n; } template<> void toJSON(std::ostream & str, const float & n) { str << n; } template<> void toJSON(std::ostream & str, const double & n) { str << n; } template<> void toJSON(std::ostream & str, const std::string & s) { toJSON(str, (std::string_view) s); } template<> void toJSON(std::ostream & str, const bool & b) { str << (b ? "true" : "false"); } template<> void toJSON(std::ostream & str, const std::nullptr_t & b) { str << "null"; } JSONWriter::JSONWriter(std::ostream & str, bool indent) : state(new JSONState(str, indent)) { state->stack++; } JSONWriter::JSONWriter(JSONState * state) : state(state) { state->stack++; } JSONWriter::~JSONWriter() { if (state) { assertActive(); state->stack--; if (state->stack == 0) delete state; } } void JSONWriter::comma() { assertActive(); if (first) { first = false; } else { state->str << ','; } if (state->indent) indent(); } void JSONWriter::indent() { state->str << '\n' << std::string(state->depth * 2, ' '); } void JSONList::open() { state->depth++; state->str << '['; } JSONList::~JSONList() { state->depth--; if (state->indent && !first) indent(); state->str << "]"; } JSONList JSONList::list() { comma(); return JSONList(state); } JSONObject JSONList::object() { comma(); return JSONObject(state); } JSONPlaceholder JSONList::placeholder() { comma(); return JSONPlaceholder(state); } void JSONObject::open() { state->depth++; state->str << '{'; } JSONObject::~JSONObject() { if (state) { state->depth--; if (state->indent && !first) indent(); state->str << "}"; } } void JSONObject::attr(std::string_view s) { comma(); toJSON(state->str, s); state->str << ':'; if (state->indent) state->str << ' '; } JSONList JSONObject::list(std::string_view name) { attr(name); return JSONList(state); } JSONObject JSONObject::object(std::string_view name) { attr(name); return JSONObject(state); } JSONPlaceholder JSONObject::placeholder(std::string_view name) { attr(name); return JSONPlaceholder(state); } JSONList JSONPlaceholder::list() { assertValid(); first = false; return JSONList(state); } JSONObject JSONPlaceholder::object() { assertValid(); first = false; return JSONObject(state); } JSONPlaceholder::~JSONPlaceholder() { if (first) { assert(std::uncaught_exceptions()); if (state->stack != 0) write(nullptr); } } }