VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
Validation.hpp
Go to the documentation of this file.
1#pragma once
2
5#include <concepts>
6#include <cstddef>
7#include <format>
8#include <optional>
9#include <string>
10#include <string_view>
11#include <vector>
12
14{
15
16/**
17 * @brief Declarative helpers for post-load config validation: skip bad entries with a
18 * warning instead of failing the whole load, and fall back to sane defaults.
19 */
20
21/** Reset @p value to @p fallback (warning names @p what) when it is blank or longer than @p maxLen. */
22inline void NormalizeTag(std::string& value, std::size_t maxLen, std::string_view fallback, std::string_view what)
23{
24 if (!Strings::Trim(value).empty() && value.size() <= maxLen)
25 {
26 return;
27 }
28
29 Log::Warn("settings: {} is empty or longer than {} chars; using \"{}\"", what, maxLen, fallback);
30 value = std::string(fallback);
31}
32
33/** Keep only items where @p validate returns nullopt; each rejection logs the reason it returned. */
34template <class T>
35void FilterValid(std::vector<T>& items, std::invocable<const T&, std::size_t> auto&& validate, std::string_view what)
36{
37 std::vector<T> kept;
38 kept.reserve(items.size());
39 for (std::size_t i = 0; i < items.size(); ++i)
40 {
41 if (auto reason = validate(items[i], i))
42 {
43 Log::Warn("settings: skipping {}[{}]: {}", what, i, *reason);
44 }
45 else
46 {
47 kept.push_back(std::move(items[i]));
48 }
49 }
50 items = std::move(kept);
51}
52
53/** Restore @p defaults (warning names @p what) when filtering left @p items empty, so a list that
54 * would dead-end a menu falls back instead. Returns true when the defaults were applied. */
55template <class T>
56bool FallbackIfEmpty(std::vector<T>& items, const std::vector<T>& defaults, std::string_view what)
57{
58 if (!items.empty() || defaults.empty())
59 {
60 return false;
61 }
62
63 Log::Warn("settings: {} has no valid entries; using built-in defaults", what);
64 items = defaults;
65 return true;
66}
67
68/** As above, but @p makeDefaults runs only when the fallback is needed and its result is moved
69 * rather than copied. Prefer it when building the defaults costs anything - passing them by value
70 * makes every caller build a list it almost always discards. */
71template <class T>
72bool FallbackIfEmpty(std::vector<T>& items, std::invocable auto&& makeDefaults, std::string_view what)
73{
74 if (!items.empty())
75 {
76 return false;
77 }
78
79 auto defaults = makeDefaults();
80 if (defaults.empty())
81 {
82 return false;
83 }
84
85 Log::Warn("settings: {} has no valid entries; using built-in defaults", what);
86 items = std::move(defaults);
87 return true;
88}
89
90/** Parse @ref ParseDuration strings, dropping invalid entries with warnings. Falls back to
91 * parsing @p defaults when nothing valid remains (so the list exists in exactly one place). */
92inline std::vector<int> ParseDurations(const std::vector<std::string>& entries,
93 const std::vector<std::string>& defaults, std::string_view what)
94{
95 std::vector<std::string> kept = entries;
97 kept,
98 [](const std::string& entry, std::size_t) -> std::optional<std::string> {
99 if (ParseDuration(entry) < 0)
100 {
101 return std::format("bad duration '{}'", entry);
102 }
103 return std::nullopt;
104 },
105 what);
107
108 std::vector<int> result;
109 result.reserve(kept.size());
110 for (const auto& entry : kept)
111 {
112 result.push_back(ParseDuration(entry));
113 }
114 return result;
115}
116
117} // namespace VoltMod::Validation
static std::string Trim(std::string_view str)
Definition Strings.cpp:107
void Warn(std::format_string< Args... > fmt, Args &&... args)
Definition Log.hpp:88
void NormalizeTag(std::string &value, std::size_t maxLen, std::string_view fallback, std::string_view what)
Declarative helpers for post-load config validation: skip bad entries with a warning instead of faili...
void FilterValid(std::vector< T > &items, std::invocable< const T &, std::size_t > auto &&validate, std::string_view what)
bool FallbackIfEmpty(std::vector< T > &items, const std::vector< T > &defaults, std::string_view what)
std::vector< int > ParseDurations(const std::vector< std::string > &entries, const std::vector< std::string > &defaults, std::string_view what)
int ParseDuration(std::string_view text)
Definition Strings.cpp:35
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56