libikarus/src/ikarus/errors.hpp

174 lines
7.6 KiB
C++

#pragma once
#include <string_view>
#include <type_traits>
#include <ikarus/errors.h>
void safe_strcpy(
std::string_view const src,
char * dest,
size_t const dest_size
);
#define IKARUS_VOID_RETURN
#define IKARUS_SET_ERROR(msg, err_info) \
if (error_out != nullptr) { \
safe_strcpy( \
msg, \
static_cast<char *>(error_out->message), \
IKARUS_ERROR_DATA_MAX_MESSAGE_LIMIT \
); \
error_out->info = err_info; \
}
#define IKARUS_FAIL(ret, msg, err_info) \
IKARUS_SET_ERROR(msg, err_info); \
return ret
#define IKARUS_FAIL_IF(condition, ret, msg, err_info) \
if (condition) { \
IKARUS_SET_ERROR(msg, err_info) \
return ret; \
}
#define IKARUS_TRY_OR_FAIL_IMPL(var_name, msg, err_info, ...) \
auto var_name = __VA_ARGS__; \
if (var_name.is_error()) { \
IKARUS_SET_ERROR( \
fmt::format( \
fmt::runtime(msg), \
std::move(var_name).unwrap_error() \
), \
err_info \
); \
return var_name; \
}
#define IKARUS_TRY_OR_FAIL(msg, err_info, ...) \
IKARUS_TRY_OR_FAIL_IMPL( \
CPPBASE_UNIQUE_NAME(result), \
msg, \
err_info, \
__VA_ARGS__ \
);
#define IKARUS_TRYRV_OR_FAIL_IMPL(var_name, ret, msg, err_info, ...) \
auto var_name = __VA_ARGS__; \
if (var_name.is_error()) { \
IKARUS_SET_ERROR( \
fmt::format( \
fmt::runtime(msg), \
std::move(var_name).unwrap_error() \
), \
err_info \
); \
return ret; \
}
#define IKARUS_TRYRV_OR_FAIL(ret, msg, err_info, ...) \
IKARUS_TRYRV_OR_FAIL_IMPL( \
CPPBASE_UNIQUE_NAME(result), \
ret, \
msg, \
err_info, \
__VA_ARGS__ \
);
#define IKARUS_VTRY_OR_FAIL_IMPL(var_name, value, msg, err_info, ...) \
auto var_name = __VA_ARGS__; \
if (var_name.is_error()) { \
IKARUS_SET_ERROR( \
fmt::format( \
fmt::runtime(msg), \
std::move(var_name).unwrap_error() \
), \
err_info \
); \
return var_name; \
} \
value = std::move(var_name).unwrap_value()
#define IKARUS_VTRY_OR_FAIL(value, msg, err_info, ...) \
IKARUS_VTRY_OR_FAIL_IMPL( \
CPPBASE_UNIQUE_NAME(result), \
value, \
msg, \
err_info, \
__VA_ARGS__ \
);
#define IKARUS_VTRYRV_OR_FAIL_IMPL(var_name, value, ret, msg, err_info, ...) \
auto var_name = __VA_ARGS__; \
if (var_name.is_error()) { \
IKARUS_SET_ERROR( \
fmt::format(fmt::runtime(msg), var_name.unwrap_error()), \
err_info \
); \
return ret; \
} \
value = std::move(var_name).unwrap_value()
#define IKARUS_VTRYRV_OR_FAIL(value, ret, msg, err_info, ...) \
IKARUS_VTRYRV_OR_FAIL_IMPL( \
CPPBASE_UNIQUE_NAME(result), \
value, \
ret, \
msg, \
err_info, \
__VA_ARGS__ \
);
#define IKARUS_FAIL_IF_ERROR(ret) \
if (ikarus_error_data_is_error(error_out)) { \
return ret; \
}
#define IKARUS_FAIL_IF_NULL(ptr, ret) \
IKARUS_FAIL_IF( \
((ptr) == nullptr), \
ret, \
#ptr " must not be null", \
IkarusErrorInfo_Client_InvalidNull \
)
#define IKARUS_FAIL_IF_NAME_INVALID(name, ret) \
IKARUS_FAIL_IF_NULL(name, ret); \
IKARUS_FAIL_IF( \
cppbase::is_empty_or_blank(name), \
ret, \
#name " must not be empty", \
IkarusErrorInfo_Client_InvalidInput \
);
#define IKARUS_FAIL_IF_NOT_EXIST_IMPL(exists_name, object, ret) \
IKARUS_VTRYRV_OR_FAIL( \
auto exists_name, \
ret, \
fmt::format( \
"failed to check if {} exists", \
std::remove_cvref_t<decltype(*object)>::object_name \
), \
IkarusErrorInfo_Database_QueryFailed, \
object->project->db->query_one<bool>( \
fmt::format( \
"SELECT EXISTS(SELECT 1 FROM `{}` WHERE `id` = ?)", \
std::remove_cvref_t<decltype(*object)>::table_name \
), \
object->id \
) \
); \
\
IKARUS_FAIL_IF( \
!exists_name, \
ret, \
fmt::format( \
"{} doesn't exist", \
std::remove_cvref_t<decltype(*object)>::object_name \
), \
IkarusErrorInfo_Client_NonExistent \
)
#define IKARUS_FAIL_IF_NOT_EXIST(object, ret) \
IKARUS_FAIL_IF_NOT_EXIST_IMPL(CPPBASE_UNIQUE_NAME(exists), object, ret)