| 1397 | } |
| 1398 | |
| 1399 | Maybe<Json> LuaDetail::tableToJsonContainer(LuaTable const& table) { |
| 1400 | JsonObject stringEntries; |
| 1401 | Map<unsigned, Json> intEntries; |
| 1402 | int typeHint = 0; |
| 1403 | |
| 1404 | if (auto mt = table.getMetatable()) { |
| 1405 | if (auto th = mt->get<Maybe<int>>("__typehint")) |
| 1406 | typeHint = *th; |
| 1407 | |
| 1408 | if (auto nils = mt->get<Maybe<LuaTable>>("__nils")) { |
| 1409 | bool failedConversion = false; |
| 1410 | // Nil entries just have a garbage integer as their value |
| 1411 | nils->iterate([&](LuaValue const& key, LuaValue const&) { |
| 1412 | if (auto i = asInteger(key)) { |
| 1413 | intEntries[*i] = Json(); |
| 1414 | } else { |
| 1415 | if (auto str = table.engine().luaMaybeTo<String>(key)) { |
| 1416 | stringEntries[str.take()] = Json(); |
| 1417 | } else { |
| 1418 | failedConversion = true; |
| 1419 | return false; |
| 1420 | } |
| 1421 | } |
| 1422 | return true; |
| 1423 | }); |
| 1424 | if (failedConversion) |
| 1425 | return {}; |
| 1426 | } |
| 1427 | } |
| 1428 | |
| 1429 | bool failedConversion = false; |
| 1430 | table.iterate([&](LuaValue key, LuaValue value) { |
| 1431 | auto jsonValue = table.engine().luaMaybeTo<Json>(value); |
| 1432 | if (!jsonValue) { |
| 1433 | failedConversion = true; |
| 1434 | return false; |
| 1435 | } |
| 1436 | |
| 1437 | if (auto i = asInteger(key)) { |
| 1438 | intEntries[*i] = jsonValue.take(); |
| 1439 | } else { |
| 1440 | auto stringKey = table.engine().luaMaybeTo<String>(std::move(key)); |
| 1441 | if (!stringKey) { |
| 1442 | failedConversion = true; |
| 1443 | return false; |
| 1444 | } |
| 1445 | |
| 1446 | stringEntries[stringKey.take()] = jsonValue.take(); |
| 1447 | } |
| 1448 | |
| 1449 | return true; |
| 1450 | }); |
| 1451 | |
| 1452 | if (failedConversion) |
| 1453 | return {}; |
| 1454 | |
| 1455 | bool interpretAsList = stringEntries.empty() |
| 1456 | && (typeHint == 1 || (typeHint != 2 && !intEntries.empty() && prev(intEntries.end())->first == intEntries.size())); |