libxpp
C++11 bindings for libx — stackful fibers, smart pointers, async primitives, and type utilities. Header-only.
At a Glance
#include <xpp/arc.h>
#include <xpp/box.h>
#include <xpp/option.h>
#include <xpp/result.h>
#include <xpp/promise.h>
#include <xpp/fiber.h>
// .await() — THE way to wait for a Promise. Works everywhere:
// outside a fiber: drives xEventLoopRun directly (blocking)
// inside a fiber: suspends via xFiberYield (non-blocking)
int result = xpp::resolve(42)
.then([](int x) { return x * 2; })
.await();
// result == 84
// Coalesce many concurrent I/O calls with xpp::fiber():
xpp::fiber([]() {
auto a = http_get("/a").await(); // fiber suspends, event loop keeps running
auto b = http_get("/b").await(); // resumes when a is ready
return a + b;
}).then([](int total) {
printf("total = %d\n", total);
});
// Also supports C++20 coroutines (co_await / co_return):
#if XPP_HAS_COROUTINES
xpp::Promise<Stats> fetch() {
auto raw = co_await http_get("/api/stats");
co_return parse_stats(raw);
}
#endif
// Result<T, E> — explicit error handling, no exceptions
xpp::Result<int, std::string> parse(std::string_view s) {
if (s.empty()) return xpp::err("empty input");
return xpp::ok(std::stoi(std::string(s)));
}
// Option<T> — nullptr == None, sizeof == sizeof(T*)
xpp::Option<xpp::Arc<Config>> cached = lookup(key);
if (cached) use(**cached);
Design philosophy:
.await()first — fiber + event loop —.await()is the canonical way to wait. Outside a fiber it drivesxEventLoopRundirectly. Inside a fiber (viaxpp::fiber()) it suspends viaxFiberYield— non-blocking, stackful, M:N concurrency withoutco_awaitsyntax. C++20 coroutines are a first-class option too.- Rust-inspired, C++11-compatible —
Result/Option/Arc/Boxwith the same semantics as their Rust counterparts, but portable to any C++11 toolchain. - Zero overhead — every smart pointer is
sizeof(T*).Option<Arc<T>>is alsosizeof(T*)via niche optimization (nullptr = None). Empty allocators vanish via EBO. - Single allocation —
Arc::make()allocates the control block and value together in one heap block, matching Rust'sArc::new.
Modules
- EventLoop & WaitScope — RAII wrappers for the libx event loop
- Fiber — Stackful coroutines via
xpp::fiber()+.await() - Promise — Composable deferred values
- .await() & Waiting —
.await()semantics (fiber + blocking), event loop integration - Deferred Resolution —
async(),PromiseResolver, cross-thread - Timers & Timeouts —
after(), timeout pattern - Combinators (all/race) —
all(),race(), waker sharing - Utilities (try_next) —
try_next(), sequential fall-through - Custom Adapters —
adapt(),work(), Adapter contract - C++20 Coroutines —
co_await/co_return(optional) - Internals — PromiseNode hierarchy, poll-based model
- .await() & Waiting —
- Allocator — Allocator protocol, GlobalAllocator, custom allocators
- Arena — Bump allocator for short-lived objects (
Arena<N>) - Smart Pointers —
Own,Box,Rc/Weak,Arc/ArcWeak,NonNull- Own — Nullable unique ownership
- Box — Non-null unique ownership
- Rc & Weak — Single-thread shared ownership
- Arc & ArcWeak — Thread-safe shared ownership
- NonNull — Non-owning, non-null reference
- Result — Success or error (Rust Result)
- Option — A value or nothing (Rust Option)
- String — UTF-8 string (Rust String)
- Vec — Contiguous growable array (Rust Vec)
- Enum — Type-safe tagged union
- Timer — Callback-based timer with pause/resume
- Filesystem — Async file I/O (
File,stat,exists,create_dir,rename) - I/O — Reactive async I/O for non-blocking fds (
AsyncFd,read,write,Error) - Net — Async TCP/UDP/DNS/URL/TLS (
TcpStream,TcpListener,UdpSocket,lookup_host,Url,TlsContext) - Panic — Assert macros
- Compiler Macros — Attribute/deprecation helpers
- Opaque Handle Wrapper — RAII for
XDEF_HANDLEtypedefs