#include <Luna/Runtime/Assertions.hpp>

Assertions are used to detect programming mistakes (or "bugs") when developing complex systems and modules. Unlike error handling that is used for run-time errors, assertions are used for errors that should never happen on correctly behaved systems and are expected to interrupt the program immediately when such error occurs, so the developer can get into the code to check the error quickly when an debugger is attached to the process. After the application is fully tested, all assertions should be disabled to increase performance.

In Luna SDK, we separate programming mistakes to internal programming mistakes and external programming mistakes, and use different macros to handle them.

Prefer assertions to throwing error codes when possible, since it simplifies the implementation, reduces the runtime cost and makes the error obvious. Use error codes only when the error cannot be completely solved during the development period.

Assertions for internal programming mistakes

Internal programming mistakes are mistakes caused by incorrectly implementing functions. Such mistakes should never happen if the function is correctly used by the user.

luassert can be used to handle such internal programming mistakes. luassert firstly evaluates the value of the given expression, if the evaluated value is 0, it calls assert_fail to report one error message then interrupts the program. luassert_msg is similar to luassert, but it allows the user to specify the message reported by assert_fail.

lupanic is equal to luassert(false), it interrupts the program immediately when being executed. The user can use lupanic to mark one position in the code that should never be reached in normal condition. lupanic_msg is similar to lupanic, but it allows the user to specify the message reported by assert_fail.

All those four assertion macros take effect only in debug version of the program or library (controlled by LUNA_DEBUG macro, which is configured by xmake). If you want these macros to work in profile and release builds, use macros with _always suffix, like luassert_always, lupanic_always, luassert_msg_always and lupanic_msg_always.

Assertions for external programming mistakes

External programming mistakes are mistakes caused by programmers who use the function. Most functions have constraints on arguments and calling time, calling such functions with bad arguments (like out-of-range index) or at improper time (using one service before it is initialized) will result in undefined behavior that is hard to debug. Unlike internal programming mistakes, these mistakes are caused by programmers who uses the function, thus is impossible to be solved when implementing the function.

For such case, lucheck and lucheck_msg can be used to check external programming mistakes. lucheck and lucheck_msg behave the same as luassert and luassert_msg. However, these two macros are not controlled by LUNA_DEBUG, but another macro called LUNA_ENABLE_CONTRACT_ASSERTION, which can be enabled by specifying contract_assertion when building the module with xmake. The module developer can place lucheck and lucheck_msg at the beginning of the function implementation to validate function arguments and calling time, and interrupts the program if the function is improperly called. With these macros, the developer of the module may ship two versions of libraries to the user, one for developing with the module, and another for releasing with the final product. The development version of the module can be compiled on release mode with contract_assertion switched on, so all luassert assertions get removed, but lucheck assertions are retained for the user, while the release version of the module will remove both luassert and lucheck for maximum performance.