You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
3.1 KiB
106 lines
3.1 KiB
#pragma once |
|
|
|
#include <array> |
|
#include <string_view> |
|
#include <type_traits> |
|
|
|
#include <expected.hpp> |
|
#include <function_ref.hpp> |
|
|
|
#include "data/file.hpp" |
|
#include "data/iterators.hpp" |
|
|
|
namespace devilution { |
|
|
|
/** |
|
* @brief A value reader. |
|
*/ |
|
class ValueReader { |
|
public: |
|
ValueReader(DataFile &dataFile, std::string_view filename); |
|
|
|
DataFileField getValueField(std::string_view expectedKey); |
|
|
|
template <typename T, typename F> |
|
void readValue(std::string_view expectedKey, T &outValue, F &&readFn) |
|
{ |
|
DataFileField valueField = getValueField(expectedKey); |
|
if (const tl::expected<void, devilution::DataFileField::Error> result = readFn(valueField, outValue); |
|
!result.has_value()) { |
|
DataFile::reportFatalFieldError(result.error(), filename_, "Value", valueField); |
|
} |
|
++it_; |
|
} |
|
|
|
template <typename T, typename F> |
|
void read(std::string_view expectedKey, T &outValue, F &&parseFn) |
|
{ |
|
readValue(expectedKey, outValue, [&parseFn](DataFileField &valueField, T &outValue) -> tl::expected<void, devilution::DataFileField::Error> { |
|
const auto result = parseFn(valueField.value()); |
|
if (!result.has_value()) { |
|
return tl::make_unexpected(devilution::DataFileField::Error::InvalidValue); |
|
} |
|
|
|
outValue = result.value(); |
|
return {}; |
|
}); |
|
} |
|
|
|
template <typename T, typename F> |
|
void readEnumList(std::string_view expectedKey, T &outValue, F &&parseFn) |
|
{ |
|
readValue(expectedKey, outValue, [&parseFn](DataFileField &valueField, T &outValue) -> tl::expected<void, devilution::DataFileField::Error> { |
|
const auto result = valueField.parseEnumList(outValue, std::forward<F>(parseFn)); |
|
if (!result.has_value()) { |
|
return tl::make_unexpected(devilution::DataFileField::Error::InvalidValue); |
|
} |
|
|
|
return {}; |
|
}); |
|
} |
|
|
|
template <typename T> |
|
typename std::enable_if_t<std::is_integral_v<T>, void> |
|
readInt(std::string_view expectedKey, T &outValue) |
|
{ |
|
readValue(expectedKey, outValue, [](DataFileField &valueField, T &outValue) { |
|
return valueField.parseInt(outValue); |
|
}); |
|
} |
|
|
|
template <typename T> |
|
typename std::enable_if_t<std::is_integral_v<T>, void> |
|
readDecimal(std::string_view expectedKey, T &outValue) |
|
{ |
|
readValue(expectedKey, outValue, [](DataFileField &valueField, T &outValue) { |
|
return valueField.parseFixed6(outValue); |
|
}); |
|
} |
|
|
|
void readString(std::string_view expectedKey, std::string &outValue) |
|
{ |
|
readValue(expectedKey, outValue, [](DataFileField &valueField, std::string &outValue) { |
|
outValue = valueField.value(); |
|
return tl::expected<void, devilution::DataFileField::Error> {}; |
|
}); |
|
} |
|
|
|
void readChar(std::string_view expectedKey, char &outValue) |
|
{ |
|
readValue(expectedKey, outValue, [](DataFileField &valueField, char &outValue) -> tl::expected<void, devilution::DataFileField::Error> { |
|
if (valueField.value().size() != 1) { |
|
return tl::make_unexpected(devilution::DataFileField::Error::InvalidValue); |
|
} |
|
|
|
outValue = valueField.value().at(0); |
|
return {}; |
|
}); |
|
} |
|
|
|
private: |
|
RecordIterator it_; |
|
const RecordIterator end_; |
|
std::string_view filename_; |
|
}; |
|
|
|
} // namespace devilution
|
|
|