From 9af6264d6b5127c8a6ef4c2a6b236829f0eced51 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 1 Dec 2023 21:30:16 +0900 Subject: [PATCH] Implement `Fiber#to_s` method If the filename and line number cannot be obtained, "(unknown):1" is used instead. Also, the file name information of the terminated fiber cannot be retrieved and will be replaced as well. This limitation is due to the fact that `cibase->proc` of the terminated fiber is collected by the GC. ```console % bin/mruby -e 'p Fiber.new { p Fiber.current }.resume' # # ``` --- mrbgems/mruby-fiber/src/fiber.c | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 62bcbc301..02fbb702b 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -1,8 +1,11 @@ #include #include #include +#include #include +#include #include +#include #include #define fiber_ptr(o) ((struct RFiber*)mrb_ptr(o)) @@ -348,6 +351,56 @@ fiber_eq(mrb_state *mrb, mrb_value self) return mrb_bool_value(fiber_ptr(self) == fiber_ptr(other)); } +/* + * call-seq: + * fiber.to_s -> string + * fiber.inspect -> string + * + * Returns fiber object information as a string. + * + * If the file information cannot be obtained, it is replaced with `(unknown):1`. + * Also, if the fiber is terminated, it will be replaced in the same way (mruby limitation). + */ +static mrb_value +fiber_to_s(mrb_state *mrb, mrb_value self) +{ + fiber_check(mrb, self); + const struct RFiber *f = fiber_ptr(self); + + mrb_value s = mrb_any_to_s(mrb, self); + mrb_assert(RSTRING_END(s)[-1] == '>'); + RSTRING_END(s)[-1] = ' '; + + const char *file; + int32_t line; + if (f->cxt->ci > f->cxt->cibase && + mrb_debug_get_position(mrb, f->cxt->cibase->proc->body.irep, 0, &line, &file)) { + mrb_str_cat_cstr(mrb, s, file); + mrb_str_cat_lit(mrb, s, ":"); + char buf[16]; + mrb_str_cat_cstr(mrb, s, mrb_int_to_cstr(buf, sizeof(buf), line, 10)); + } + else { + mrb_str_cat_lit(mrb, s, "(unknown):1"); + } + + const char *st; + switch (fiber_ptr(self)->cxt->status) { + case MRB_FIBER_CREATED: st = "created"; break; + case MRB_FIBER_RUNNING: st = "resumed"; break; + case MRB_FIBER_RESUMED: st = "suspended by resuming"; break; + case MRB_FIBER_SUSPENDED: st = "suspended"; break; + case MRB_FIBER_TRANSFERRED: st = "suspended"; break; + case MRB_FIBER_TERMINATED: st = "terminated"; break; + default: st = "UNKNOWN STATUS (BUG)"; break; + } + mrb_str_cat_lit(mrb, s, " ("); + mrb_str_cat_cstr(mrb, s, st); + mrb_str_cat_lit(mrb, s, ")>"); + + return s; +} + /* * call-seq: * fiber.transfer(args, ...) -> obj @@ -485,6 +538,8 @@ mrb_mruby_fiber_gem_init(mrb_state* mrb) mrb_define_method(mrb, c, "transfer", fiber_transfer, MRB_ARGS_ANY()); mrb_define_method(mrb, c, "alive?", fiber_alive_p, MRB_ARGS_NONE()); mrb_define_method(mrb, c, "==", fiber_eq, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, c, "to_s", fiber_to_s, MRB_ARGS_NONE()); + mrb_define_alias(mrb, c, "inspect", "to_s"); mrb_define_class_method(mrb, c, "yield", fiber_yield, MRB_ARGS_ANY()); mrb_define_class_method(mrb, c, "current", fiber_current, MRB_ARGS_NONE());