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
}
};