This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <modulus/config.hpp>
|
||||
#include <modulus/error.hpp>
|
||||
#include <modulus/json_config.hpp>
|
||||
#include <modulus/log.hpp>
|
||||
#include <modulus/result.hpp>
|
||||
#include <modulus/source_location.hpp>
|
||||
#include <modulus/types.hpp>
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
#include <modulus/error.hpp>
|
||||
#include <modulus/log.hpp>
|
||||
|
||||
namespace modulus {
|
||||
|
||||
struct logging_config {
|
||||
modulus::log_level level{modulus::log_level::INFO};
|
||||
};
|
||||
|
||||
struct config {
|
||||
modulus::logging_config logging{};
|
||||
modulus::error_config errors{};
|
||||
};
|
||||
|
||||
auto parse_logging_config(boost::json::value const& value) -> std::expected<modulus::logging_config, modulus::error>;
|
||||
auto parse_error_config(boost::json::value const& value) -> std::expected<modulus::error_config, modulus::error>;
|
||||
auto parse_config(boost::json::value const& value) -> std::expected<modulus::config, modulus::error>;
|
||||
auto load_config(std::string const& path) -> std::expected<modulus::config, modulus::error>;
|
||||
auto to_json(modulus::logging_config const& config) -> boost::json::value;
|
||||
auto to_json(modulus::error_config const& config) -> boost::json::value;
|
||||
auto to_json(modulus::config const& config) -> boost::json::value;
|
||||
auto configure_logger(modulus::logger& logger, modulus::logging_config const& config) -> void;
|
||||
auto configure(modulus::config const& config) -> void;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <modulus/source_location.hpp>
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
namespace modulus {
|
||||
|
||||
struct error_config {
|
||||
std::bool_t include_category{true};
|
||||
std::bool_t include_code{true};
|
||||
std::bool_t include_message{true};
|
||||
std::bool_t include_location{true};
|
||||
};
|
||||
|
||||
class error {
|
||||
public:
|
||||
error() = default;
|
||||
error(std::string category, std::int32_t code, std::string message, modulus::source_location location = modulus::source_location( __builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION()));
|
||||
auto category() const noexcept -> std::string_view;
|
||||
auto code() const noexcept -> std::int32_t;
|
||||
auto message() const noexcept -> std::string_view;
|
||||
auto location() const noexcept -> const modulus::source_location&;
|
||||
auto describe(modulus::error_config const& config) const -> std::string;
|
||||
auto describe() const -> std::string;
|
||||
private:
|
||||
std::string category_{"generic"};
|
||||
std::int32_t code_{};
|
||||
std::string message_{};
|
||||
modulus::source_location location_{modulus::source_location::unknown()};
|
||||
};
|
||||
|
||||
auto make_error(std::string category, std::int32_t code, std::string message, modulus::source_location location = modulus::source_location( __builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> modulus::error;
|
||||
auto set_default_error_config(modulus::error_config config) -> void;
|
||||
auto default_error_config() -> modulus::error_config;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
#include <modulus/error.hpp>
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
namespace modulus::json_config {
|
||||
|
||||
struct options {
|
||||
std::string_view category{"modulus.config"};
|
||||
std::int32_t invalid_argument_code{1};
|
||||
std::int32_t not_found_code{2};
|
||||
};
|
||||
|
||||
template <typename ENUM>
|
||||
struct enum_mapping {
|
||||
std::string_view name{};
|
||||
ENUM value{};
|
||||
};
|
||||
|
||||
auto invalid(modulus::json_config::options config, std::string message) -> modulus::error;
|
||||
auto not_found(modulus::json_config::options config, std::string message) -> modulus::error;
|
||||
auto load_value(std::string const& path, modulus::json_config::options config = {}) -> std::expected<boost::json::value, modulus::error>;
|
||||
auto require_object(boost::json::value const& value, std::string_view context, modulus::json_config::options config = {}) -> std::expected<boost::json::object const*, modulus::error>;
|
||||
auto reject_unknown_fields(boost::json::object const& object, std::initializer_list<std::string_view> allowed, std::string_view context, modulus::json_config::options config = {}) -> std::expected<void, modulus::error>;
|
||||
auto optional_bool_field(boost::json::object const& object, std::string_view name, std::bool_t fallback, modulus::json_config::options config = {}) -> std::expected<std::bool_t, modulus::error>;
|
||||
auto optional_string_field(boost::json::object const& object, std::string_view name, std::string fallback, modulus::json_config::options config = {}) -> std::expected<std::string, modulus::error>;
|
||||
auto required_string_field(boost::json::object const& object, std::string_view name, std::string_view context, modulus::json_config::options config = {}) -> std::expected<std::string, modulus::error>;
|
||||
auto optional_uint64_field(boost::json::object const& object, std::string_view name, std::uint64_t fallback, std::uint64_t max_value, modulus::json_config::options config = {}) -> std::expected<std::uint64_t, modulus::error>;
|
||||
auto positive_uint64_field(boost::json::object const& object, std::string_view name, std::uint64_t fallback, std::uint64_t max_value, modulus::json_config::options config = {}) -> std::expected<std::uint64_t, modulus::error>;
|
||||
auto optional_int32_field(boost::json::object const& object, std::string_view name, std::int32_t fallback, std::int32_t min_value, std::int32_t max_value, modulus::json_config::options config = {}) -> std::expected<std::int32_t, modulus::error>;
|
||||
auto positive_milliseconds_field(boost::json::object const& object, std::string_view name, std::chrono::milliseconds fallback, std::uint64_t max_value = static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max()), modulus::json_config::options config = {}) -> std::expected<std::chrono::milliseconds, modulus::error>;
|
||||
|
||||
template <typename ENUM>
|
||||
auto parse_enum(std::string_view value, std::initializer_list<modulus::json_config::enum_mapping<ENUM>> mappings, std::string_view message, modulus::json_config::options config = {}) -> std::expected<ENUM, modulus::error>;
|
||||
|
||||
template <typename ENUM>
|
||||
auto optional_enum_field(boost::json::object const& object, std::string_view name, ENUM fallback, std::initializer_list<modulus::json_config::enum_mapping<ENUM>> mappings, std::string_view message, modulus::json_config::options config = {}) -> std::expected<ENUM, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
template <typename ENUM>
|
||||
auto modulus::json_config::parse_enum(std::string_view value, std::initializer_list<modulus::json_config::enum_mapping<ENUM>> mappings, std::string_view message, modulus::json_config::options config) -> std::expected<ENUM, modulus::error> {
|
||||
for (auto mapping : mappings) {
|
||||
if (value == mapping.name) {
|
||||
return mapping.value;
|
||||
}
|
||||
}
|
||||
return std::unexpected(modulus::json_config::invalid(config, std::string{message}));
|
||||
}
|
||||
|
||||
template <typename ENUM>
|
||||
auto modulus::json_config::optional_enum_field(boost::json::object const& object, std::string_view name, ENUM fallback, std::initializer_list<modulus::json_config::enum_mapping<ENUM>> mappings, std::string_view message, modulus::json_config::options config) -> std::expected<ENUM, modulus::error> {
|
||||
auto found = object.find(name);
|
||||
if (found == object.end()) {
|
||||
return fallback;
|
||||
}
|
||||
if (!found->value().is_string()) {
|
||||
return std::unexpected(modulus::json_config::invalid(config, std::string{name} + " must be a string"));
|
||||
}
|
||||
return modulus::json_config::parse_enum(std::string_view{found->value().as_string()}, mappings, message, config);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <modulus/source_location.hpp>
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
namespace modulus {
|
||||
|
||||
enum class log_level : std::int32_t {
|
||||
TRACE,
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR,
|
||||
CRITICAL,
|
||||
OFF,
|
||||
};
|
||||
|
||||
auto to_string(modulus::log_level level) noexcept -> std::string_view;
|
||||
|
||||
struct log_record {
|
||||
modulus::log_level level{modulus::log_level::INFO};
|
||||
std::string message{};
|
||||
modulus::source_location location{modulus::source_location::unknown()};
|
||||
std::chrono::system_clock::time_point timestamp{std::chrono::system_clock::now()};
|
||||
std::thread::id thread_id{std::this_thread::get_id()};
|
||||
};
|
||||
|
||||
class logger {
|
||||
public:
|
||||
logger();
|
||||
auto set_level(modulus::log_level level) -> void;
|
||||
auto level() const -> modulus::log_level;
|
||||
auto enabled(modulus::log_level level) const -> std::bool_t;
|
||||
auto set_sink(std::function<void(const modulus::log_record&)> sink) -> void;
|
||||
auto write(modulus::log_record record) const -> void;
|
||||
auto log(modulus::log_level level, std::string message, modulus::source_location location = modulus::source_location( __builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) const -> void;
|
||||
private:
|
||||
mutable std::mutex mutex_;
|
||||
mutable std::mutex sink_mutex_;
|
||||
modulus::log_level level_{modulus::log_level::INFO};
|
||||
std::function<void(const modulus::log_record&)> sink_{};
|
||||
};
|
||||
|
||||
auto default_logger() -> modulus::logger&;
|
||||
auto set_default_log_level(modulus::log_level level) -> void;
|
||||
auto is_log_enabled(modulus::log_level level) -> std::bool_t;
|
||||
auto log(modulus::log_level level, std::string message, modulus::source_location location = modulus::source_location( __builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
auto log_trace(std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
auto log_debug(std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
auto log_info(std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
auto log_warn(std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
auto log_error(std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
auto log_critical(std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
|
||||
template <typename MESSAGE>
|
||||
auto log_lazy(modulus::log_level level, MESSAGE&& message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> void;
|
||||
|
||||
}
|
||||
|
||||
template <typename MESSAGE>
|
||||
auto modulus::log_lazy(modulus::log_level level, MESSAGE&& message, modulus::source_location location) -> void {
|
||||
assert(static_cast<std::int32_t>(level) >= static_cast<std::int32_t>(modulus::log_level::TRACE));
|
||||
assert(static_cast<std::int32_t>(level) <= static_cast<std::int32_t>(modulus::log_level::OFF));
|
||||
assert(location.file_name() != nullptr);
|
||||
assert(location.function_name() != nullptr);
|
||||
if (modulus::is_log_enabled(level)) {
|
||||
modulus::log(level, std::string(std::forward<MESSAGE>(message)()), location);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <expected>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <modulus/error.hpp>
|
||||
|
||||
namespace modulus {
|
||||
|
||||
template <typename VALUE>
|
||||
auto success(VALUE&& value) -> std::expected<std::decay_t<VALUE>, modulus::error>;
|
||||
|
||||
template <typename VALUE>
|
||||
auto fail(modulus::error value) -> std::expected<VALUE, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
template <typename VALUE>
|
||||
auto modulus::success(VALUE&& value) -> std::expected<std::decay_t<VALUE>, modulus::error> {
|
||||
return std::forward<VALUE>(value);
|
||||
}
|
||||
|
||||
template <typename VALUE>
|
||||
auto modulus::fail(modulus::error value) -> std::expected<VALUE, modulus::error> {
|
||||
assert(!value.category().empty());
|
||||
return std::unexpected<modulus::error>(std::move(value));
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
namespace modulus {
|
||||
|
||||
class source_location {
|
||||
public:
|
||||
constexpr source_location() noexcept = default;
|
||||
constexpr source_location(std::char_t const* file, std::uint_least32_t line, std::char_t const* function) noexcept;
|
||||
static consteval auto current(std::char_t const* file = __builtin_FILE(), std::uint_least32_t line = __builtin_LINE(), std::char_t const* function = __builtin_FUNCTION()) noexcept -> modulus::source_location;
|
||||
static constexpr auto unknown() noexcept -> modulus::source_location;
|
||||
constexpr auto file_name() const noexcept -> std::char_t const*;
|
||||
constexpr auto line() const noexcept -> std::uint_least32_t;
|
||||
constexpr auto function_name() const noexcept -> std::char_t const*;
|
||||
private:
|
||||
std::char_t const* file_{"<unknown>"};
|
||||
std::uint_least32_t line_{};
|
||||
std::char_t const* function_{"<unknown>"};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
constexpr modulus::source_location::source_location(std::char_t const* file, std::uint_least32_t line, std::char_t const* function) noexcept : file_(file), line_(line), function_(function) {
|
||||
assert(file != nullptr);
|
||||
assert(function != nullptr);
|
||||
}
|
||||
|
||||
consteval auto modulus::source_location::current(std::char_t const* file, std::uint_least32_t line, std::char_t const* function) noexcept -> modulus::source_location {
|
||||
assert(file != nullptr);
|
||||
assert(function != nullptr);
|
||||
return modulus::source_location(file, line, function);
|
||||
}
|
||||
|
||||
constexpr auto modulus::source_location::unknown() noexcept -> modulus::source_location {
|
||||
return modulus::source_location();
|
||||
}
|
||||
|
||||
constexpr auto modulus::source_location::file_name() const noexcept -> std::char_t const* {
|
||||
assert(file_ != nullptr);
|
||||
return file_;
|
||||
}
|
||||
|
||||
constexpr auto modulus::source_location::line() const noexcept -> std::uint_least32_t {
|
||||
assert(file_ != nullptr);
|
||||
return line_;
|
||||
}
|
||||
|
||||
constexpr auto modulus::source_location::function_name() const noexcept -> std::char_t const* {
|
||||
assert(function_ != nullptr);
|
||||
return function_;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__has_include)
|
||||
# if __has_include(<stdfloat>)
|
||||
# include <stdfloat>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace std {
|
||||
|
||||
using bool_t = decltype(true);
|
||||
using char_t = decltype('x');
|
||||
using uchar_t = std::uint8_t;
|
||||
|
||||
#if !defined(__STDCPP_FLOAT32_T__)
|
||||
using float32_t = decltype(0.0F);
|
||||
#endif
|
||||
|
||||
#if !defined(__STDCPP_FLOAT64_T__)
|
||||
using float64_t = decltype(0.0);
|
||||
#endif
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user