Add the MRB_ENSURE() macro

This commit is contained in:
dearblue
2026-01-24 11:31:32 +09:00
parent c25b562256
commit 3ac682b2de
2 changed files with 40 additions and 0 deletions
+4
View File
@@ -1615,6 +1615,10 @@ mrbmemset(void *s, int c, size_t n)
#define mrb_int_hash_func(mrb,key) (uint32_t)((key)^((key)<<2)^((key)>>2))
#define MRB_UNIQNAME(name) MRB_UNIQNAME_1(name, __LINE__)
#define MRB_UNIQNAME_1(name, line) MRB_UNIQNAME_2(name, line)
#define MRB_UNIQNAME_2(name, line) name##line
MRB_END_DECL
#endif /* MRUBY_H */
+36
View File
@@ -127,6 +127,42 @@ MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_val
mrb_func_t rescue, mrb_value r_data,
mrb_int len, struct RClass **classes);
/**
* Calls `func` via `mrb_protect_error()` and then always executes the user block exactly once.
* Even if a global jump (similar to a Ruby exception) occurs within `func`, the block will be executed,
* and after the block's completion, the global jump will be re-thrown.
*
* By checking `mrb->exc != NULL` within the block, you can determine if a global jump occurred in `func`.
*
* If you want to suppress the global jump and continue processing, use `mrb_clear_error(mrb); break;`.
*
* - `mrb`: The mruby state reference
* - `result_var`: Pre-defined mrb_value type variable (to receive `func`'s return value)
* - `func`: Function to call (compatible with `mrb_protect_error_func`)
* - `data`: User data to pass to `func`
*
* Example:
*
* mrb_value result;
* MRB_ENSURE(mrb, result, body_func, userdata) {
* // This block is always executed (equivalent to Ruby's ensure)
*
* if (mrb->exc) {
* // Post-processing when an exception occurs
* }
*
* // To ignore the global jump, use `mrb_clear_error(mrb); break;` here
* }
*/
#define MRB_ENSURE(mrb, result_var, func, data) \
for (mrb_bool MRB_UNIQNAME(_break_) = FALSE; \
!MRB_UNIQNAME(_break_) && \
(((result_var) = mrb_protect_error(mrb, func, data, &MRB_UNIQNAME(_break_))), \
((mrb)->exc = (MRB_UNIQNAME(_break_) ? mrb_obj_ptr((result_var)) : NULL)), \
TRUE); \
(void)(MRB_UNIQNAME(_break_) && (mrb)->jmp && (mrb_exc_raise(mrb, result_var), TRUE)), \
MRB_UNIQNAME(_break_) = TRUE)
MRB_END_DECL
#endif /* MRUBY_ERROR_H */