Browse Source

base/runtime: Add `ensure` and `ensure_contextless`

This provides an equivalent to `assert` and `assert_contextless` that
are always evaluated, ignoring `ODIN_DISABLE_ASSERT`, which is useful
for enforcing API contracts or "asserting" on conditionals with
side-effects.
Yawning Angel 8 months ago
parent
commit
3a5440e4ed
1 changed files with 29 additions and 0 deletions
  1. 29 0
      base/runtime/core_builtin.odin

+ 29 - 0
base/runtime/core_builtin.odin

@@ -964,6 +964,24 @@ assert :: proc(condition: bool, message := #caller_expression(condition), loc :=
 	}
 }
 
+// Evaluates the condition and aborts the program iff the condition is
+// false.  This routine ignores `ODIN_DISABLE_ASSERT`, and will always
+// execute.
+@builtin
+ensure :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
+	if !condition {
+		@(cold)
+		internal :: proc(message: string, loc: Source_Code_Location) {
+			p := context.assertion_failure_proc
+			if p == nil {
+				p = default_assertion_failure_proc
+			}
+			p("unsatisfied ensure", message, loc)
+		}
+		internal(message, loc)
+	}
+}
+
 @builtin
 panic :: proc(message: string, loc := #caller_location) -> ! {
 	p := context.assertion_failure_proc
@@ -999,6 +1017,17 @@ assert_contextless :: proc "contextless" (condition: bool, message := #caller_ex
 	}
 }
 
+@builtin
+ensure_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) {
+	if !condition {
+		@(cold)
+		internal :: proc "contextless" (message: string, loc: Source_Code_Location) {
+			default_assertion_contextless_failure_proc("unsatisfied ensure", message, loc)
+		}
+		internal(message, loc)
+	}
+}
+
 @builtin
 panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! {
 	default_assertion_contextless_failure_proc("panic", message, loc)