fix: define declared method + insert new bar entries to config file list + rename Hyprsunset -> Nightlight
This commit is contained in:
+260
-211
@@ -16,352 +16,401 @@ namespace {
|
||||
|
||||
// We don't know the option here so it isn't set, it should be set by the caller
|
||||
DecodeResult error(DiagnosticType::Type type, const QString& message) {
|
||||
Diagnostic error;
|
||||
error.type = type;
|
||||
error.message = message;
|
||||
return { .value = QVariant(), .error = error, .indexPath = {} };
|
||||
Diagnostic error;
|
||||
error.type = type;
|
||||
error.message = message;
|
||||
return {.value = QVariant(), .error = error, .indexPath = {}};
|
||||
}
|
||||
|
||||
DecodeResult mismatch(ExpectedType expected, const QJsonValue& value) {
|
||||
return { .value = QVariant(), .error = Diagnostic::mismatch(expected, value), .indexPath = {} };
|
||||
return {
|
||||
.value = QVariant(),
|
||||
.error = Diagnostic::mismatch(expected, value),
|
||||
.indexPath = {}};
|
||||
}
|
||||
|
||||
DecodeResult mismatch(const QList<ExpectedType>& expected, const QJsonValue& value) {
|
||||
return { .value = QVariant(), .error = Diagnostic::mismatch(expected, value), .indexPath = {} };
|
||||
DecodeResult mismatch(
|
||||
const QList<ExpectedType>& expected, const QJsonValue& value) {
|
||||
return {
|
||||
.value = QVariant(),
|
||||
.error = Diagnostic::mismatch(expected, value),
|
||||
.indexPath = {}};
|
||||
}
|
||||
|
||||
template <typename Container> ValueCodec* makeListCodec(const QMetaType& type) {
|
||||
const auto* elementCodec = ValueCodec::codecFor(QMetaType::fromType<typename Container::value_type>());
|
||||
return elementCodec ? new ListCodec<Container>(type, elementCodec) : nullptr;
|
||||
const auto* elementCodec = ValueCodec::codecFor(
|
||||
QMetaType::fromType<typename Container::value_type>());
|
||||
return elementCodec ? new ListCodec<Container>(type, elementCodec)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
// Unions are keyed by their alternatives in order, since order decides which one wins
|
||||
QString unionKey(const QList<QMetaType>& types) {
|
||||
QStringList ids;
|
||||
ids.reserve(types.size());
|
||||
for (const auto& type : types)
|
||||
ids << QString::number(type.id());
|
||||
return ids.join(u","_s);
|
||||
QStringList ids;
|
||||
ids.reserve(types.size());
|
||||
for (const auto& type : types)
|
||||
ids << QString::number(type.id());
|
||||
return ids.join(u","_s);
|
||||
}
|
||||
|
||||
QList<ExpectedType> expectedTypesOf(const QList<const ValueCodec*>& alternatives) {
|
||||
QList<ExpectedType> types;
|
||||
types.reserve(alternatives.size());
|
||||
for (const auto* codec : alternatives)
|
||||
types << codec->expected();
|
||||
return types;
|
||||
QList<ExpectedType> expectedTypesOf(
|
||||
const QList<const ValueCodec*>& alternatives) {
|
||||
QList<ExpectedType> types;
|
||||
types.reserve(alternatives.size());
|
||||
for (const auto* codec : alternatives)
|
||||
types << codec->expected();
|
||||
return types;
|
||||
}
|
||||
|
||||
using ListFactory = ValueCodec* (*)(const QMetaType&);
|
||||
|
||||
const QHash<int, ListFactory>& listFactories() {
|
||||
static const QHash<int, ListFactory> k_factories{
|
||||
{ QMetaType::fromType<QStringList>().id(), &makeListCodec<QStringList> },
|
||||
{ QMetaType::fromType<QList<qreal>>().id(), &makeListCodec<QList<qreal>> },
|
||||
};
|
||||
return k_factories;
|
||||
static const QHash<int, ListFactory> k_factories{
|
||||
{QMetaType::fromType<QStringList>().id(), &makeListCodec<QStringList>},
|
||||
{QMetaType::fromType<QList<qreal>>().id(),
|
||||
&makeListCodec<QList<qreal>>},
|
||||
};
|
||||
return k_factories;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ValueCodec::ValueCodec(const QMetaType& type, ExpectedType expected)
|
||||
: m_type(type)
|
||||
, m_expected(expected) {}
|
||||
: m_type(type), m_expected(expected) {}
|
||||
|
||||
QMetaType ValueCodec::type() const {
|
||||
return m_type;
|
||||
return m_type;
|
||||
}
|
||||
|
||||
ExpectedType ValueCodec::expected() const {
|
||||
return m_expected;
|
||||
return m_expected;
|
||||
}
|
||||
|
||||
ValueCodec* ValueCodec::codecFor(const QMetaType& type) {
|
||||
// Cache for codecs, keyed by type id
|
||||
static QHash<int, ValueCodec*> s_registry;
|
||||
// Cache for codecs, keyed by type id
|
||||
static QHash<int, ValueCodec*> s_registry;
|
||||
|
||||
// Cached lookup
|
||||
if (const auto it = s_registry.constFind(type.id()); it != s_registry.constEnd())
|
||||
return *it;
|
||||
// Cached lookup
|
||||
if (const auto it = s_registry.constFind(type.id());
|
||||
it != s_registry.constEnd())
|
||||
return *it;
|
||||
|
||||
ValueCodec* codec = nullptr;
|
||||
switch (type.id()) {
|
||||
case QMetaType::Bool:
|
||||
codec = new BoolCodec(type);
|
||||
break;
|
||||
case QMetaType::Int:
|
||||
codec = new IntCodec(type);
|
||||
break;
|
||||
case QMetaType::Double:
|
||||
codec = new RealCodec(type);
|
||||
break;
|
||||
case QMetaType::QString:
|
||||
codec = new StringCodec(type);
|
||||
break;
|
||||
case QMetaType::QVariantList:
|
||||
codec = new VariantListCodec(type);
|
||||
break;
|
||||
case QMetaType::QVariantMap:
|
||||
codec = new VariantMapCodec(type);
|
||||
break;
|
||||
default:
|
||||
if (const auto factory = listFactories().constFind(type.id()); factory != listFactories().constEnd())
|
||||
codec = (*factory)(type);
|
||||
else if (util::isSupportedEnum(type))
|
||||
codec = new EnumCodec(type, util::metaEnumFor(type));
|
||||
break;
|
||||
}
|
||||
ValueCodec* codec = nullptr;
|
||||
switch (type.id()) {
|
||||
case QMetaType::Bool:
|
||||
codec = new BoolCodec(type);
|
||||
break;
|
||||
case QMetaType::Int:
|
||||
codec = new IntCodec(type);
|
||||
break;
|
||||
case QMetaType::Double:
|
||||
codec = new RealCodec(type);
|
||||
break;
|
||||
case QMetaType::QString:
|
||||
codec = new StringCodec(type);
|
||||
break;
|
||||
case QMetaType::QVariantList:
|
||||
codec = new VariantListCodec(type);
|
||||
break;
|
||||
case QMetaType::QVariantMap:
|
||||
codec = new VariantMapCodec(type);
|
||||
break;
|
||||
default:
|
||||
if (const auto factory = listFactories().constFind(type.id());
|
||||
factory != listFactories().constEnd())
|
||||
codec = (*factory)(type);
|
||||
else if (util::isSupportedEnum(type))
|
||||
codec = new EnumCodec(type, util::metaEnumFor(type));
|
||||
break;
|
||||
}
|
||||
|
||||
// Cache codec
|
||||
if (codec)
|
||||
s_registry.insert(type.id(), codec);
|
||||
// Cache codec
|
||||
if (codec) s_registry.insert(type.id(), codec);
|
||||
|
||||
return codec;
|
||||
return codec;
|
||||
}
|
||||
|
||||
ValueCodec* ValueCodec::unionFor(const QList<QMetaType>& types) {
|
||||
// Cache for union codecs, keyed by their alternatives
|
||||
static QHash<QString, ValueCodec*> s_registry;
|
||||
// Cache for union codecs, keyed by their alternatives
|
||||
static QHash<QString, ValueCodec*> s_registry;
|
||||
|
||||
if (types.size() < 2) {
|
||||
qCCritical(lcSettings, "A union needs at least two types, got %lld", types.size());
|
||||
return nullptr;
|
||||
}
|
||||
if (types.size() < 2) {
|
||||
qCCritical(
|
||||
lcSettings,
|
||||
"A union needs at least two types, got %lld",
|
||||
types.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto key = unionKey(types);
|
||||
const auto key = unionKey(types);
|
||||
|
||||
// Cached lookup
|
||||
if (const auto it = s_registry.constFind(key); it != s_registry.constEnd())
|
||||
return *it;
|
||||
// Cached lookup
|
||||
if (const auto it = s_registry.constFind(key); it != s_registry.constEnd())
|
||||
return *it;
|
||||
|
||||
QList<const ValueCodec*> alternatives;
|
||||
alternatives.reserve(types.size());
|
||||
QList<const ValueCodec*> alternatives;
|
||||
alternatives.reserve(types.size());
|
||||
|
||||
for (const auto& type : types) {
|
||||
const auto* codec = codecFor(type);
|
||||
if (!codec) {
|
||||
qCCritical(lcSettings, "No codec found for type %s, cannot build union", type.name());
|
||||
return nullptr;
|
||||
}
|
||||
alternatives << codec;
|
||||
}
|
||||
for (const auto& type : types) {
|
||||
const auto* codec = codecFor(type);
|
||||
if (!codec) {
|
||||
qCCritical(
|
||||
lcSettings,
|
||||
"No codec found for type %s, cannot build union",
|
||||
type.name());
|
||||
return nullptr;
|
||||
}
|
||||
alternatives << codec;
|
||||
}
|
||||
|
||||
auto* const codec = new UnionCodec(alternatives);
|
||||
s_registry.insert(key, codec);
|
||||
auto* const codec = new UnionCodec(alternatives);
|
||||
s_registry.insert(key, codec);
|
||||
|
||||
return codec;
|
||||
return codec;
|
||||
}
|
||||
|
||||
QJsonValue BoolCodec::encode(const QVariant& value) const {
|
||||
return value.toBool();
|
||||
return value.toBool();
|
||||
}
|
||||
|
||||
DecodeResult BoolCodec::decode(const QJsonValue& value) const {
|
||||
// 1 and "true" are not booleans
|
||||
if (!value.isBool())
|
||||
return mismatch(ExpectedType::Bool, value);
|
||||
// 1 and "true" are not booleans
|
||||
if (!value.isBool()) return mismatch(ExpectedType::Bool, value);
|
||||
|
||||
return { .value = value.toBool(), .error = std::nullopt, .indexPath = {} };
|
||||
return {.value = value.toBool(), .error = std::nullopt, .indexPath = {}};
|
||||
}
|
||||
|
||||
QJsonValue IntCodec::encode(const QVariant& value) const {
|
||||
return value.toInt();
|
||||
return value.toInt();
|
||||
}
|
||||
|
||||
DecodeResult IntCodec::decode(const QJsonValue& value) const {
|
||||
if (!value.isDouble())
|
||||
return mismatch(ExpectedType::Int, value);
|
||||
if (!value.isDouble()) return mismatch(ExpectedType::Int, value);
|
||||
|
||||
const auto num = value.toDouble();
|
||||
const auto num = value.toDouble();
|
||||
|
||||
double integral;
|
||||
if (std::fpclassify(std::modf(num, &integral)) != FP_ZERO)
|
||||
return error(
|
||||
DiagnosticType::InvalidValue, QStringLiteral("Expected an integer, got the real %1").arg(QString::number(num)));
|
||||
double integral;
|
||||
if (std::fpclassify(std::modf(num, &integral)) != FP_ZERO)
|
||||
return error(
|
||||
DiagnosticType::InvalidValue,
|
||||
QStringLiteral("Expected an integer, got the real %1")
|
||||
.arg(QString::number(num)));
|
||||
|
||||
constexpr auto k_min = std::numeric_limits<int>::min();
|
||||
constexpr auto k_max = std::numeric_limits<int>::max();
|
||||
if (num < static_cast<double>(k_min) || num > static_cast<double>(k_max)) {
|
||||
const auto message = QStringLiteral("Integer %1 is out of range, expected between %2 and %3").arg(QString::number(num, 'f', 0), QString::number(k_min), QString::number(k_max));
|
||||
return error(DiagnosticType::InvalidValue, message);
|
||||
}
|
||||
constexpr auto k_min = std::numeric_limits<int>::min();
|
||||
constexpr auto k_max = std::numeric_limits<int>::max();
|
||||
if (num < static_cast<double>(k_min) || num > static_cast<double>(k_max)) {
|
||||
const auto message =
|
||||
QStringLiteral(
|
||||
"Integer %1 is out of range, expected between %2 and %3")
|
||||
.arg(
|
||||
QString::number(num, 'f', 0),
|
||||
QString::number(k_min),
|
||||
QString::number(k_max));
|
||||
return error(DiagnosticType::InvalidValue, message);
|
||||
}
|
||||
|
||||
return { .value = static_cast<int>(num), .error = std::nullopt, .indexPath = {} };
|
||||
return {
|
||||
.value = static_cast<int>(num), .error = std::nullopt, .indexPath = {}};
|
||||
}
|
||||
|
||||
QJsonValue RealCodec::encode(const QVariant& value) const {
|
||||
return value.toDouble();
|
||||
return value.toDouble();
|
||||
}
|
||||
|
||||
DecodeResult RealCodec::decode(const QJsonValue& value) const {
|
||||
if (!value.isDouble())
|
||||
return mismatch(ExpectedType::Real, value);
|
||||
if (!value.isDouble()) return mismatch(ExpectedType::Real, value);
|
||||
|
||||
return { .value = QVariant::fromValue<qreal>(value.toDouble()), .error = std::nullopt, .indexPath = {} };
|
||||
return {
|
||||
.value = QVariant::fromValue<qreal>(value.toDouble()),
|
||||
.error = std::nullopt,
|
||||
.indexPath = {}};
|
||||
}
|
||||
|
||||
QJsonValue StringCodec::encode(const QVariant& value) const {
|
||||
return value.toString();
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
DecodeResult StringCodec::decode(const QJsonValue& value) const {
|
||||
if (!value.isString())
|
||||
return mismatch(ExpectedType::String, value);
|
||||
if (!value.isString()) return mismatch(ExpectedType::String, value);
|
||||
|
||||
return { .value = value.toString(), .error = std::nullopt, .indexPath = {} };
|
||||
return {.value = value.toString(), .error = std::nullopt, .indexPath = {}};
|
||||
}
|
||||
|
||||
QJsonValue VariantListCodec::encode(const QVariant& value) const {
|
||||
return QJsonArray::fromVariantList(value.toList());
|
||||
return QJsonArray::fromVariantList(value.toList());
|
||||
}
|
||||
|
||||
DecodeResult VariantListCodec::decode(const QJsonValue& value) const {
|
||||
if (!value.isArray())
|
||||
return mismatch(ExpectedType::Array, value);
|
||||
if (!value.isArray()) return mismatch(ExpectedType::Array, value);
|
||||
|
||||
return { .value = value.toArray().toVariantList(), .error = std::nullopt, .indexPath = {} };
|
||||
return {
|
||||
.value = value.toArray().toVariantList(),
|
||||
.error = std::nullopt,
|
||||
.indexPath = {}};
|
||||
}
|
||||
|
||||
QJsonValue VariantMapCodec::encode(const QVariant& value) const {
|
||||
return QJsonObject::fromVariantMap(value.toMap());
|
||||
return QJsonObject::fromVariantMap(value.toMap());
|
||||
}
|
||||
|
||||
DecodeResult VariantMapCodec::decode(const QJsonValue& value) const {
|
||||
if (!value.isObject())
|
||||
return mismatch(ExpectedType::Object, value);
|
||||
if (!value.isObject()) return mismatch(ExpectedType::Object, value);
|
||||
|
||||
return { .value = value.toObject().toVariantMap(), .error = std::nullopt, .indexPath = {} };
|
||||
return {
|
||||
.value = value.toObject().toVariantMap(),
|
||||
.error = std::nullopt,
|
||||
.indexPath = {}};
|
||||
}
|
||||
|
||||
EnumCodec::EnumCodec(const QMetaType& type, const QMetaEnum& metaEnum)
|
||||
: ValueCodec(type, ExpectedType::String)
|
||||
, m_metaEnum(metaEnum) {}
|
||||
: ValueCodec(type, ExpectedType::String), m_metaEnum(metaEnum) {}
|
||||
|
||||
QJsonValue EnumCodec::encode(const QVariant& value) const {
|
||||
const auto* key = util::enumKeyFor(m_metaEnum, value);
|
||||
if (!key) {
|
||||
qCWarning(
|
||||
lcSettings, "Cannot encode value %lld of enum %s, no such enumerator", value.toLongLong(), m_type.name());
|
||||
return {};
|
||||
}
|
||||
const auto* key = util::enumKeyFor(m_metaEnum, value);
|
||||
if (!key) {
|
||||
qCWarning(
|
||||
lcSettings,
|
||||
"Cannot encode value %lld of enum %s, no such enumerator",
|
||||
value.toLongLong(),
|
||||
m_type.name());
|
||||
return {};
|
||||
}
|
||||
|
||||
return QString::fromUtf8(key);
|
||||
return QString::fromUtf8(key);
|
||||
}
|
||||
|
||||
DecodeResult EnumCodec::decode(const QJsonValue& value) const {
|
||||
if (!value.isString())
|
||||
return mismatch(ExpectedType::String, value);
|
||||
if (!value.isString()) return mismatch(ExpectedType::String, value);
|
||||
|
||||
const auto key = value.toString();
|
||||
const auto key = value.toString();
|
||||
|
||||
for (int i = 0; i < m_metaEnum.keyCount(); ++i) {
|
||||
if (QString::compare(QString::fromUtf8(m_metaEnum.key(i)), key, Qt::CaseInsensitive) != 0)
|
||||
continue;
|
||||
for (int i = 0; i < m_metaEnum.keyCount(); ++i) {
|
||||
if (QString::compare(
|
||||
QString::fromUtf8(m_metaEnum.key(i)),
|
||||
key,
|
||||
Qt::CaseInsensitive) != 0)
|
||||
continue;
|
||||
|
||||
const auto raw = m_metaEnum.value(i);
|
||||
QVariant decoded(m_type);
|
||||
if (!QMetaType::convert(QMetaType::fromType<int>(), &raw, m_type, decoded.data())) {
|
||||
qCCritical(lcSettings, "Failed to convert value %d to enum %s", raw, m_type.name());
|
||||
return error(DiagnosticType::InvalidValue,
|
||||
QStringLiteral("Could not convert %1 to %2").arg(key, QString::fromUtf8(m_type.name())));
|
||||
}
|
||||
const auto raw = m_metaEnum.value(i);
|
||||
QVariant decoded(m_type);
|
||||
if (!QMetaType::convert(
|
||||
QMetaType::fromType<int>(), &raw, m_type, decoded.data())) {
|
||||
qCCritical(
|
||||
lcSettings,
|
||||
"Failed to convert value %d to enum %s",
|
||||
raw,
|
||||
m_type.name());
|
||||
return error(
|
||||
DiagnosticType::InvalidValue,
|
||||
QStringLiteral("Could not convert %1 to %2")
|
||||
.arg(key, QString::fromUtf8(m_type.name())));
|
||||
}
|
||||
|
||||
return { .value = decoded, .error = std::nullopt, .indexPath = {} };
|
||||
}
|
||||
return {.value = decoded, .error = std::nullopt, .indexPath = {}};
|
||||
}
|
||||
|
||||
QStringList options;
|
||||
options.reserve(m_metaEnum.keyCount());
|
||||
for (int i = 0; i < m_metaEnum.keyCount(); ++i)
|
||||
options << QString::fromUtf8(m_metaEnum.key(i));
|
||||
QStringList options;
|
||||
options.reserve(m_metaEnum.keyCount());
|
||||
for (int i = 0; i < m_metaEnum.keyCount(); ++i)
|
||||
options << QString::fromUtf8(m_metaEnum.key(i));
|
||||
|
||||
return error(DiagnosticType::InvalidValue,
|
||||
QStringLiteral("Invalid enum value %1. Expected one of %2").arg(key, options.join(u", "_s)));
|
||||
return error(
|
||||
DiagnosticType::InvalidValue,
|
||||
QStringLiteral("Invalid enum value %1. Expected one of %2")
|
||||
.arg(key, options.join(u", "_s)));
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
ListCodec<Container>::ListCodec(const QMetaType& type, const ValueCodec* elementCodec)
|
||||
: ValueCodec(type, ExpectedType::Array)
|
||||
, m_elementCodec(elementCodec) {}
|
||||
ListCodec<Container>::ListCodec(
|
||||
const QMetaType& type, const ValueCodec* elementCodec)
|
||||
: ValueCodec(type, ExpectedType::Array), m_elementCodec(elementCodec) {}
|
||||
|
||||
template <typename Container> QJsonValue ListCodec<Container>::encode(const QVariant& value) const {
|
||||
QJsonArray array;
|
||||
const auto list = value.value<Container>();
|
||||
for (const auto& element : list)
|
||||
array.append(m_elementCodec->encode(QVariant::fromValue(element)));
|
||||
return array;
|
||||
template <typename Container>
|
||||
QJsonValue ListCodec<Container>::encode(const QVariant& value) const {
|
||||
QJsonArray array;
|
||||
const auto list = value.value<Container>();
|
||||
for (const auto& element : list)
|
||||
array.append(m_elementCodec->encode(QVariant::fromValue(element)));
|
||||
return array;
|
||||
}
|
||||
|
||||
template <typename Container> DecodeResult ListCodec<Container>::decode(const QJsonValue& value) const {
|
||||
if (!value.isArray())
|
||||
return mismatch(ExpectedType::Array, value);
|
||||
template <typename Container>
|
||||
DecodeResult ListCodec<Container>::decode(const QJsonValue& value) const {
|
||||
if (!value.isArray()) return mismatch(ExpectedType::Array, value);
|
||||
|
||||
const auto array = value.toArray();
|
||||
Container list;
|
||||
list.reserve(array.size());
|
||||
const auto array = value.toArray();
|
||||
Container list;
|
||||
list.reserve(array.size());
|
||||
|
||||
for (qsizetype i = 0; i < array.size(); ++i) {
|
||||
auto result = m_elementCodec->decode(array.at(i));
|
||||
for (qsizetype i = 0; i < array.size(); ++i) {
|
||||
auto result = m_elementCodec->decode(array.at(i));
|
||||
|
||||
// Reject the entire list if any element is invalid
|
||||
if (result.error) {
|
||||
result.indexPath.prepend(i);
|
||||
return result;
|
||||
}
|
||||
// Reject the entire list if any element is invalid
|
||||
if (result.error) {
|
||||
result.indexPath.prepend(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
list.append(result.value.value<Value>());
|
||||
}
|
||||
list.append(result.value.value<Value>());
|
||||
}
|
||||
|
||||
return { .value = QVariant::fromValue(list), .error = std::nullopt, .indexPath = {} };
|
||||
return {
|
||||
.value = QVariant::fromValue(list),
|
||||
.error = std::nullopt,
|
||||
.indexPath = {}};
|
||||
}
|
||||
|
||||
UnionCodec::UnionCodec(const QList<const ValueCodec*>& alternatives)
|
||||
: ValueCodec(QMetaType::fromType<QVariant>(), alternatives.first()->expected())
|
||||
, m_alternatives(alternatives)
|
||||
, m_expectedTypes(expectedTypesOf(alternatives)) {
|
||||
m_byType.reserve(alternatives.size());
|
||||
: ValueCodec(
|
||||
QMetaType::fromType<QVariant>(), alternatives.first()->expected())
|
||||
, m_alternatives(alternatives)
|
||||
, m_expectedTypes(expectedTypesOf(alternatives)) {
|
||||
m_byType.reserve(alternatives.size());
|
||||
|
||||
for (const auto* codec : alternatives)
|
||||
m_byType.insert(codec->type().id(), codec);
|
||||
for (const auto* codec : alternatives)
|
||||
m_byType.insert(codec->type().id(), codec);
|
||||
}
|
||||
|
||||
QJsonValue UnionCodec::encode(const QVariant& value) const {
|
||||
// An unset union is simply absent from the file
|
||||
if (!value.isValid())
|
||||
return QJsonValue::Undefined;
|
||||
// An unset union is simply absent from the file
|
||||
if (!value.isValid()) return QJsonValue::Undefined;
|
||||
|
||||
const auto* codec = m_byType.value(value.metaType().id());
|
||||
if (!codec) {
|
||||
qCWarning(lcSettings, "Cannot encode value of type %s, it is not one of the allowed types", value.typeName());
|
||||
return QJsonValue::Undefined;
|
||||
}
|
||||
const auto* codec = m_byType.value(value.metaType().id());
|
||||
if (!codec) {
|
||||
qCWarning(
|
||||
lcSettings,
|
||||
"Cannot encode value of type %s, it is not one of the allowed "
|
||||
"types",
|
||||
value.typeName());
|
||||
return QJsonValue::Undefined;
|
||||
}
|
||||
|
||||
return codec->encode(value);
|
||||
return codec->encode(value);
|
||||
}
|
||||
|
||||
DecodeResult UnionCodec::decode(const QJsonValue& value) const {
|
||||
std::optional<DecodeResult> best;
|
||||
std::optional<DecodeResult> best;
|
||||
|
||||
for (const auto* codec : m_alternatives) {
|
||||
auto result = codec->decode(value);
|
||||
for (const auto* codec : m_alternatives) {
|
||||
auto result = codec->decode(value);
|
||||
|
||||
// The first alternative to accept the value wins
|
||||
if (!result.error)
|
||||
return result;
|
||||
// The first alternative to accept the value wins
|
||||
if (!result.error) return result;
|
||||
|
||||
// Non-nested type mismatch just means try another alternative
|
||||
if (result.indexPath.isEmpty() && result.error->type == DiagnosticType::TypeMismatch)
|
||||
continue;
|
||||
// Non-nested type mismatch just means try another alternative
|
||||
if (result.indexPath.isEmpty() &&
|
||||
result.error->type == DiagnosticType::TypeMismatch)
|
||||
continue;
|
||||
|
||||
// Report the deepest error that isn't a type mismatch
|
||||
if (!best || result.indexPath.size() > best->indexPath.size())
|
||||
best = std::move(result);
|
||||
}
|
||||
// Report the deepest error that isn't a type mismatch
|
||||
if (!best || result.indexPath.size() > best->indexPath.size())
|
||||
best = std::move(result);
|
||||
}
|
||||
|
||||
if (best)
|
||||
return *best;
|
||||
if (best) return *best;
|
||||
|
||||
// Nothing matched the shape, so report every alternative
|
||||
return mismatch(m_expectedTypes, value);
|
||||
// Nothing matched the shape, so report every alternative
|
||||
return mismatch(m_expectedTypes, value);
|
||||
}
|
||||
|
||||
// Instantiated for types as needed
|
||||
|
||||
Reference in New Issue
Block a user