Working example
This commit is contained in:
98
sdl3/sdl3_assert.odin
Normal file
98
sdl3/sdl3_assert.odin
Normal file
@@ -0,0 +1,98 @@
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user