41 lines
1.0 KiB
C++
41 lines
1.0 KiB
C++
#pragma once
|
|
|
|
#include <charconv>
|
|
#include <concepts>
|
|
#include <expected>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <system_error>
|
|
#include <type_traits>
|
|
|
|
#include <modulus/result.hpp>
|
|
|
|
#include <vamp_zero/errors.hpp>
|
|
|
|
|
|
namespace vamp_zero {
|
|
|
|
template <std::integral VALUE>
|
|
requires(!std::is_same_v<VALUE, std::bool_t>)
|
|
auto parse_integer(std::string_view text, std::string_view name) -> std::expected<VALUE, modulus::error> {
|
|
auto invalid = [&](std::string_view reason) {
|
|
return modulus::fail<VALUE>(
|
|
make_error(error_code::INVALID_ARGUMENT, std::string{name} + " " + std::string{reason}));
|
|
};
|
|
if (text.empty()) {
|
|
return invalid("must be an integer");
|
|
}
|
|
auto value = VALUE{};
|
|
auto end = text.data() + text.size();
|
|
auto parsed = std::from_chars(text.data(), end, value);
|
|
if (parsed.ec == std::errc::result_out_of_range) {
|
|
return invalid("is out of range");
|
|
}
|
|
if (parsed.ec != std::errc{} || parsed.ptr != end) {
|
|
return invalid("must be an integer");
|
|
}
|
|
return modulus::success(value);
|
|
}
|
|
|
|
}
|