Added complete documentation for all C API functions providing exception handling capabilities in src/exception.c: ## Core C API Functions: ### Exception Protection: - mrb_protect: executes function under exception protection, equivalent to Ruby's begin/rescue blocks, catches exceptions and returns them as objects with error state flag for C code exception handling ### Guaranteed Cleanup: - mrb_ensure: executes function with guaranteed cleanup, equivalent to Ruby's begin/ensure blocks, ensures cleanup function always runs regardless of exceptions, re-raises caught exceptions after cleanup ### Exception Handling: - mrb_rescue: executes function with StandardError exception handling, convenience wrapper for common rescue patterns, automatically catches StandardError and its subclasses - mrb_rescue_exceptions: executes function with specific exception class handling, allows selective exception catching based on class hierarchy, re-raises unmatched exceptions for precise error control ## Helper Components: ### Internal Structures: - protect_data: helper structure to pass function and data to protection wrapper, encapsulates function pointer and argument data for safe execution ### Internal Functions: - protect_body: helper function that wraps user function calls for exception protection, extracts function and data from protect_data structure and calls user function with proper parameters Key features documented: - Exception protection and propagation control - Guaranteed cleanup execution (ensure semantics) - Selective exception class handling with inheritance support - Integration with mruby's exception system and GC - C API patterns for robust error handling in extensions Provides complete coverage of exception handling C API for robust error management in mruby C extensions and embedded applications, essential for building reliable C code that integrates with mruby's exception system. Co-authored-by: Atlassian Rovo Dev
mruby-error
The mruby-error mrbgem provides a set of C-level APIs for structured exception handling within mruby. These functions allow C extensions or embedded mruby code to implement error handling patterns similar to Ruby's begin, rescue, and ensure keywords. This is particularly useful when writing C code that needs to interact with mruby's exception system in a robust way.
mrb_protect
The mrb_protect function is used to execute a C function (body) and capture any exceptions that might be raised during its execution. This allows you to run potentially unsafe operations and handle errors gracefully.
C Signature:
mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state);
Parameters:
mrb_state *mrb: The current mruby state.mrb_func_t body: A function pointer to the C function to be executed. This function should have the signaturemrb_value (*body)(mrb_state *mrb, mrb_value data).mrb_value data: Amrb_valuethat will be passed as an argument to thebodyfunction.mrb_bool *state: A pointer to a boolean. Aftermrb_protectreturns, this boolean will be:FALSE(0) if thebodyfunction executed without raising an exception.TRUE(1) if an exception was raised within thebodyfunction.
Return Value:
- If no exception occurs (
*stateisFALSE),mrb_protectreturns the value returned by thebodyfunction. - If an exception occurs (
*stateisTRUE),mrb_protectreturns the exception object.
mrb_ensure
The mrb_ensure function ensures that a specific C function (ensure) is executed, regardless of whether another C function (body) completes normally or raises an exception. This is analogous to Ruby's ensure clause.
C Signature:
mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t ensure, mrb_value e_data);
Parameters:
mrb_state *mrb: The current mruby state.mrb_func_t body: A function pointer to the main C function to be executed.mrb_value b_data: Amrb_valuepassed as data to thebodyfunction.mrb_func_t ensure: A function pointer to the C function that will always be executed after thebodyfunction.mrb_value e_data: Amrb_valuepassed as data to theensurefunction.
Behavior:
The body function is executed first. After its completion (either normally or due to an exception), the ensure function is executed. If the body function raised an exception, that exception is re-thrown after the ensure function has finished. The return value of mrb_ensure is the result of the body function if no exception occurred.
mrb_rescue
The mrb_rescue function executes a C function (body) and, if an exception that is a StandardError (or a subclass of StandardError) is raised, it executes a specified rescue C function. This is similar to a rescue clause in Ruby that doesn't specify a particular exception type (which defaults to StandardError).
C Signature:
mrb_value mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data);
Parameters:
mrb_state *mrb: The current mruby state.mrb_func_t body: A function pointer to the main C function to be executed.mrb_value b_data: Amrb_valuepassed as data to thebodyfunction.mrb_func_t rescue: A function pointer to the C function that will be executed if aStandardError(or its subclass) is caught.mrb_value r_data: Amrb_valuepassed as data to therescuefunction.
Behavior:
If the body function executes without raising an exception, its result is returned. If a StandardError (or one of its descendants) is raised, the rescue function is executed, and its result becomes the return value of mrb_rescue. If an exception occurs that is not a StandardError (or its subclass), it is not caught by this function and will propagate up the call stack. Similarly, if the rescue block itself raises an exception, that exception will propagate.
mrb_rescue_exceptions
The mrb_rescue_exceptions function provides more fine-grained exception handling than mrb_rescue. It executes a C function (body) and, if an exception matching one of the specified classes is raised, it executes a rescue C function. This is analogous to Ruby's rescue SpecificError1, SpecificError2 => e syntax.
C Signature:
mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data, mrb_int len, struct RClass **classes);
Parameters:
mrb_state *mrb: The current mruby state.mrb_func_t body: A function pointer to the main C function to be executed.mrb_value b_data: Amrb_valuepassed as data to thebodyfunction.mrb_func_t rescue: A function pointer to the C function that will be executed if a matching exception is caught.mrb_value r_data: Amrb_valuepassed as data to therescuefunction.mrb_int len: The number of exception classes provided in theclassesarray.struct RClass **classes: An array of pointers to mrubyRClassobjects representing the exception classes to be rescued.
Behavior:
If the body function executes without raising an exception, its result is returned. If an exception is raised that is an instance of one of the classes specified in the classes array (or a subclass of one of them), the rescue function is executed, and its result becomes the return value of mrb_rescue_exceptions. If an exception occurs that does not match any of the specified classes, it is not caught and will propagate. If the rescue block itself raises an exception, that exception will propagate.
Usage Examples
The C functions provided by this mrbgem are typically used when writing mruby C extensions that need to interact with Ruby code or manage resources carefully in the presence of potential exceptions.
For concrete examples of how these functions are used, please refer to the test files within this mrbgem:
test/exception.c: Shows how these C functions are called directly.test/exception.rb: Demonstrates the behavior of these C functions from the Ruby side, through theExceptionTestmodule (defined intest/exception.c).
These tests illustrate how to set up callback functions and how the error handling mechanisms behave in practice.