// 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 #include #include #include #include #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& 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 opt_str(std::string_view key) const { return b_.opt_str(key); } std::vector 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 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 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 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& problems_; }; } // namespace game::data::detail