sots-engine/src/game/data/fields.h

84 lines
2.7 KiB
C++

// game::data -- internal helper: typed reads of a Block's scalars that record
// a Problem when a value is present but has the wrong shape. Shared by the
// loaders; not part of the public API.
#pragma once
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "game/data/block.h"
#include "game/data/common.h"
namespace game::data::detail {
class Fields {
public:
Fields(const Block& b, std::string file, std::vector<Problem>& problems)
: b_(b), file_(std::move(file)), problems_(problems) {}
const Block& block() const { return b_; }
// Last occurrence wins for every accessor (the rule for repeated scalar keys).
std::string str(std::string_view key) const { return b_.str(key); }
std::optional<std::string> opt_str(std::string_view key) const { return b_.opt_str(key); }
std::vector<std::string> strs(std::string_view key) const { return b_.strs(key); }
std::string required_str(std::string_view key) {
const Attr* a = b_.find(key);
if (!a) {
missing(key);
return {};
}
return a->value;
}
std::optional<std::int64_t> opt_int(std::string_view key) {
const Attr* a = b_.find(key);
if (!a) return std::nullopt;
auto v = a->as_int();
if (!v) bad(*a, "expected an integer");
return v;
}
std::optional<double> opt_double(std::string_view key) {
const Attr* a = b_.find(key);
if (!a) return std::nullopt;
auto v = a->as_double();
if (!v) bad(*a, "expected a number");
return v;
}
std::optional<bool> opt_bool(std::string_view key) {
const Attr* a = b_.find(key);
if (!a) return std::nullopt;
auto v = a->as_bool();
if (!v) bad(*a, "expected true/false or 0/1");
return v;
}
void missing(std::string_view key) {
problems_.push_back({Problem::Kind::MissingKey, file_, b_.line, std::string(key),
"required key `" + std::string(key) + "` missing in block `" + b_.name + "`"});
}
void bad(const Attr& a, std::string_view what) {
problems_.push_back({Problem::Kind::BadValue, file_, a.line, a.key,
std::string(what) + " for `" + a.key + "`, got `" + a.value + "`"});
}
void problem(Problem::Kind kind, int line, std::string key, std::string message) {
problems_.push_back({kind, file_, line, std::move(key), std::move(message)});
}
Fields sub(const Block& child) const { return Fields(child, file_, problems_); }
private:
const Block& b_;
std::string file_;
std::vector<Problem>& problems_;
};
} // namespace game::data::detail