Files
odin-sdl3-static-linking/sdl3/sdl3_assert.odin
2025-12-15 12:37:50 -05:00

99 lines
3.2 KiB
Odin

package sdl3
import "base:intrinsics"
import "core:c"
TriggerBreakpoint :: intrinsics.debug_trap
AssertBreakpoint :: TriggerBreakpoint
/**
* Possible outcomes from a triggered assertion.
*
* When an enabled assertion triggers, it may call the assertion handler
* (possibly one provided by the app via SDL_SetAssertionHandler), which will
* return one of these values, possibly after asking the user.
*
* Then SDL will respond based on this outcome (loop around to retry the
* condition, try to break in a debugger, kill the program, or ignore the
* problem).
*
* \since This enum is available since SDL 3.2.0.
*/
AssertState :: enum c.int {
RETRY, /**< Retry the assert immediately. */
BREAK, /**< Make the debugger trigger a breakpoint. */
ABORT, /**< Terminate the program. */
IGNORE, /**< Ignore the assert. */
ALWAYS_IGNORE, /**< Ignore the assert from now on. */
}
/**
* Information about an assertion failure.
*
* This structure is filled in with information about a triggered assertion,
* used by the assertion handler, then added to the assertion report. This is
* returned as a linked list from SDL_GetAssertionReport().
*
* \since This struct is available since SDL 3.2.0.
*/
AssertData :: struct {
always_ignore: bool, /**< true if app should always continue when assertion is triggered. */
trigger_count: c.uint, /**< Number of times this assertion has been triggered. */
condition: cstring, /**< A string of this assert's test code. */
filename: cstring, /**< The source file where this assert lives. */
linenum: c.int, /**< The line in `filename` where this assert lives. */
function: cstring, /**< The name of the function where this assert lives. */
next: ^AssertData, /**< next item in the linked list. */
}
AssertionHandler :: #type proc "c" (data: ^AssertData, userdata: rawptr) -> AssertState
@(default_calling_convention="c", link_prefix="SDL_")
foreign lib {
ReportAssertion :: proc(data: ^AssertData, func, file: cstring, line: c.int) -> AssertState ---
SetAssertionHandler :: proc(handler: AssertionHandler, userdata: rawptr) ---
GetDefaultAssertionHandler :: proc() -> AssertionHandler ---
GetAssertionReport :: proc() -> AssertData ---
ResetAssertionReport :: proc() ---
}
disabled_assert :: proc "c" (condition: bool) {
return
}
enabled_assert :: proc "c" (condition: bool, loc := #caller_location, _message := #caller_expression(condition)) {
if condition {
return
}
// NOTE(bill): relying on these being NUL terminated
c := cstring(raw_data(_message))
p := cstring(raw_data(loc.procedure))
f := cstring(raw_data(loc.file_path))
for {
@(static)
sdl_assert_data: AssertData
sdl_assert_data.condition = c
sdl_assert_state := ReportAssertion(&sdl_assert_data, p, f, loc.line)
if sdl_assert_state == .RETRY {
continue
} else if sdl_assert_state == .BREAK {
AssertBreakpoint()
}
break
}
}
@(disabled=ODIN_DISABLE_ASSERT)
assert :: proc "c" (condition: bool, loc := #caller_location, _message := #caller_expression(condition)) {
enabled_assert(condition, loc, _message)
}
assert_release :: assert
assert_always :: enabled_assert