#ifndef STAR_JSON_EXTRA_HPP #define STAR_JSON_EXTRA_HPP #include "StarJson.hpp" #include "StarPoly.hpp" #include "StarColor.hpp" #include "StarSet.hpp" #include "StarWeightedPool.hpp" #include "StarDirectives.hpp" namespace Star { // Extra methods to parse a variety of types out of pure JSON. Throws // JsonException if json is not of correct type or size. size_t jsonToSize(Json const& v); Json jsonFromSize(size_t s); // Must be array of appropriate size. Vec2D jsonToVec2D(Json const& v); Vec2F jsonToVec2F(Json const& v); Json jsonFromVec2F(Vec2F const& v); Vec2I jsonToVec2I(Json const& v); Json jsonFromVec2I(Vec2I const& v); Vec2U jsonToVec2U(Json const& v); Json jsonFromVec2U(Vec2U const& v); Vec2B jsonToVec2B(Json const& v); Json jsonFromVec2B(Vec2B const& v); Vec3D jsonToVec3D(Json const& v); Vec3F jsonToVec3F(Json const& v); Json jsonFromVec3F(Vec3F const& v); Vec3I jsonToVec3I(Json const& v); Json jsonFromVec3I(Vec3I const& v); Vec3B jsonToVec3B(Json const& v); Vec4B jsonToVec4B(Json const& v); Vec4I jsonToVec4I(Json const& v); Vec4F jsonToVec4F(Json const& v); // Must be array of size 4 or 2 arrays of size 2 in an array. RectD jsonToRectD(Json const& v); Json jsonFromRectD(RectD const& rect); RectF jsonToRectF(Json const& v); Json jsonFromRectF(RectF const& rect); RectI jsonToRectI(Json const& v); Json jsonFromRectI(RectI const& rect); RectU jsonToRectU(Json const& v); Json jsonFromRectU(RectU const& rect); // Can be a string, array of size 3 or 4 of doubles or ints. If double, range // is 0.0 to 1.0, if int range is 0-255 Color jsonToColor(Json const& v); Json jsonFromColor(Color const& color); // HACK: Fix clockwise specified polygons in coming from JSON template Polygon fixInsideOutPoly(Polygon p); // Array of size 2 arrays PolyD jsonToPolyD(Json const& v); PolyF jsonToPolyF(Json const& v); PolyI jsonToPolyI(Json const& v); Json jsonFromPolyF(PolyF const& poly); // Expects a size 2 array of size 2 arrays Line2F jsonToLine2F(Json const& v); Json jsonFromLine2F(Line2F const& line); Mat3F jsonToMat3F(Json const& v); Json jsonFromMat3F(Mat3F const& v); StringList jsonToStringList(Json const& v); Json jsonFromStringList(List const& v); StringSet jsonToStringSet(Json const& v); Json jsonFromStringSet(StringSet const& v); List jsonToFloatList(Json const& v); List jsonToIntList(Json const& v); List jsonToVec2IList(Json const& v); List jsonToVec2UList(Json const& v); List jsonToVec2FList(Json const& v); List jsonToVec4BList(Json const& v); List jsonToColorList(Json const& v); List jsonToDirectivesList(Json const& v); Json jsonFromDirectivesList(List const& v); Json weightedChoiceFromJson(Json const& source, Json const& default_); // Assumes that the bins parameter is an array of pairs (arrays), where the // first element is a minimum value and the second element is the actual // important value. Finds the pair with the highest value that is less than or // equal to the given target, and returns the second element. Json binnedChoiceFromJson(Json const& bins, float target, Json const& def = Json()); template WeightedPool jsonToWeightedPool(Json const& source); template WeightedPool jsonToWeightedPool(Json const& source, Converter&& converter); template Json jsonFromWeightedPool(WeightedPool const& pool); template Json jsonFromWeightedPool(WeightedPool const& pool, Converter&& converter); template Array jsonToArrayU(Json const& v) { if (v.size() != Size) throw JsonException(strf("Json array not of size %d in jsonToArrayU", Size).c_str()); Array res; for (size_t i = 0; i < Size; i++) { res[i] = v.getUInt(i); } return res; } template Array jsonToArrayS(Json const& v) { if (v.size() != Size) throw JsonException(strf("Json array not of size %d in jsonToArrayS", Size).c_str()); Array res; for (size_t i = 0; i < Size; i++) { res[i] = v.getUInt(i); } return res; } template Array jsonToArrayI(Json const& v) { if (v.size() != Size) throw JsonException(strf("Json array not of size %d in jsonToArrayI", Size).c_str()); Array res; for (size_t i = 0; i < Size; i++) { res[i] = v.getInt(i); } return res; } template Array jsonToArrayF(Json const& v) { if (v.size() != Size) throw JsonException(strf("Json array not of size %d in jsonToArrayF", Size).c_str()); Array res; for (size_t i = 0; i < Size; i++) { res[i] = v.getFloat(i); } return res; } template Array jsonToArrayD(Json const& v) { if (v.size() != Size) throw JsonException(strf("Json array not of size %d in jsonToArrayD", Size).c_str()); Array res; for (size_t i = 0; i < Size; i++) { res[i] = v.getDouble(i); } return res; } template Array jsonToStringArray(Json const& v) { if (v.size() != Size) throw JsonException(strf("Json array not of size %d in jsonToStringArray", Size).c_str()); Array res; for (size_t i = 0; i < Size; i++) { res[i] = v.getString(i); } return res; } template List jsonToList(Json const& v) { return jsonToList(v, construct()); } template List jsonToList(Json const& v, Converter&& valueConvert) { if (v.type() != Json::Type::Array) throw JsonException("Json type is not a array in jsonToList"); List res; for (auto const& entry : v.iterateArray()) res.push_back(valueConvert(entry)); return res; } template Json jsonFromList(List const& list) { return jsonFromList(list, construct()); } template Json jsonFromList(List const& list, Converter&& valueConvert) { JsonArray res; for (auto const& entry : list) res.push_back(valueConvert(entry)); return res; } template Set jsonToSet(Json const& v) { return jsonToSet(v, construct()); } template Set jsonToSet(Json const& v, Converter&& valueConvert) { if (v.type() != Json::Type::Array) throw JsonException("Json type is not an array in jsonToSet"); Set res; for (auto const& entry : v.iterateArray()) res.add(valueConvert(entry)); return res; } template Json jsonFromSet(Set const& Set) { return jsonFromSet(Set, construct()); } template Json jsonFromSet(Set const& Set, Converter&& valueConvert) { JsonArray res; for (auto entry : Set) res.push_back(valueConvert(entry)); return res; } template MapType jsonToMapKV(Json const& v, KeyConverter&& keyConvert, ValueConverter&& valueConvert) { if (v.type() != Json::Type::Object) throw JsonException("Json type is not an object in jsonToMap"); MapType res; for (auto const& pair : v.iterateObject()) res.add(keyConvert(pair.first), valueConvert(pair.second)); return res; } template MapType jsonToMapK(Json const& v, KeyConverter&& keyConvert) { return jsonToMapKV(v, forward(keyConvert), construct()); } template MapType jsonToMapV(Json const& v, ValueConverter&& valueConvert) { return jsonToMapKV(v, construct(), forward(valueConvert)); } template MapType jsonToMap(Json const& v) { return jsonToMapKV(v, construct(), construct()); } template Json jsonFromMapKV(MapType const& map, KeyConverter&& keyConvert, ValueConverter&& valueConvert) { JsonObject res; for (auto pair : map) res[keyConvert(pair.first)] = valueConvert(pair.second); return res; } template Json jsonFromMapK(MapType const& map, KeyConverter&& keyConvert) { return jsonFromMapKV(map, forward(keyConvert), construct()); } template Json jsonFromMapV(MapType const& map, ValueConverter&& valueConvert) { return jsonFromMapKV(map, construct(), forward(valueConvert)); } template Json jsonFromMap(MapType const& map) { return jsonFromMapKV(map, construct(), construct()); } template Json jsonFromMaybe(Maybe const& m, Converter&& converter) { return m.apply(converter).value(); } template Json jsonFromMaybe(Maybe const& m) { return jsonFromMaybe(m, construct()); } template Maybe jsonToMaybe(Json v, Converter&& converter) { if (v.isNull()) return {}; return converter(v); } template Maybe jsonToMaybe(Json const& v) { return jsonToMaybe(v, construct()); } template WeightedPool jsonToWeightedPool(Json const& source) { return jsonToWeightedPool(source, construct()); } template WeightedPool jsonToWeightedPool(Json const& source, Converter&& converter) { WeightedPool res; if (source.isNull()) return res; for (auto entry : source.iterateArray()) { if (entry.isType(Json::Type::Array)) res.add(entry.get(0).toDouble(), converter(entry.get(1))); else res.add(entry.getDouble("weight"), converter(entry.get("item"))); } return res; } template Json jsonFromWeightedPool(WeightedPool const& pool) { return jsonFromWeightedPool(pool, construct()); } template Json jsonFromWeightedPool(WeightedPool const& pool, Converter&& converter) { JsonArray res; for (auto const& pair : pool.items()) { res.append(JsonObject{ {"weight", pair.first}, {"item", converter(pair.second)}, }); } return res; } template <> WeightedPool jsonToWeightedPool(Json const& source); template <> WeightedPool jsonToWeightedPool(Json const& source); template <> WeightedPool jsonToWeightedPool(Json const& source); template <> WeightedPool jsonToWeightedPool(Json const& source); template <> WeightedPool jsonToWeightedPool(Json const& source); template <> WeightedPool jsonToWeightedPool(Json const& source); template <> WeightedPool jsonToWeightedPool(Json const& source); template Polygon fixInsideOutPoly(Polygon p) { if (p.sides() > 2) { if ((p.side(1).diff() ^ p.side(0).diff()) > 0) reverse(p.vertexes()); } return p; } } #endif