Skip to content

Commit e77c510

Browse files
author
Fszontagh
committed
fix(modules/json): preserve array shape on encode roundtrip
ObjectMap with keys "0","1",...,"N-1" comes from JSON arrays (per jsonToValueWithContext) and array literals. convertMapToJson was emitting them back as objects with string keys, so a JSON manifest's "archs":["x86_64"] round-tripped to "archs":{"0":"x86_64"}. Detect the array shape (every key is "0"-indexed contiguous integer) and emit nlohmann::json::array() in numeric order. Verified against {"archs":["x86_64","aarch64"], "count":3, "nested":{"k":1}} which now round-trips byte-identical. Found while building hello-2.12-1.x86_64.blackhole.unsigned: META.json contained {"archs":{"0":"x86_64"}} which the layer-0 acceptance script rejected as not containing 'x86_64' in m['archs'].
1 parent b9e7ac8 commit e77c510

1 file changed

Lines changed: 44 additions & 15 deletions

File tree

src/Modules/BuiltIn/JsonConverters.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// JsonConverters.cpp
22
#include "JsonConverters.hpp"
33
#include "../../json.hpp"
4-
#include <sstream>
5-
#include <iomanip>
4+
#include <algorithm>
65
#include <cmath>
6+
#include <iomanip>
77
#include <limits>
8+
#include <sstream>
9+
#include <vector>
810

911
namespace Modules {
1012
namespace JsonConverters {
@@ -145,51 +147,78 @@ Symbols::ObjectMap convertJsonObjectToMap(const nlohmann::json& json, const std:
145147
* @param objMap The ObjectMap to convert
146148
* @return nlohmann::json The converted JSON object
147149
*/
150+
// Detect array-shape ObjectMap: every key is "0","1",...,"N-1" with no
151+
// gaps. Such maps were created from JSON arrays (jsonToValueWithContext)
152+
// or array literals; round-trip them back as JSON arrays so consumers
153+
// see the same shape they wrote in.
154+
static bool isArrayShape(const Symbols::ObjectMap& m) {
155+
if (m.empty()) return false;
156+
for (size_t i = 0; i < m.size(); ++i) {
157+
auto it = m.find(std::to_string(i));
158+
if (it == m.end()) return false;
159+
}
160+
return true;
161+
}
162+
148163
nlohmann::json convertMapToJson(const Symbols::ObjectMap& objMap) {
149-
nlohmann::json result;
164+
nlohmann::json result = isArrayShape(objMap) ? nlohmann::json::array()
165+
: nlohmann::json::object();
166+
auto put = [&](const std::string& key, nlohmann::json v) {
167+
if (result.is_array()) result.push_back(std::move(v));
168+
else result[key] = std::move(v);
169+
};
170+
171+
// For arrays we must iterate in numeric order, not std::map's lex order.
172+
std::vector<std::string> keys;
173+
keys.reserve(objMap.size());
174+
for (const auto& kv : objMap) keys.push_back(kv.first);
175+
if (result.is_array()) {
176+
std::sort(keys.begin(), keys.end(), [](const std::string& a, const std::string& b) {
177+
return std::stoll(a) < std::stoll(b);
178+
});
179+
}
150180

151-
for (const auto& kv : objMap) {
152-
const std::string& key = kv.first;
153-
const Symbols::ValuePtr& value = kv.second;
181+
for (const auto& key : keys) {
182+
const Symbols::ValuePtr& value = objMap.at(key);
154183

155184
switch (value.getType()) {
156185
case Symbols::Variables::Type::NULL_TYPE:
157-
result[key] = nullptr;
186+
put(key, nullptr);
158187
break;
159188

160189
case Symbols::Variables::Type::BOOLEAN:
161-
result[key] = value.get<bool>();
190+
put(key, value.get<bool>());
162191
break;
163192

164193
case Symbols::Variables::Type::INTEGER:
165-
result[key] = value.get<int>();
194+
put(key, value.get<int>());
166195
break;
167196

168197
case Symbols::Variables::Type::FLOAT:
169-
result[key] = value.get<float>();
198+
put(key, value.get<float>());
170199
break;
171200

172201
case Symbols::Variables::Type::DOUBLE:
173-
result[key] = value.get<double>();
202+
put(key, value.get<double>());
174203
break;
175204

176205
case Symbols::Variables::Type::STRING:
177-
result[key] = value.get<std::string>();
206+
put(key, value.get<std::string>());
178207
break;
179208

180209
case Symbols::Variables::Type::OBJECT:
181210
case Symbols::Variables::Type::CLASS:
182-
result[key] = convertMapToJson(value.get<Symbols::ObjectMap>());
211+
put(key, convertMapToJson(value.get<Symbols::ObjectMap>()));
183212
break;
184213

185214
case Symbols::Variables::Type::ENUM:
186215
// Convert enum to string representation
187-
result[key] = value.toString();
216+
put(key, value.toString());
188217
break;
189218

190219
default:
191220
// Unsupported type, convert to null
192-
result[key] = nullptr;
221+
put(key, nullptr);
193222
break;
194223
}
195224
}

0 commit comments

Comments
 (0)