diff --git a/projectloader.cpp b/projectloader.cpp index 91c714a..61b7986 100644 --- a/projectloader.cpp +++ b/projectloader.cpp @@ -1,3 +1,5 @@ +#include + #include "projectloader.h" namespace ProjectLoader { @@ -45,8 +47,12 @@ concept JsonNumber = (std::integral && !std::same_as && !std::is_enu template concept LoadableQEnum = std::is_enum_v; +template +concept SameAsQualified = std::same_as, U>; + } // namespace detail + // forward declarations for loading stuff from QJsonValue template std::expected load(const QJsonValue &json); @@ -55,6 +61,55 @@ std::expected load(const QJsonValue &json); template std::expected load(const QJsonValue &json); + +// iterateMembers stuff +template T, typename CB> +void iterateMembers(T &ref, CB &&cb) +{ + cb("deviceTypes", ref.deviceTypes); + cb("devices", ref.devices); + cb("presets", ref.presets); +} + +template T, typename CB> +void iterateMembers(T &ref, CB &&cb) +{ + cb("id", ref.id); + cb("name", ref.name); + cb("iconName", ref.iconName); + cb("registers", ref.registers); +} + +template T, typename CB> +void iterateMembers(T &ref, CB &&cb) +{ + cb("id", ref.id); + cb("name", ref.name); + cb("deviceTypeId", ref.deviceTypeId); + cb("address", ref.address); + cb("position", ref.position); +} + +template T, typename CB> +void iterateMembers(T &ref, CB &&cb) +{ + cb("id", ref.id); + cb("name", ref.name); + cb("steps", ref.steps); +} + +template T, typename CB> +void iterateMembers(T &ref, CB &&cb) +{ + cb("type", ref.type); +} + +template T, typename CB> +void iterateMembers(T &ref, CB &&cb) +{ + cb("sliders", ref.sliders); +} + template std::expected load(const QJsonArray &json) { T result; @@ -146,137 +201,26 @@ std::expected loadIfExists(const QJsonObject &json, const QString &k } } -template T> +template std::expected load(const QJsonObject &json) { - LightProject lp; + T t; + std::optional> error; - if (auto deviceTypes = loadIfExists(json, "deviceTypes"); deviceTypes) { - lp.deviceTypes = std::move(deviceTypes.value()); - } else { - return std::unexpected(QString("deviceTypes: %1").arg(deviceTypes.error())); - } + iterateMembers(t, [&json, &error] (const char *name, auto &field) { + if (error) + return; - if (auto devices = loadIfExists(json, "devices"); devices) { - lp.devices = std::move(devices.value()); - } else { - return std::unexpected(QString("devices: %1").arg(devices.error())); - } + if (auto result = loadIfExists>(json, name)) { + field = std::move(result.value()); + } else { + error = std::unexpected(QString("%1: %2").arg(name).arg(result.error())); + } + }); - if (auto presets = loadIfExists(json, "presets"); presets) { - lp.presets = std::move(presets.value()); - } else { - return std::unexpected(QString("presets: %1").arg(presets.error())); - } + if (error) + return *error; - return lp; -} - -template T> -std::expected load(const QJsonObject &json) { - DeviceTypeConfig dtc; - - if (auto val = loadIfExists(json, "id"); val) { - dtc.id = val.value(); - } else { - return std::unexpected(QString("id: %1").arg(val.error())); - } - - if (auto val = loadIfExists(json, "name"); val) { - dtc.name = val.value(); - } else { - return std::unexpected(QString("name: %1").arg(val.error())); - } - - if (auto val = loadIfExists(json, "iconName"); val) { - dtc.iconName = val.value(); - } else { - return std::unexpected(QString("iconName: %1").arg(val.error())); - } - - if (auto val = loadIfExists(json, "registers"); val) { - dtc.registers = std::move(val.value()); - } else { - return std::unexpected(QString("registers: %1").arg(val.error())); - } - - return dtc; -} - -template T> -std::expected load(const QJsonObject &json) { - DeviceTypeRegisterConfig dtrc; - if (auto val = loadIfExists(json, "type"); val) { - dtrc.type = val.value(); - } else { - return std::unexpected(QString("type: %1").arg(val.error())); - } - - return dtrc; -} - -template T> -std::expected load(const QJsonObject &json) { - DeviceConfig dc; - if (auto val = loadIfExists(json, "id"); val) { - dc.id = val.value(); - } else { - return std::unexpected(QString("id: %1").arg(val.error())); - } - if (auto val = loadIfExists(json, "name"); val) { - dc.name = val.value(); - } else { - return std::unexpected(QString("name: %1").arg(val.error())); - } - if (auto val = loadIfExists(json, "deviceTypeId"); val) { - dc.deviceTypeId = val.value(); - } else { - return std::unexpected(QString("deviceTypeId: %1").arg(val.error())); - } - if (auto val = loadIfExists(json, "address"); val) { - dc.address = val.value(); - } else { - return std::unexpected(QString("address: %1").arg(val.error())); - } - if (auto val = loadIfExists(json, "position"); val) { - dc.position = val.value(); - } else { - return std::unexpected(QString("position: %1").arg(val.error())); - } - - return dc; -} - -template T> -std::expected load(const QJsonObject &json) { - PresetStepConfig rgc; - if (auto val = loadIfExists(json, "sliders"); val) { - rgc.sliders = val.value(); - } else { - return std::unexpected(QString("sliders: %1").arg(val.error())); - } - return rgc; -} - -template T> -std::expected load(const QJsonObject &json) { - PresetConfig rgc; - if (auto val = loadIfExists(json, "id"); val) { - rgc.id = val.value(); - } else { - return std::unexpected(QString("id: %1").arg(val.error())); - } - if (auto val = loadIfExists(json, "name"); val) { - rgc.name = val.value(); - } else { - return std::unexpected(QString("name: %1").arg(val.error())); - } - if (auto val = loadIfExists(json, "steps"); val) { - rgc.steps = val.value(); - } else { - return std::unexpected(QString("steps: %1").arg(val.error())); - } - - return rgc; + return t; } template @@ -329,110 +273,24 @@ std::expected save(const T &val) { } } -template T> +template std::expected save(const T &val) { QJsonObject json; + std::optional> error; - if (auto id = save(val.id); id) { - json["id"] = id.value(); - } else { - return std::unexpected(QString("id: %1").arg(id.error())); - } + iterateMembers(val, [&json, &error] (const char *name, auto &field) { + if (error) + return; - if (auto name = save(val.name); name) { - json["name"] = name.value(); - } else { - return std::unexpected(QString("name: %1").arg(name.error())); - } + if (auto result = save>(field)) { + json[name] = result.value(); + } else { + error = std::unexpected(QString("%1: %2").arg(name).arg(result.error())); + } + }); - if (auto iconName = save(val.iconName); iconName) { - json["iconName"] = iconName.value(); - } else { - return std::unexpected(QString("iconName: %1").arg(iconName.error())); - } - - if (auto registers = save(val.registers); registers) { - json["registers"] = registers.value(); - } else { - return std::unexpected(QString("registers: %1").arg(registers.error())); - } - - return json; -} - -template T> -std::expected save(const T &val) { - QJsonObject json; - if (auto type = save(val.type); type) { - json["type"] = type.value(); - } else { - return std::unexpected(QString("type: %1").arg(type.error())); - } - - return json; -} - -template T> -std::expected save(const T &val) { - QJsonObject json; - if (auto id = save(val.id); id) { - json["id"] = id.value(); - } else { - return std::unexpected(QString("id: %1").arg(id.error())); - } - if (auto name = save(val.name); name) { - json["name"] = name.value(); - } else { - return std::unexpected(QString("name: %1").arg(name.error())); - } - if (auto deviceTypeId = save(val.deviceTypeId); deviceTypeId) { - json["deviceTypeId"] = deviceTypeId.value(); - } else { - return std::unexpected(QString("deviceTypeId: %1").arg(deviceTypeId.error())); - } - if (auto address = save(val.address); address) { - json["address"] = address.value(); - } else { - return std::unexpected(QString("address: %1").arg(address.error())); - } - if (auto position = save(val.position); position) { - json["position"] = position.value(); - } else { - return std::unexpected(QString("position: %1").arg(position.error())); - } - - return json; -} - -template T> -std::expected save(const T &val) { - QJsonObject json; - if (auto sliders = save(val.sliders); sliders) { - json["sliders"] = sliders.value(); - } else { - return std::unexpected(QString("sliders: %1").arg(sliders.error())); - } - return json; -} - -template T> -std::expected save(const T &val) { - QJsonObject json; - if (auto id = save(val.id); id) { - json["id"] = id.value(); - } else { - return std::unexpected(QString("id: %1").arg(id.error())); - } - if (auto name = save(val.name); name) { - json["name"] = name.value(); - } else { - return std::unexpected(QString("name: %1").arg(name.error())); - } - if (auto steps = save(val.steps); steps) { - json["steps"] = steps.value(); - } else { - return std::unexpected(QString("steps: %1").arg(steps.error())); - } + if (error) + return *error; return json; } @@ -454,30 +312,6 @@ std::expected save(const T &val) { return arr; } -template T> -std::expected save(const T &val) { - QJsonObject json; - if (auto deviceTypes = save(val.deviceTypes); deviceTypes) { - json["deviceTypes"] = deviceTypes.value(); - } else { - return std::unexpected(QString("deviceTypes: %1").arg(deviceTypes.error())); - } - - if (auto devices = save(val.devices); devices) { - json["devices"] = devices.value(); - } else { - return std::unexpected(QString("devices: %1").arg(devices.error())); - } - - if (auto presets = save(val.presets); presets) { - json["presets"] = presets.value(); - } else { - return std::unexpected(QString("presets: %1").arg(presets.error())); - } - - return json; -} - } // namespace std::expected saveProject(const LightProject &val) {