I/O Error

Introduction

xpp::io::Error is a structured I/O error type, packed into 4 bytes. It mirrors Rust's std::io::Error — a categorical ErrorKind plus an optional OS errno or libx xErrno.

#include <xpp/io/error.h>

xpp::io::Error err = xpp::io::Error::from_errno(EADDRINUSE);
if (err.kind() == xpp::io::ErrorKind::AddrInUse) {
    // handle address-in-use
}
printf("%s\n", err.message());  // "Address already in use"

API Reference

ErrorKind

VariantMeaning
InvalidInputMalformed input (bad address string, NULL arg)
HostNotFoundDNS resolution returned no results
AddrInUseEADDRINUSE
AddrNotAvailableEADDRNOTAVAIL
PermissionDeniedEACCES
ConnectionRefusedECONNREFUSED
ConnectionResetECONNRESET
BrokenPipeEPIPE
TimedOutETIMEDOUT
OtherOther syscall error

Error

MethodReturnsDescription
kind()ErrorKindCategorical kind
raw_os_error()intOS errno, or 0 if not from a syscall
raw_xerrno()xErrnolibx error code, or xErrno_Ok if not from libx
message()const char*Human-readable (strerror or kind description)
from_errno(e)ErrorConstruct from OS errno
from_kind(k)ErrorConstruct from ErrorKind
from_xerrno(e)ErrorConstruct from libx xErrno

io::Result<T>

template <class T> using Result = xpp::Result<T, Error>;

Convenience alias — mirrors Rust's std::io::Result<T>.

Encoding

sizeof(io::Error) == 4 (one int32_t). Three sources are distinguishable via bit patterns:

m_code rangeSourceAccessor
0x00000001 .. 0x3FFFFFFFOS errnoraw_os_error()
0x40000000 .. 0x7FFFFFFFlibx xErrno (bit 30 set)raw_xerrno()
0x80000000 .. 0xFFFFFFFFCustom ErrorKind (negative)kind()
0x00000000Niche (Ok sentinel)—

Bit 30 (0x40000000) is the xErrno flag. Errno and xErrno values are both small (< 256). Bit 31 (sign) separates custom kinds.

Usage Examples

From errno

xpp::io::Error err = xpp::io::Error::from_errno(ECONNREFUSED);
err.kind();          // ErrorKind::ConnectionRefused
err.raw_os_error();  // ECONNREFUSED (61 on macOS)
err.message();       // "Connection refused"

From xErrno

xErrno libx_err = xErrno_DnsNotFound;
xpp::io::Error err = xpp::io::Error::from_xerrno(libx_err);
err.kind();          // ErrorKind::HostNotFound
err.raw_xerrno();    // xErrno_DnsNotFound
err.raw_os_error();  // 0 (not from a syscall)

From ErrorKind

xpp::io::Error err = xpp::io::Error::from_kind(xpp::io::ErrorKind::InvalidInput);
err.kind();          // ErrorKind::InvalidInput
err.raw_os_error();  // 0
err.raw_xerrno();    // xErrno_Ok

With io::Result — .await()

auto r = xpp::net::UdpSocket::bind("127.0.0.1:9090").await();
if (r.is_err()) {
    auto e = r.unwrap_err();
    if (e.kind() == xpp::io::ErrorKind::AddrInUse) {
        // port already taken
    }
}

With io::Result — co_await (C++20)

xpp::Promise<void> bind_or_retry(const char *addr) {
    auto r = co_await xpp::net::UdpSocket::bind(addr);
    if (r.is_err()) {
        auto e = r.unwrap_err();
        if (e.kind() == xpp::io::ErrorKind::AddrInUse) {
            co_await xpp::after(1000);
        }
        co_return;
    }
    auto sock = std::move(r).unwrap();
}