Porytiles
Loading...
Searching...
No Matches
cli_option_provider_impl.ipp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cctype>
5#include <charconv>
6#include <format>
7#include <optional>
8#include <sstream>
9#include <string>
10#include <vector>
11
24
25// The anonymous namespace ensures internal linkage per translation unit
26// This file is intentionally included only in cli_option_provider.cpp
27namespace {
28
29using namespace porytiles;
30
42LayerValue<std::size_t> parse_size_t(const std::optional<std::string> &raw_value, const std::string &option_name)
43{
44 if (!raw_value.has_value()) {
46 }
47
48 const auto &str = raw_value.value();
49
50 // Use std::from_chars for efficient, locale-independent parsing
51 std::size_t value = 0;
52 const auto *begin = str.data();
53 const auto *end = str.data() + str.size();
54 auto [ptr, ec] = std::from_chars(begin, end, value);
55
56 if (ec == std::errc{} && ptr == end) {
57 return LayerValue<std::size_t>::valid(value, option_name, "CLI");
58 }
59
60 if (ec == std::errc::result_out_of_range) {
61 const auto error = std::format("Invalid value '{}' for '{}': value out of range.", str, option_name);
62 return LayerValue<std::size_t>::invalid(error, option_name);
63 }
64
65 // Invalid argument or trailing characters
66 const auto error = std::format("Invalid value '{}' for '{}': not a valid integer.", str, option_name);
67 return LayerValue<std::size_t>::invalid(error, option_name);
68}
69
81LayerValue<bool> parse_bool(const std::optional<std::string> &raw_value, const std::string &option_name)
82{
83 if (!raw_value.has_value()) {
85 }
86
87 const auto &str = raw_value.value();
88
89 if (str == "true") {
90 return LayerValue<bool>::valid(true, option_name, "CLI");
91 }
92 if (str == "false") {
93 return LayerValue<bool>::valid(false, option_name, "CLI");
94 }
95
96 const auto error = std::format("Invalid value '{}' for '{}': expected 'true' or 'false'.", str, option_name);
97 return LayerValue<bool>::invalid(error, option_name);
98}
99
111LayerValue<Rgba32> parse_rgba32(const std::optional<std::string> &raw_value, const std::string &option_name)
112{
113 if (!raw_value.has_value()) {
115 }
116
117 const auto &input = raw_value.value();
118 std::istringstream iss{input};
119 std::string token;
120 std::vector<int> values;
121
122 while (std::getline(iss, token, ',')) {
123 // Use std::from_chars for robust integer parsing
124 int val = 0;
125 const auto *begin = token.data();
126 const auto *end = token.data() + token.size();
127 auto [ptr, ec] = std::from_chars(begin, end, val);
128
129 if (ec != std::errc{} || ptr != end) {
130 const auto error =
131 std::format("Invalid value '{}' for '{}': '{}' is not a valid integer.", input, option_name, token);
132 return LayerValue<Rgba32>::invalid(error, option_name);
133 }
134
135 if (val < 0 || val > 255) {
136 const auto error = std::format(
137 "Invalid value '{}' for '{}': component {} is out of range (must be 0-255).", input, option_name, val);
138 return LayerValue<Rgba32>::invalid(error, option_name);
139 }
140
141 values.push_back(val);
142 }
143
144 if (values.size() == 3) {
145 Rgba32 result{
146 static_cast<std::uint8_t>(values[0]),
147 static_cast<std::uint8_t>(values[1]),
148 static_cast<std::uint8_t>(values[2]),
149 255};
150 return LayerValue<Rgba32>::valid(result, option_name, "CLI");
151 }
152
153 if (values.size() == 4) {
154 Rgba32 result{
155 static_cast<std::uint8_t>(values[0]),
156 static_cast<std::uint8_t>(values[1]),
157 static_cast<std::uint8_t>(values[2]),
158 static_cast<std::uint8_t>(values[3])};
159 return LayerValue<Rgba32>::valid(result, option_name, "CLI");
160 }
161
162 const auto error = std::format(
163 "Invalid value '{}' for '{}': expected R,G,B or R,G,B,A format (got {} components).",
164 input,
165 option_name,
166 values.size());
167 return LayerValue<Rgba32>::invalid(error, option_name);
168}
169
180LayerValue<std::string> parse_string(const std::optional<std::string> &raw_value, const std::string &option_name)
181{
182 if (!raw_value.has_value()) {
184 }
185
186 return LayerValue<std::string>::valid(raw_value.value(), option_name, "CLI");
187}
188
204parse_string_vector(const std::vector<std::string> &raw_values, const std::string &option_name)
205{
206 if (raw_values.empty()) {
208 }
209 return LayerValue<std::vector<std::string>>::valid(raw_values, option_name, "CLI");
210}
211
225parse_artifact_edit_mode(const std::optional<std::string> &raw_value, const std::string &option_name)
226{
227 if (!raw_value.has_value()) {
229 }
230
231 const auto &str = raw_value.value();
232 const auto result = artifact_edit_mode_from_str(str);
233
234 if (result.has_value()) {
235 return LayerValue<ArtifactEditMode>::valid(result.value(), option_name, "CLI");
236 }
237
238 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
239 return LayerValue<ArtifactEditMode>::invalid(error, option_name);
240}
241
254parse_tiles_pal_mode(const std::optional<std::string> &raw_value, const std::string &option_name)
255{
256 if (!raw_value.has_value()) {
258 }
259
260 const auto &str = raw_value.value();
261 const auto result = tiles_pal_mode_from_str(str);
262
263 if (result.has_value()) {
264 return LayerValue<TilesPalMode>::valid(result.value(), option_name, "CLI");
265 }
266
267 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
268 return LayerValue<TilesPalMode>::invalid(error, option_name);
269}
270
283parse_anim_pal_resolution_strategy(const std::optional<std::string> &raw_value, const std::string &option_name)
284{
285 if (!raw_value.has_value()) {
287 }
288
289 const auto &str = raw_value.value();
290 const auto result = anim_pal_resolution_strategy_from_str(str);
291
292 if (result.has_value()) {
293 return LayerValue<AnimPalResolutionStrategy>::valid(result.value(), option_name, "CLI");
294 }
295
296 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
298}
299
312parse_anim_key_frame_resolution_strategy(const std::optional<std::string> &raw_value, const std::string &option_name)
313{
314 if (!raw_value.has_value()) {
316 }
317
318 const auto &str = raw_value.value();
319 const auto result = anim_key_frame_resolution_strategy_from_str(str);
320
321 if (result.has_value()) {
322 return LayerValue<AnimKeyFrameResolutionStrategy>::valid(result.value(), option_name, "CLI");
323 }
324
325 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
327}
328
340LayerValue<AnimMultiPalSubtileResolutionStrategy> parse_anim_multi_pal_subtile_resolution_strategy(
341 const std::optional<std::string> &raw_value, const std::string &option_name)
342{
343 if (!raw_value.has_value()) {
345 }
346
347 const auto &str = raw_value.value();
349
350 if (result.has_value()) {
351 return LayerValue<AnimMultiPalSubtileResolutionStrategy>::valid(result.value(), option_name, "CLI");
352 }
353
354 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
356}
357
370parse_frame_linking(const std::optional<std::string> &raw_value, const std::string &option_name)
371{
372 if (!raw_value.has_value()) {
374 }
375
376 const auto &str = raw_value.value();
377 const auto result = frame_linking_from_str(str);
378
379 if (result.has_value()) {
380 return LayerValue<FrameLinking>::valid(result.value(), option_name, "CLI");
381 }
382
383 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
384 return LayerValue<FrameLinking>::invalid(error, option_name);
385}
386
399parse_tile_sharing_packing(const std::optional<std::string> &raw_value, const std::string &option_name)
400{
401 if (!raw_value.has_value()) {
403 }
404
405 const auto &str = raw_value.value();
406 const auto result = tile_sharing_packing_from_str(str);
407
408 if (result.has_value()) {
409 return LayerValue<TileSharingPacking>::valid(result.value(), option_name, "CLI");
410 }
411
412 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
414}
415
428parse_tile_sharing_alignment(const std::optional<std::string> &raw_value, const std::string &option_name)
429{
430 if (!raw_value.has_value()) {
432 }
433
434 const auto &str = raw_value.value();
435 const auto result = tile_sharing_alignment_from_str(str);
436
437 if (result.has_value()) {
438 return LayerValue<TileSharingAlignment>::valid(result.value(), option_name, "CLI");
439 }
440
441 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
443}
444
446parse_packing_strategy_type(const std::optional<std::string> &raw_value, const std::string &option_name)
447{
448 if (!raw_value.has_value()) {
450 }
451
452 const auto &str = raw_value.value();
453 const auto result = packing_strategy_type_from_str(str);
454
455 if (result.has_value()) {
456 return LayerValue<PackingStrategyType>::valid(result.value(), option_name, "CLI");
457 }
458
459 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
461}
462
464parse_primary_pairing_mode(const std::optional<std::string> &raw_value, const std::string &option_name)
465{
466 if (!raw_value.has_value()) {
468 }
469
470 const auto &str = raw_value.value();
471 const auto result = primary_pairing_mode_from_str(str);
472
473 if (result.has_value()) {
474 return LayerValue<PrimaryPairingMode>::valid(result.value(), option_name, "CLI");
475 }
476
477 const auto error = std::format("Invalid value '{}' for '{}'.", str, option_name);
479}
480
481} // namespace
Represents a 32-bit RGBA color.
Definition rgba32.hpp:23
std::size_t end
std::optional< TilesPalMode > tiles_pal_mode_from_str(const std::string &str)
Parses a string into a TilesPalMode with fuzzy matching.
std::optional< ArtifactEditMode > artifact_edit_mode_from_str(const std::string &str)
Parses a string into a ArtifactEditMode with fuzzy matching.
std::optional< PackingStrategyType > packing_strategy_type_from_str(const std::string &str)
Parses a string into a PackingStrategyType with fuzzy matching.
std::optional< FrameLinking > frame_linking_from_str(const std::string &str)
Parses a string into a FrameLinking with fuzzy matching.
std::optional< PrimaryPairingMode > primary_pairing_mode_from_str(const std::string &str)
Parses a string into a PrimaryPairingMode with fuzzy matching.
std::optional< AnimPalResolutionStrategy > anim_pal_resolution_strategy_from_str(const std::string &str)
Parses a string into a AnimPalResolutionStrategy with fuzzy matching.
@ error
Emit a formatted error and fail decompilation.
std::optional< TileSharingPacking > tile_sharing_packing_from_str(const std::string &str)
Parses a string into a TileSharingPacking with fuzzy matching.
std::optional< TileSharingAlignment > tile_sharing_alignment_from_str(const std::string &str)
Parses a string into a TileSharingAlignment with fuzzy matching.
std::optional< AnimMultiPalSubtileResolutionStrategy > anim_multi_pal_subtile_resolution_strategy_from_str(const std::string &str)
Parses a string into a AnimMultiPalSubtileResolutionStrategy with fuzzy matching.
std::optional< AnimKeyFrameResolutionStrategy > anim_key_frame_resolution_strategy_from_str(const std::string &str)
Parses a string into a AnimKeyFrameResolutionStrategy with fuzzy matching.
A small container that holds an optional-wrapped value, validation state, and metadata about the valu...
static LayerValue valid(T val, std::string source_key, std::string source_info)
Creates a LayerValue representing a valid configuration value.
static LayerValue not_provided()
Creates a LayerValue representing that the provider does not supply this configuration.
static LayerValue invalid(std::string error, std::string source_info)
Creates a LayerValue representing an invalid configuration value.