carb/Error.h
File members: carb/Error.h
// Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "Defines.h"
#include "Interface.h"
#include "Types.h"
#include "Version.h"
#include "cpp/StringView.h"
#include "detail/DeferredLoad.h"
#include "extras/Errors.h"
#include "../omni/core/Result.h"
#include "../omni/String.h"
#include <cinttypes>
namespace carb
{
using omni::core::Result;
// bring all the kResult___ values into carb namespace
#define CARB_RESULT_USE_OMNI_RESULT_GEN(symbol_, ...) \
\
using omni::core::kResult##symbol_;
OMNI_RESULT_CODE_LIST(CARB_RESULT_USE_OMNI_RESULT_GEN)
class Error;
struct ErrorApi
{
CARB_PLUGIN_INTERFACE("carb::ErrorApi", 1, 0);
static ErrorApi const& instance() noexcept;
Error const*(CARB_ABI* viewCurrentError)(Result* code);
Error*(CARB_ABI* takeCurrentError)(Result* code);
Result(CARB_ABI* internalSetError)(Result code, char const* message, std::size_t message_size);
Result(CARB_ABI* setErrorTo)(Error* error);
void(CARB_ABI* setErrorOom)();
Result(CARB_ABI* errorRelease)(Error* error);
Error*(CARB_ABI* errorClone)(Error const* source);
Error*(CARB_ABI* errorCreate)(Result code, const char* message, std::size_t message_size);
Result(CARB_ABI* getErrorInfo)(Error const* error, Result* code, char const** message, std::size_t* message_size);
Result(CARB_ABI* getCodeDescription)(
Result code, char const** name, std::size_t* name_size, char const** message, std::size_t* message_size);
//
// Inline helper functions
//
Result setError(Result code) const noexcept;
Result setError(Result code, const std::string& message) const noexcept;
Result setError(Result code, const omni::string& message) const noexcept;
Result setError(Result code, cpp::string_view message) const noexcept;
Result setError(Result code, const char* message) const noexcept;
Result setError(Result code, const char* message, std::size_t message_size) const noexcept;
//
// Static Inline helper functions
//
static void clearError() noexcept;
static Result getError() noexcept;
static void setFromErrno();
#if CARB_PLATFORM_WINDOWS || defined(DOXYGEN_BUILD)
static void setFromWinApiErrorCode();
#endif
};
} // namespace carb
#if CARB_REQUIRE_LINKED
CARB_DYNAMICLINK carb::ErrorApi const* carbGetErrorApi(carb::Version* version);
#else
CARB_DYNAMICLINK carb::ErrorApi const* carbGetErrorApi(carb::Version* version) CARB_ATTRIBUTE(weak);
#endif
namespace carb
{
namespace detail
{
CARB_DETAIL_DEFINE_DEFERRED_LOAD(getCarbErrorApiFunc, carbGetErrorApi, (carb::ErrorApi const* (*)(carb::Version*)));
} // namespace detail
inline ErrorApi const& ErrorApi::instance() noexcept
{
static ErrorApi const* const papi = []() -> ErrorApi const* {
const Version expected_version = ErrorApi::getInterfaceDesc().version;
Version found_version = expected_version;
auto p = detail::getCarbErrorApiFunc()(&found_version);
CARB_FATAL_UNLESS(p != nullptr,
"Failed to load Error API for version this module was compiled against. This module was "
"compiled with Error API %" PRIu32 ".%" PRIu32
", but the maximum-supported version of the "
"API in the linked %s is %" PRIu32 ".%" PRIu32,
expected_version.major, expected_version.minor,
CARB_PLATFORM_WINDOWS ? "carb.dll" : "libcarb.so", found_version.major, found_version.minor);
return p;
}();
return *papi;
}
inline void ErrorApi::clearError() noexcept
{
auto r = instance().setErrorTo(nullptr);
CARB_UNUSED(r);
CARB_ASSERT(r == omni::core::kResultSuccess);
}
inline Result ErrorApi::getError() noexcept
{
Result r;
instance().viewCurrentError(&r);
return r;
}
inline Result ErrorApi::setError(Result code) const noexcept
{
return internalSetError(code, nullptr, 0);
}
inline Result ErrorApi::setError(Result code, const std::string& message) const noexcept
{
return internalSetError(code, message.c_str(), message.length());
}
inline Result ErrorApi::setError(Result code, const omni::string& message) const noexcept
{
return internalSetError(code, message.c_str(), message.length());
}
inline Result ErrorApi::setError(Result code, cpp::string_view message) const noexcept
{
return internalSetError(code, message.data(), message.length());
}
inline Result ErrorApi::setError(Result code, const char* message) const noexcept
{
return internalSetError(code, message, message ? std::strlen(message) : 0);
}
inline Result ErrorApi::setError(Result code, const char* message, std::size_t message_size) const noexcept
{
CARB_ASSERT(message_size != size_t(-1));
return internalSetError(code, message, message_size);
}
inline void ErrorApi::setFromErrno()
{
auto e = errno;
switch (e)
{
case 0:
instance().setError(kResultSuccess);
break;
case ENOSYS:
instance().setError(kResultNotImplemented);
break;
case EACCES:
instance().setError(kResultAccessDenied);
break;
case ENOMEM:
instance().setError(kResultOutOfMemory);
break;
case EINVAL:
instance().setError(kResultInvalidArgument);
break;
case EAGAIN:
#if !CARB_POSIX
// This is different on Windows but the same for POSIX
case EWOULDBLOCK:
#endif
instance().setError(kResultTryAgain);
break;
case EINTR:
instance().setError(kResultInterrupted);
break;
case EEXIST:
instance().setError(kResultAlreadyExists);
break;
case EPERM:
instance().setError(kResultInvalidOperation);
break;
case ENOENT:
instance().setError(kResultNotFound);
break;
default:
instance().setError(kResultFail, extras::convertErrnoToMessage(e));
break;
}
errno = e;
}
#if CARB_PLATFORM_WINDOWS
inline void ErrorApi::setFromWinApiErrorCode()
{
auto e = GetLastError();
switch (e)
{
case CARBWIN_ERROR_SUCCESS:
instance().setError(kResultSuccess);
break;
case CARBWIN_ERROR_FILE_NOT_FOUND:
case CARBWIN_ERROR_PATH_NOT_FOUND:
instance().setError(kResultNotFound);
break;
case CARBWIN_ERROR_ACCESS_DENIED:
instance().setError(kResultAccessDenied);
break;
case CARBWIN_ERROR_ALREADY_EXISTS:
case CARBWIN_ERROR_FILE_EXISTS:
instance().setError(kResultAlreadyExists);
break;
case CARBWIN_ERROR_OUTOFMEMORY:
instance().setError(kResultOutOfMemory);
break;
case CARBWIN_ERROR_NO_MORE_FILES:
case CARBWIN_ERROR_NO_MORE_ITEMS:
instance().setError(kResultNoMoreItems);
break;
case CARBWIN_ERROR_CALL_NOT_IMPLEMENTED:
instance().setError(kResultNotImplemented);
break;
case CARBWIN_WAIT_TIMEOUT:
case CARBWIN_ERROR_TIMEOUT:
instance().setError(kResultTryAgain);
break;
default:
instance().setError(kResultFail, extras::convertWinApiErrorCodeToMessage(e));
break;
}
SetLastError(e);
}
#endif
} // namespace carb