Redefining message()

You may remember that our custom _file_io_error_domain inherits from outcome_e::posix_code::domain_type, and thus does not have to implement the many pure virtual functions required by outcome_e::status_code_domain.

What we do need to do is reimplement _do_message() to append the file and line information to the POSIX error description string returned by outcome_e::posix_code::domain_type. This causes the status code’s .message() observer to return a string with the extra payload information represented in text.

  // Return a string describing a specific code. We will return the
  // string returned by our POSIX code base domain, with the source
  // file and line number appended
  virtual int _do_message(_vtable_message_args &args) const noexcept override final
  {
    assert(args.code.domain() == *this);

    // Fetch message from base domain (POSIX)
    const int errcode = _base::_do_message(args);
    if(errcode != 0)
    {
      return errcode;
    }
    const auto msg = std::move(args.ret);
    const auto &c1 = static_cast<const file_io_error &>(args.code);  // NOLINT
    const value_type &v = c1.value();

    // Append my source file and line number
    if(v.file == nullptr)
    {
      args.ret = msg;
      return 0;  // errno value if failed
    }
    size_t length = strlen(v.file) + 16 + msg.size();
    auto *p = static_cast<char *>(malloc(length));  // NOLINT
    if(p == nullptr)
    {
      args.ret = _base::string_ref("failed to get message from system");
      return ENOMEM;
    }
    snprintf(p, length, "%s (%s:%d)", msg.data(), v.file, v.lineno);

    // Return as atomically reference counted string
    args.ret = _base::atomic_refcounted_string_ref(p, length);
    free(p);
    return 0;  // errno value if failed
  }
};
View this code on Github