#pragma once #include #include inline void safe_strcpy(char * dest, std::string_view src, size_t dest_size) { for (int i = 0; i < dest_size; ++i) { if (src[i] == '\0') { dest[i] = '\0'; return; } dest[i] = src[i]; } } #define IKARUS_SET_ERROR(msg, err_info) \ if (error_out != nullptr) { \ safe_strcpy(static_cast(error_out->message), msg, 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_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_TRY_OR_FAIL_IMPL(var_name, msg, err_info, ...) \ auto var_name = __VA_ARGS__; \ if (var_name.is_error()) { \ IKARUS_SET_ERROR(fmt::format(msg, 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(msg, 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(msg, var_name.unwrap_error()), err_info); \ return var_name; \ } \ value = 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(msg, var_name.unwrap_error()), err_info); \ return ret; \ } \ value = 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_OBJECT_MISSING_IMPL(var_name, obj, ret) \ IKARUS_VTRYRV_OR_FAIL( \ bool const var_name, \ ret, \ "unable to check whether object exists: {}", \ IkarusErrorInfo_Database_QueryFailed, \ (obj)->project->db->template query_one("SELECT EXISTS(SELECT 1 FROM `objects` WHERE `id` = ?)", (obj)->id) \ ) \ \ IKARUS_FAIL_IF(!(var_name), ret, "object does not exist", IkarusErrorInfo_Client_Misuse); #define IKARUS_FAIL_IF_OBJECT_MISSING(obj, ret) IKARUS_FAIL_IF_OBJECT_MISSING_IMPL(CPPBASE_UNIQUE_NAME(exists), obj, ret);