concurrency group CI-${{ github.ref }} with cancel-in-progress — on the
single runner an in-flight run for an older master commit blocks the newer
one for its full ~70 min; a new push now cancels the outdated run instead.
Teles — Cross-Platform C++14 Framework
Teles is a comprehensive C++14 framework providing a unified, modular set of utilities for building robust C++ applications. It abstracts away platform differences across Windows, macOS, and Linux, offering a single consistent API surface with no heavy dependencies (no Boost). Public headers are lightweight; implementation details are compiled into a static (or shared) library.
All third-party libraries ({fmt}, mpark::variant, ghc::filesystem,
nlohmann/json, miniz) are fully encapsulated behind teles:: APIs —
users never interact with upstream namespaces directly.
Quick Start
# Configure (builds static library by default)
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build (compiles tests if TELES_BUILD_TESTS=ON)
cmake --build build
# Run tests
cd build && ctest --output-on-failure
CMake Integration
# In your project's CMakeLists.txt:
find_package(teles REQUIRED)
target_link_libraries(my_app PRIVATE teles::teles)
Or add as a subdirectory:
add_subdirectory(teles)
target_link_libraries(my_app PRIVATE teles::teles)
Build Options
| Option | Default | Description |
|---|---|---|
TELES_BUILD_TESTS |
OFF |
Build Google Test unit tests + rapidcheck property tests |
TELES_BUILD_FUZZ |
OFF |
Build libFuzzer/AFL++ fuzz targets |
TELES_BUILD_SHARED |
OFF |
Build teles as a shared library (default: static) |
TELES_INSTALL |
OFF |
Generate install targets (headers + library + CMake package) |
Compiler Requirements
GCC 7+, Clang 7+, or MSVC 2019+ with full C++14 support.
Usage
Include everything via the umbrella header:
#include <teles/teles.h>
Or include individual module headers for finer control:
#include <teles/memory/allocator.h>
#include <teles/error/result.h>
#include <teles/str/string_ops.h>
#include <teles/concurrency/thread_pool.h>
#include <teles/fs/file_stream.h>
#include <teles/io/tcp.h>
#include <teles/reactive/reactive.h>
#include <teles/serialization/json.h>
#include <teles/config/config.h>
#include <teles/system/signal_handling.h>
#include <teles/system/crash_diagnostics.h>
Error Handling
#include <teles/teles.h>
using namespace teles;
// Success case
Result<int, Error> ParsePort(StringView s) {
// ... parse logic ...
return Ok(8080);
}
// Error case with cause chaining
Result<int, Error> ParsePort(StringView s) {
return Err(Error::InvalidArgument("not a number")
.WithCause(Error::System(errno, "strtol failed")));
}
// Functional combinators
auto result = ParsePort("8080")
.Map([](int port) { return port + 1; })
.Inspect([](int v) { Print("port: {}\n", v); });
if (result) {
int port = result.Value();
} else {
Print("error: {}\n", result.Error().ToChainString());
}
Memory Allocation
#include <teles/teles.h>
using namespace teles;
// Default allocator (malloc/free)
void* p = memory::DefaultAllocator()->Allocate(128);
// Pool allocator — O(1) alloc/dealloc for fixed-size blocks
memory::PoolAllocator pool(sizeof(Node), 1024);
void* node = pool.Allocate(sizeof(Node));
pool.Deallocate(node);
// Arena allocator — bump-pointer, bulk-free for short-lived objects
{
memory::ScopedArena arena(64 * 1024);
char* buf = static_cast<char*>(arena.Allocate(256));
// memory reclaimed on scope exit
}
// Tracking allocator — leak detection, guard bytes (debug builds)
memory::TrackingAllocator tracker(memory::DefaultAllocator());
void* tracked = tracker.Allocate(64);
tracker.Deallocate(tracked);
auto stats = tracker.Stats(); // allocCount, peakBytes, liveAllocations, ...
String Operations
#include <teles/teles.h>
using namespace teles;
// Split / Trim / Replace
auto parts = str::Split("a,b,c", ','); // {"a", "b", "c"}
auto trimmed = str::Trim(" hello "); // "hello"
auto replaced = str::ReplaceAll("foo bar foo", "foo", "baz");
// Case conversion
str::ToCamelCase("hello_world"); // "helloWorld"
str::ToSnakeCase("HTTPServer"); // "http_server"
str::ToKebabCase("XMLParser"); // "xml-parser"
// Natural ordering
str::NaturalLess less;
less("file2", "file10"); // true — numeric comparison of digit runs
// StringBuilder / StrCat
std::string s = str::StrCat("x = ", 42, ", y = ", 3.14);
// UTF-8
str::utf8::IsValid("héllo"); // true
str::utf8::Length("héllo"); // 5 (code points, not bytes)
// Encoding conversion
auto utf16 = str::Utf8ToUtf16("héllo");
auto wide = str::Utf8ToWide("héllo");
Formatting
#include <teles/teles.h>
using namespace teles;
// {fmt} is a public dependency — format directly
auto s = fmt::format("x = {}, y = {:>8}", 42, "hi");
fmt::print("count: {}\n", 100);
// ToString: the only hand-written overloads are the null-safe pair
format::ToString("str"); // copy, null-safe
format::ToString(nullptr); // ""
// TELES_ENUM macro — generates enum + Names + Count + ToString + TryParse
TELES_ENUM(Color, Red, Green, Blue);
// Generates:
// enum class Color { Red, Green, Blue };
// const char* const* ColorNames();
// constexpr std::size_t ColorCount();
// std::string ToString(Color);
// bool TryParseColor(StringView, Color&);
Community Sugar
#include <teles/teles.h>
using namespace teles;
// TELES_TRY — Rust-style ? operator for Result propagation
Result<int, Error> Compute() {
TELES_TRY_ASSIGN(a, ParseValue("42"));
TELES_TRY_ASSIGN(b, ParseValue("100"));
return Ok(a + b);
}
// Overloaded — visitor pattern with lambdas
auto visitor = core::MakeOverloaded(
[](int x) { return "int"; },
[](double x) { return "double"; },
[](StringView x) { return "string"; }
);
// Match — pattern matching on Optional
auto result = core::Match(maybeValue,
[](int v) { return v * 2; }, // onSome
[]() { return 0; } // onNone
);
// Box — ownership transfer (unique_ptr alias)
auto obj = std::make_unique<MyClass>(arg1, arg2);
// User-defined literals
using namespace teles::literals;
auto sv = "hello"_sv; // StringView
auto s = "world"_s; // std::string
auto sz = 4_KB; // std::size_t (4096)
auto dur = 500_ms; // std::chrono::milliseconds
// Bit operations
bitops::PopCount32(0xFF); // 8
bitops::CountLeadingZeros32(1); // 31
bitops::IsPowerOfTwo(64); // true
// Hash combining
std::size_t h = core::HashValue(x, y, z);
Concurrency
#include <teles/teles.h>
using namespace teles;
using namespace teles::concurrency;
// --- ThreadPool with rejection policy ---
ThreadPoolConfig cfg;
cfg.coreThreads = 4;
cfg.maxThreads = 16;
cfg.queueCapacity = 256;
cfg.rejectionPolicy = RejectionPolicy::CallerRuns; // run in submitting thread
ThreadPool pool(cfg);
// Submit returns Future<R>
Future<int> f = pool.Submit([] {
// ... work ...
return 42;
});
int result = f.Get(); // blocking
// --- Global pools (lazily initialized) ---
Future<int> f1 = CpuPool()->Submit([] { return 1; });
Future<int> f2 = IoPool()->Submit([] { return 2; });
Future<int> f3 = SinglePool()->Submit([] { return 3; });
Schedulers::Shutdown(); // optional teardown
// --- Async helpers ---
Future<int> a = Async([] { return 100; }); // submits to CpuPool
Future<int> b = AsyncOn(pool, [] { return 200; }); // submits to a specific pool
// --- Future combinators ---
Promise<int> p;
Future<int> base = MakeFuture(p);
auto chained = Then(base, [](int v) { return v * 2; }); // 84
auto recovered = OnError(chained, [](Error) { return -1; }); // recover on error
auto timed = WithTimeout(recovered, 500_ms); // error if > 500ms
p.SetValue(42); // settle the chain
// All — wait for every future
std::vector<Future<int>> futures = {
Async([] { return 1; }),
Async([] { return 2; }),
Async([] { return 3; })
};
Future<std::vector<int>> all = All(futures);
auto vals = all.Get(); // {1, 2, 3}
// Any — first to complete wins
std::vector<Future<int>> racers = {
Async([] { return 10; }),
Async([] { return 20; })
};
Future<int> winner = Any(racers);
int first = winner.Get(); // 10 or 20
// --- Channel<T> (Go-style) ---
Channel<int> ch(8); // bounded, capacity 8
Channel<int> unbounded; // unbounded
ch.Send(1);
Optional<int> v = ch.Recv(); // 1
Optional<int> e = ch.TryRecv(); // non-blocking; empty if nothing available
bool ok = ch.SendFor(2, Duration::Milliseconds(100)); // timed; false = timeout/closed
Optional<int> t = ch.RecvFor(Duration::Milliseconds(100)); // timed receive
// --- Mutex / RwLock ---
Mutex<int> mtx(0);
mtx.With([](int& v) { v++; }); // lambda executes under lock
RwLock<Config> rwlock;
rwlock.WithRead([](const Config& c) { /* read-only access */ });
rwlock.WithWrite([](Config& c) { c.Update(); });
// --- Synchronization primitives ---
Latch latch(3);
latch.CountDown(); // count down from 3
latch.Wait(); // blocks until count reaches 0
WaitGroup wg(5);
wg.Done(); // decrement
wg.Wait(); // blocks until 0
Filesystem
#include <teles/teles.h>
using namespace teles;
using namespace teles::fs;
// --- Path manipulation ---
Path p = Path("/usr/local") / "bin" / "app";
p.Filename(); // "app"
p.Extension(); // ""
p.Parent(); // "/usr/local/bin"
p.IsAbsolute(); // true
// --- One-shot file read/write ---
auto content = ReadFile("/etc/hostname");
if (content) {
Print("hostname: {}\n", content.Value());
}
WriteFile(Path("/tmp/test.txt"), "hello world");
// --- File status (type, size, timestamps, permissions) ---
auto status = Status(Path("/tmp/test.txt"));
if (status) {
// status.Value().type, .size, .modifiedNanos, .accessedNanos, .createdNanos
}
// --- FileStream: streaming sequential/random I/O ---
FileStream stream(Path("/tmp/data.bin"), FileMode::Read, 8192);
auto bytesRead = stream.Read(buf, sizeof(buf));
stream.Seek(0, SeekOrigin::Begin); // rewind
auto pos = stream.Tell();
stream.Close(); // or let RAII close on destruction
// --- Directory iteration ---
for (auto& entry : BeginDirectory(Path("/tmp"))) {
Print("{}\n", entry.path.Str());
}
// Recursive iteration with symlink-cycle-safe CopyRecursive
CopyRecursive(Path("/src"), Path("/dst"));
// --- TempDir / TempFile (RAII cleanup) ---
{
TempDir tmp("myapp");
WriteFile(tmp.Get() / "config.json", "{}");
// directory deleted on scope exit
}
// --- Glob pattern matching ---
auto files = Glob("/tmp/*.log");
for (const auto& f : files.Value()) {
Print("matched: {}\n", f.Str());
}
I/O (Networking + Async)
#include <teles/teles.h>
using namespace teles;
using namespace teles::io;
// --- EventLoop (signal-driven reactor, no external proactor lib) ---
concurrency::EventLoop loop;
std::thread loop_thread([&] { loop.Run(); });
// --- TCP client (signal-based; hold in a shared_ptr) ---
auto conn = std::make_shared<TcpConnection>(&loop);
auto connected = conn->OnConnected.Connect([](TcpConnection* c) {
c->SetNoDelay(true);
const uint8_t req[] = "GET / HTTP/1.0\r\n\r\n";
c->Write(req, sizeof(req) - 1); // buffered; OnWritable fires when drained
});
auto onData = conn->OnData.Connect(
[](TcpConnection* c, const uint8_t* data, size_t len) {
// data is valid only during the callback — copy it if needed
});
// Connect() returns a Future resolving to Result<void> — Get() never throws
auto connectResult = conn->Connect("example.com", 80).Get();
if (connectResult.Ok()) {
conn->SetTimeout(5_s); // idle timeout watchdog
conn->SetKeepAlive(true); // TCP keep-alive
}
conn->Close();
// --- Timers (TimerQueue-based; RAII Disposable cancels on destruction) ---
concurrency::CoarseTimerQueue tq;
auto t1 = concurrency::SetTimeout(&tq, 500_ms, [&] { Print("fired!\n"); });
auto t2 = concurrency::SetInterval(&tq, 1_s, [&] { PollSensors(); },
concurrency::MissedTick::Skip);
// --- Blocking sleep (monotonic base) ---
time::SleepFor(100_ms);
// --- Async file I/O (offloaded to a ThreadPool) ---
concurrency::ThreadPoolConfig cfg;
cfg.coreThreads = 4;
concurrency::ThreadPool pool(cfg);
auto data = AsyncReadFile(pool, Path("/tmp/large.bin")).Get().Value();
loop.Stop();
loop_thread.join();
Reactive (teles::reactive)
Push-based composable streams — Flowable<T> with Rx-style operators, backpressure strategies, schedulers, and subjects.
#include <teles/teles.h>
using namespace teles;
using namespace teles::reactive;
// --- Flowable basics: Subscribe returns a Subscription (RAII auto-cancel) ---
auto src = FlowableRange(1, 5); // emits 1, 2, 3, 4, 5
{
auto sub = src.Subscribe(
[](int v) { Print("got: {}\n", v); },
[](std::exception_ptr) { Print("error\n"); },
[]() { Print("done\n"); }
);
// Callback-style Subscribe requests unbounded demand for you.
// sub auto-cancels at scope exit.
}
// SubscribeAndForget — fire-and-forget (no Subscription to manage)
src.SubscribeAndForget([](int v) { Print("val: {}\n", v); });
// --- Chain methods (preferred) ---
auto doubled = FlowableRange(1, 3)
.Map<int>([](int x) { return x * 2; }); // 2, 4, 6
auto scan = FlowableRange(1, 4).Scan<int>(
0, [](int acc, int x) { return acc + x; }); // 1, 3, 6, 10 (running sum)
// FlatMap — map each item to an inner Flowable, merge results
auto flat = FlowableRange(1, 3).FlatMap<int>(
[](int x) { return FlowableRange(x, 2); }); // 1,2, 2,3, 3,4 (interleaved)
// --- Filtering operators ---
auto evens = FlowableRange(1, 10).Filter(
[](int x) { return x % 2 == 0; });
auto first3 = FlowableRange(1, 100).Take(3); // 1, 2, 3 then complete
auto skip2 = FlowableRange(1, 5).Skip(2); // 3, 4, 5
auto uniq = FlowableFromIterable<int>({1, 1, 2, 2, 3, 3, 1})
.DistinctUntilChanged(); // 1, 2, 3, 1
// --- Combining operators ---
auto merged = Merge(std::vector<Flowable<int>>{
FlowableFromIterable<int>({1, 2}),
FlowableFromIterable<int>({3, 4})
}); // 1, 2, 3, 4 (interleaved)
auto concatenated = Concat(
FlowableFromIterable<int>({1, 2}),
FlowableFromIterable<int>({3, 4})); // 1, 2, 3, 4 (sequential)
// Zip — binary form with a zipper; the vector-emitting form uses a vector zipper
auto zipped = Zip<int, int, std::vector<int>>(
FlowableFromIterable<int>({1, 2}),
FlowableFromIterable<int>({10, 20}),
[](int a, int b) { return std::vector<int>{a, b}; });
// {1,10}, {2,20}
auto prefixed = StartWith(FlowableRange(3, 2), {0, 1, 2}); // 0, 1, 2, 3, 4
// --- Aggregate operators ---
auto sum = FlowableRange(1, 5).Reduce(
[](int a, int b) { return a + b; }); // 15
auto cnt = Count(FlowableRange(1, 100)); // 100 (emits int64_t)
auto list = FlowableRange(1, 3).ToList();
// emits {1, 2, 3} as a single std::vector<int>
auto collected = Collect<int, std::string>(
FlowableRange(1, 3),
std::string(""),
[](std::string& acc, int x) { acc += std::to_string(x); }
); // "123"
// --- Error handling ---
auto withFallback = OnErrorReturnItem<int>(
FlowableThrow<int>(std::make_exception_ptr(std::runtime_error("oops"))),
-1
); // emits -1, then completes
// --- Side-effect / utility ---
auto logged = FlowableRange(1, 3).DoOnNext(
[](int v) { Print("side: {}\n", v); });
auto cleaned = FlowableRange(1, 3).DoFinally(
[]() { Print("cleanup\n"); });
// --- First (emit first item, then complete) ---
auto firstOnly = First(FlowableRange(1, 100)); // emits 1, then completes
// --- Blocking operators (synchronous extraction) ---
// BlockingFirst — block until the first emission, return T by value
int first = BlockingFirst(FlowableRange(1, 100)); // 1
int last = BlockingLast(FlowableRange(1, 5)); // 5
// Empty/erroring sources throw std::out_of_range (or rethrow the upstream error).
// --- Custom sources: Create(fn, strategy) + FlowableEmitter ---
auto custom = Flowable<int>::Create(
[](FlowableEmitter<int>& em) {
for (int i = 1; i <= 3 && !em.State()->IsCancelled(); ++i) {
em.OnNext(i);
}
em.OnComplete();
},
BackpressureStrategy::Missing);
// --- Backpressure strategies (OnBackpressure*) ---
// OnBackpressureBuffer — buffer items when downstream can't keep up
auto buffered = OnBackpressureBuffer(FlowableRange(1, 10));
// OnBackpressureDrop — drop items when downstream can't keep up
auto dropped = OnBackpressureDrop(FlowableRange(1, 100));
// OnBackpressureLatest — keep only the most recent value
auto latest = OnBackpressureLatest(FlowableRange(1, 100));
// --- Defer — lazy factory (creates a Flowable per subscription) ---
int counter = 0;
auto deferred = FlowableDefer<int>([&counter]() {
counter++;
return FlowableJust(counter); // fresh source each subscribe
});
// Each subscription gets a new FlowableJust(counter) at subscribe-time
// --- Factory methods ---
FlowableJust(42); // single value, then complete
FlowableEmpty<int>(); // immediate complete
FlowableNever<int>(); // never emits, never completes
FlowableThrow<int>(ep); // immediate error
// --- Bridge to Future (teles/reactive/future_bridge.h) ---
auto fut = FlowableJust(7).ToFuture(); // resolves with the first value
auto flw = FromFuture<int>(some_future); // Future → Flowable
// --- Subjects (hot flowables) ---
PublishSubject<int> pub; // broadcast, no history
auto flw1 = pub.AsFlowable();
flw1.Subscribe([](int v) { Print("A: {}\n", v); });
pub.OnNext(1); // A: 1
pub.OnNext(2); // A: 2
BehaviorSubject<int> beh(0); // replays last value to new subscribers
beh.OnNext(42);
beh.AsFlowable().Subscribe(
[](int v) { Print("late: {}\n", v); }); // late: 42 (replayed)
ReplaySubject<int> repl(3); // bounded replay buffer (last 3)
repl.OnNext(10);
repl.OnNext(20);
repl.OnNext(30);
repl.AsFlowable().Subscribe(
[](int v) { Print("replay: {}\n", v); });
// replay: 10, replay: 20, replay: 30
// --- ConnectableFlowable (multicast) ---
// Publish wraps a source so it can be shared among multiple subscribers
auto connectable = Publish(FlowableRange(1, 5));
// Subscribe before connecting — all subscribers see the same emissions
connectable.Ref().Subscribe([](int v) { Print("A: {}\n", v); });
connectable.Ref().Subscribe([](int v) { Print("B: {}\n", v); });
// Connect starts broadcasting upstream to all subscribers
auto conn = connectable.Connect();
// Both A and B see 1, 2, 3, 4, 5
// Share — auto-connect on first subscriber, auto-disconnect on last unsubscribe
auto shared = Share(FlowableRange(1, 5));
shared.Subscribe([](int v) { Print("shared: {}\n", v); });
// --- Schedulers ---
// ImmediateScheduler runs tasks inline on the calling thread
teles::concurrency::ImmediateScheduler imm;
imm.Submit([] { Print("inline\n"); });
// Global thread pools (lazily initialized)
CpuPool()->Submit([] { Print("on cpu pool\n"); });
IoPool()->Submit([] { Print("on io pool\n"); });
Schedulers::Shutdown(); // optional teardown
System (teles::system)
Signal handling and crash diagnostics for production reliability.
#include <teles/teles.h>
using namespace teles;
using namespace teles::system;
// --- Signal handling (self-pipe pattern — callbacks run on a normal thread) ---
SignalHandler handler;
handler.Register(Signal::Interrupt, [](Signal s) {
Print("Caught signal: {}\n", SignalName(s));
// graceful shutdown logic here
});
handler.Register(Signal::Hangup, [](Signal) { ReloadConfig(); });
// Signal::Terminate, Signal::User1, Signal::User2, ... also available
// Block signals in a critical section (restored on scope exit)
SignalBlocker blocker(SignalSet{Signal::Interrupt, Signal::Quit});
// Ignore / restore default disposition
IgnoreSignal(Signal::Pipe); // SIG_IGN — don't crash on broken pipe
DefaultSignal(Signal::Pipe); // restore SIG_DFL
// Thread naming for diagnostics
SetThreadName("worker-1");
Print("thread: {}\n", ThreadName()); // "worker-1"
Print("tid: {}\n", CurrentThreadId());
// Spawn a configured thread: named/pinned before its first instruction
system::ThreadOptions opts;
opts.name = "db-worker";
opts.affinity = {0};
system::Thread worker(std::move(opts), [] { /* ... */ });
worker.TryJoinFor(teles::time::Duration::Milliseconds(500));
// --- Crash diagnostics ---
// Install a global crash handler for SIGSEGV/SIGABRT/SIGFPE/SIGILL/SIGBUS.
// The config also arms the minidump tier: a crash (or CaptureDump below)
// freezes every thread and a raw-clone child writes a standard MDMP file.
system::CrashHandlerConfig crash;
crash.callback = [](const system::CrashReport& report) {
// Invoked in a forked child — safe to use std::string, malloc, etc.
// Persist the report to a monitoring system, send an alert, ...
};
crash.log_file_path = "/var/log/myapp/crash.log"; // "" = stderr only
crash.dump_dir = "/var/log/myapp"; // "" = working dir
auto installed = system::InstallCrashHandler(crash); // Result<void, Error>
// Capture a minidump at any point (not just on crash) — the process
// survives and resumes. Optionally pin app-owned memory into every dump:
system::RegisterDumpRegion(&app_state, sizeof(app_state), "app-state");
auto dump = system::CaptureDump("pre-upgrade snapshot"); // Result<path>
// Capture a backtrace at any point (not just on crash)
auto frames = Backtrace(1, 32); // skip this frame, max 32 deep
Print("{}\n", FormatBacktrace(frames));
// CrashReport fields: signal, message, timestamp, threadId,
// stackTrace, platformInfo, threadName, dumpPath
Design notes:
SignalHandleruses the self-pipe pattern: the async-signal-safe handler only writes a byte to a pipe, and user callbacks execute on an internal reader thread — never inside a signal handler contextSignalBlockerwrapspthread_sigmaskand restores the previous mask on destructionInstallCrashHandlercollects the backtrace using only async-signal-safe functions, then forks a child process to invoke the user callback — this allows the callback to use non-signal-safe functions (std::string,malloc, etc.)- After writing the crash report, the handler re-raises the signal so the process terminates with the correct exit status
Application Layer
#include <teles/teles.h>
using namespace teles;
using namespace teles::serialization;
// --- JSON parsing and serialization ---
auto j = Json::Parse(R"({"name":"teles","version":1,"enabled":true})");
if (j.HasValue()) {
Json root = j.Value();
std::string name = root["name"].AsString(); // "teles"
bool enabled = root["enabled"].AsBool(); // true
Print("name: {}, enabled: {}\n", name, enabled);
}
// Build JSON programmatically
Json obj;
obj["port"] = Json(8080);
obj["host"] = Json("localhost");
Print("config: {}\n", obj.Dump()); // {"host":"localhost","port":8080}
// --- TELES_SERIALIZABLE: automatic ToJson generation ---
struct ServerConfig {
std::string host;
int port;
bool tls;
};
TELES_SERIALIZABLE(ServerConfig, host, port, tls)
ServerConfig cfg{"0.0.0.0", 443, true};
Json json = ToJson(cfg); // {"host":"0.0.0.0","port":443,"tls":true}
std::string str = ToJsonString(cfg); // compact JSON string
// --- Configuration management ---
using namespace teles::config;
ConfigManager manager;
// JSON config provider with dot-path traversal
auto cfgJson = Json::Parse(R"({"server":{"port":8080,"host":"0.0.0.0"},"debug":false})");
if (cfgJson.HasValue()) {
manager.AddProvider(std::make_shared<JsonConfigProvider>(cfgJson.Value(), "app", 0));
}
// Load from file
auto fileSrc = JsonConfigProvider::FromFile("/etc/myapp/config.json", 0);
if (fileSrc.IsOk()) {
manager.AddProvider(std::make_shared<JsonConfigProvider>(fileSrc.Value()));
}
// Environment variable provider (MYAPP_ prefix, type inference)
// e.g. MYAPP_SERVER_PORT=9090 overrides the JSON value
manager.AddProvider(std::make_shared<EnvConfigProvider>("MYAPP_", 10));
// Priority-ordered merge: higher priority provider wins
int port = manager.GetInt("server.port", 8080);
bool debug = manager.GetBool("debug", false);
std::string host = manager.GetString("server.host", "localhost");
System (teles::system)
Signal handling and crash diagnostics for production-grade applications.
| Component | Header | Description |
|---|---|---|
Signal enum |
system/signal_handling.h |
17 named signals (Interrupt, Terminate, SegFault, Abort, ...) mapped to platform constants |
ToNativeSignal() / FromNativeSignal() |
system/signal_handling.h |
Convert between Signal enum and native integer signal numbers |
SignalName() |
system/signal_handling.h |
Human-readable name for a Signal value |
SignalSet |
system/signal_handling.h |
Signal set builder: Add/Remove/Contains/Size, converts to sigset_t for pthread_sigmask |
SignalHandler |
system/signal_handling.h |
Self-pipe pattern handler: Register/Unregister callbacks that run on an internal thread (not in signal context) |
SignalBlocker |
system/signal_handling.h |
RAII guard around pthread_sigmask — blocks signals in scope, restores previous mask on destruction |
IgnoreSignal() / DefaultSignal() |
system/signal_handling.h |
Set SIG_IGN / SIG_DFL disposition for a signal |
CurrentThreadId() |
system/thread_info.h |
Stable uint64_t identifier for the calling thread |
ThreadName() / SetThreadName() |
system/thread_info.h |
Get/set the calling thread's name (pthread_getname_np / SetThreadDescription); truncated to 15 bytes on Linux |
Thread + ThreadOptions |
system/thread.h |
Native thread with spawn-time name/priority/affinity/stack-size (applied before the first instruction), bounded TryJoinFor, RAII join |
StackFrame |
system/crash_diagnostics.h |
Stack frame info: address, functionName, fileName, line, column |
Backtrace() |
system/crash_diagnostics.h |
Capture current call stack with skipFrames and maxDepth; symbols resolved via dladdr |
FormatBacktrace() |
system/crash_diagnostics.h |
Format vector<StackFrame> into readable text |
CrashReport |
system/crash_diagnostics.h |
Structured crash info: signal, message, timestamp, threadId, stackTrace, platformInfo, threadName, dumpPath |
FormatCrashReport() |
system/crash_diagnostics.h |
Format a CrashReport into a human-readable string |
InstallCrashHandler(CrashHandlerConfig) |
system/crash_diagnostics.h |
Install global handler for SIGSEGV/SIGABRT/SIGFPE/SIGILL/SIGBUS; async-signal-safe backtrace, fork-based callback, minidump tier. Result<void, Error> — an Err leaves nothing installed |
UninstallCrashHandler() / IsCrashHandlerInstalled() |
system/crash_diagnostics.h |
Remove crash handler / query installation state |
CaptureDump(reason) |
system/crash_dump.h |
On-demand standard-minidump capture of the whole process; synchronous, process-surviving, returns the dump path |
RegisterDumpRegion() / UnregisterDumpRegion() |
system/crash_dump.h |
Pin app-owned memory ranges into every dump (64-entry table, tagged) |
GetResolvedDumpTracerMode() |
system/crash_dump.h |
What DumpTracerMode::kAuto resolved to at install time (also recorded in every dump's marker) |
GetPlatformInfo() |
system/crash_diagnostics.h |
OS name, version, and architecture string |
Design notes:
SignalHandleruses the self-pipe pattern: the actual signal handler (installed viasigaction) only performs an async-signal-safewrite()to a pipe; user callbacks execute on an internal reader thread, so they are never constrained by async-signal-safety rules- Only one callback per signal is supported; re-registering replaces the previous callback
SignalBlockersaves the previous signal mask on construction and restores it on destruction — safe for nested blocking scopesInstallCrashHandleroperates in two phases: (1) the signal-safe handler collects the backtrace and writes to a file descriptor or stderr, then (2) forks a child process to invoke the userCrashCallback— this allows the callback to usestd::string,malloc,std::function, etc. without undefined behavior- After reporting, the crash handler re-raises the signal so the process terminates with the correct status (and core dumps are generated if enabled)
Backtrace()usesbacktrace()+dladdr()for symbol resolution;fileNameandlinemay be empty if debug symbols are unavailable
Serialization (teles::serialization)
JSON wrapper around nlohmann/json with automatic struct serialization via macros.
| Component | Header | Description |
|---|---|---|
Json |
serialization/json.h |
Opaque JSON value wrapper: Parse/Dump/DumpPretty, type queries (IsNull/IsBool/...), At/Set/operator[] const reads, Native access |
Json::Type |
serialization/json.h |
Type enum: Null/Bool/Number/String/Array/Object |
ToJson() |
serialization/serializer.h |
Built-in overloads for bool, int, int64_t, double, const char*, string, vector, map<string,V> |
FromJson<T>() |
serialization/serializer.h |
Deserialize built-in types from Json (bool, int, int64_t, double, string) |
FromJsonVector<T>() |
serialization/serializer.h |
Deserialize JSON array to vector<T> |
To<T>() / TryFrom<T>() |
serialization/serializer.h |
Generic serialize/deserialize entry points |
ToJsonString() / FromJsonString<T>() |
serialization/serializer.h |
Convenience: serialize to string / parse + deserialize in one call |
TELES_SERIALIZABLE |
serialization/serializer.h |
Macro generating ToJson() for user structs (1–12 fields) |
Design notes:
Jsonfully encapsulates nlohmann/json — users never interact with the upstream namespace directlyTELES_SERIALIZABLE(Type, field1, field2, ...)generates aToJson(const Type&)free function found via ADL; supports 1–12 fieldsFromJsonString<T>()returnsOptional<T>— emptyOptionalindicates a parse failure
Configuration (teles::config)
Multi-provider configuration with priority-ordered merge, JSON file loading, and environment variable support.
| Component | Header | Description |
|---|---|---|
ConfigValue |
config/config.h |
Type-safe value: Bool/Int/Double/String/Null with As* and As*Or accessors |
ConfigProvider |
config/config.h |
Abstract interface: Name()/Priority()/Get(key) — higher priority overrides lower |
JsonConfigProvider |
config/config.h |
JSON-backed provider with dot-path traversal ("server.port") and FromFile factory |
EnvConfigProvider |
config/config.h |
Environment variable provider with prefix transformation and type inference (int/double/bool/string) |
ConfigManager |
config/config.h |
Multi-provider priority merge: AddProvider/RemoveProvider, GetBool/GetInt/GetDouble/GetString with defaults |
Design notes:
ConfigManager::AddProvider()sorts providers by priority descending — the first provider that has a key wins on lookupJsonConfigProvider::Get()traverses dot-separated paths (e.g."server.port"→data["server"]["port"])EnvConfigProvidertransforms keys by uppercasing and replacing.with_, prefixed with the configured prefix (e.g."server.port"with prefix"MYAPP_"→"MYAPP_SERVER_PORT")EnvConfigProviderinfers types: numeric strings becomeIntorDouble,"true"/"1"/"yes"becomeBool(true), everything else staysStringJsonConfigProvider::FromFile()returnsResult<JsonConfigProvider>for structured error handling on file I/O or JSON parse failures
Core Types (teles::core)
Self-implemented C++14 standard-library gaps and community sugar.
| Component | Header | Description |
|---|---|---|
Optional<T> |
core/optional.h |
Self-implemented optional with Map/AndThen/Filter/OrElse combinators |
Variant<Ts...> |
core/variant.h |
Type-safe union (wraps mpark::variant) |
StringView |
core/string_view.h |
Non-owning string reference (~150 lines) |
Span<T> |
core/span.h |
Non-owning array view (~120 lines) |
Byte |
core/byte.h |
Type-safe byte type |
Platform |
core/platform.h |
Compile-time OS/compiler/arch detection with 8 categories |
Assert |
core/assert.h |
TELES_ASSERT / TELES_CHECK macros |
Defer / TELES_SCOPE_* |
core/utility.h |
RAII deferred execution |
NotNull<T> |
core/not_null.h |
Non-null pointer wrapper |
Any |
core/any.h |
Type-erased single value |
FunctionRef<Sig> |
core/function_ref.h |
Non-owning callable reference |
Community Sugar (Phase 2):
| Component | Header | Description |
|---|---|---|
TELES_TRY / TELES_TRY_ASSIGN |
core/try_macros.h |
Rust-style ? operator for Result error propagation |
Overloaded<Fs...> |
core/overloaded.h |
Multi-lambda visitor via inheritance pack |
Literals (_sv, _s, _ms, _KB, ...) |
core/literals.h |
User-defined literal operators |
SourceLocation |
core/source_location.h |
Lightweight source-position capture (TELES_HERE) |
HashCombine / HashValue |
core/hash.h |
Boost-style hash combining for heterogeneous args |
bitops:: |
core/bitops.h |
CLZ/CTZ/PopCount/Rotate/IsPowerOfTwo/Bit — constexpr intrinsics |
IsDetected / DetectedOrT |
core/detect.h |
N4502 detection idiom for C++14 |
ArraySize / MakeArray / MakeSpan |
core/array_utils.h |
Array utilities |
Box<T> |
core/utility.h |
unique_ptr alias |
Match(optional, onSome, onNone) |
core/match.h |
Functional pattern matching on Optional<T> |
Memory (teles::memory)
Allocator model with diagnostics, alignment, and factory functions.
| Component | Header | Description |
|---|---|---|
IAllocator |
memory/allocator.h |
Abstract allocator interface (Allocate/Deallocate/Name) |
MallocAllocator |
memory/allocator.h |
Thread-safe malloc/free reference implementation |
DefaultAllocator() / SetDefaultAllocator() |
memory/allocator.h |
Process-wide singleton with one-shot replacement |
PoolAllocator |
memory/pool_allocator.h |
Fixed-block O(1) allocator via intrusive free list |
ArenaAllocator |
memory/arena_allocator.h |
Bump-pointer allocator with chunk linked list, Reset() |
ScopedArena |
memory/scoped_arena.h |
RAII wrapper around ArenaAllocator |
TrackingAllocator |
memory/tracking_allocator.h |
Debug wrapper: guard bytes, fill patterns, leak detection, stats |
AlignedAlloc / AlignedFree |
memory/aligned.h |
Platform-native aligned allocation + constants |
MakeUnique / MakeShared |
memory/factory.h |
Allocator-aware smart-pointer factories |
GetProcessMemory() |
memory/process_info.h |
RSS, virtual, and peak-RSS reporting (Linux/macOS/Windows) |
| Debug fill constants | memory/debug_fill.h |
0xCD/0xDD/0xFD patterns + sanitizer coexistence gating |
Design principles:
Allocatereturnsnullptron failure (never throws)- Debug instrumentation (guard bytes, fill patterns) is compile-time gated against ASan/MSan to avoid double overhead
TrackingAllocatordegrades to stats-only mode when a sanitizer is active- Pool and arena allocators are not thread-safe (callers synchronize)
Error & Result (teles::error)
Result-first error handling with functional combinators.
| Component | Header | Description |
|---|---|---|
Error |
error/error.h |
Structured error: code + message + category + cause chain |
ErrorCategory |
error/error.h |
System / Network / IO / Config / InvalidArgument / Runtime / Unknown |
Result<T, E> |
error/result.h |
Rust-inspired result type with Map/MapErr/AndThen/OrElse/Inspect/Unwrap |
Ok() / Err() |
error/result.h |
Concise construction helpers |
| Exception hierarchy | error/exceptions.h |
TelesException base + 6 category-specific subclasses |
Result<T, E> combinators:
| Combinator | Signature | Description |
|---|---|---|
Map(f) |
T → U |
Transform Ok value, propagate Err |
MapErr(f) |
E → F |
Transform Err value, propagate Ok |
AndThen(f) |
T → Result<U,E> |
Monadic bind; Err short-circuits |
OrElse(f) |
E → Result<T,F> |
Error recovery; Ok short-circuits |
Inspect(f) |
T& → void |
Side-effect on Ok, returns *this |
InspectErr(f) |
E& → void |
Side-effect on Err, returns *this |
Unwrap() |
Value or throw on Err | |
UnwrapOr(fallback) |
Value or fallback | |
UnwrapOrElse(f) |
Value or f(error) |
String (teles::str)
Locale-independent string operations, UTF-8 codec, and encoding conversion.
| Component | Header | Description |
|---|---|---|
ascii:: classifiers |
str/ascii.h |
11 classifiers (IsDigit, IsAlpha, IsSpace, ...) |
| String operations | str/string_ops.h |
Split/Trim/Replace/Search/Pad/Repeat/Truncate/Partition |
| Case conversions | str/case.h |
ToCamelCase / ToSnakeCase / ToKebabCase / ToPascalCase / ToTrainCase |
StringBuilder |
str/string_builder.h |
Mutable builder with AppendFmt() and StrCat() |
NaturalCompare |
str/natural_compare.h |
Numeric-aware ordering ("file2" < "file10") |
| Layout helpers | str/string_ops.h |
WordWrap, Indent, Dedent |
| UTF-8 codec | str/utf8.h |
Validate/Length/Encode/Decode/Substring/Iterator, ToUpper/ToLower |
| Encoding conversion | str/utf_convert.h |
UTF-8 ↔ UTF-16/UTF-32/Wide with BOM detection |
All functions are locale-independent (pure ASCII range tests, ICU-free).
Format (teles::format)
Enum name tables and null-safe ToString helpers. Everything else is {fmt} — a public dependency — used directly.
| Component | Header | Description |
|---|---|---|
ToString null-safe overloads |
format/to_string.h |
const char* and nullptr_t (fmt covers scalars/containers natively) |
FormatEnum / TELES_ENUM |
format/enum_format.h |
Enum-to-string via name table + X-macro generating Names/Count/ToString/TryParse |
Concurrency (teles::concurrency)
Thread pools, futures, channels, synchronization primitives, and concurrency patterns.
| Component | Header | Description |
|---|---|---|
ThreadPool |
concurrency/thread_pool.h |
Configurable pool with priority queue, timed/periodic scheduling, metrics |
ThreadPoolConfig / ThreadPoolMetrics |
concurrency/thread_pool.h |
Config (core/max threads, keepAlive, queue capacity, RejectionPolicy) + runtime stats |
RejectionPolicy |
concurrency/thread_pool.h |
Abort / CallerRuns / Discard / DiscardOldest |
Future<T> / Promise<T> |
concurrency/future.h |
Shared-state future: Get/IsReady/WaitFor/WaitUntil/TryGet + cancellation |
Ready() / Then() / ThenOn() |
concurrency/future_combinators.h |
Value factory, continuation chaining (inline or on a pool) |
OnError() / WithTimeout() |
concurrency/future_combinators.h |
Error recovery continuation + deadline race |
All() / Any() / ThenCompose() |
concurrency/future_combinators.h |
Wait-all, race (first-wins), flatMap chaining |
Async() / AsyncOn() |
concurrency/future_combinators.h |
Submit to CpuPool or a specified pool |
CpuPool() / IoPool() / SinglePool() |
concurrency/schedulers.h |
Lazy global pools: fixed CPU, elastic IO, single-thread |
Schedulers::Shutdown() |
concurrency/schedulers.h |
Teardown for all global pools |
Channel<T> |
concurrency/channel.h |
Go-style bounded/unbounded channels with timed SendFor/RecvFor |
Mutex<T> / RecursiveMutex<T> |
concurrency/mutex.h |
Timed mutex with data slot + lambda sugar; reentrant variant |
RwLock<T> |
concurrency/rwlock.h |
Writer-preference read-write lock with ReadGuard/WriteGuard |
Atomic<T> / AtomicIntegral<T> / AtomicEnum<T> |
concurrency/atomic.h |
std::atomic wrappers with teles MemoryOrder enum |
AtomicFlag / AtomicOptional<T> |
concurrency/atomic.h |
Flag and optional-with-CAS atomic types |
CondVar / Semaphore / WaitGroup |
concurrency/sync.h |
Condition variable, counting semaphore, wait-group |
Latch / Barrier / Once |
concurrency/sync.h |
Countdown latch, generation barrier (timed wait + IsBroken()), one-time call |
Design notes:
Future<T>/Promise<T>use a final shared-state control block (nostd::future);Promiseis move-only,Futureis move-only and one-shotRejectionPolicy::Abort(the default) rejects by settling the future with anError;CallerRunsexecutes the task inline in the submitting threadChannel<T>default-constructs as unbounded;Channel(capacity)constructs bounded.Close()signals completion;Recv()returns emptyOptionalon a closed/empty channelSelectpolls multiple channels and returns the first availableSelectResult<T>(index + value); returns{index: -1}when all channels are closed and empty
Filesystem (teles::fs)
Cross-platform path manipulation, file/directory operations, streaming I/O, and memory-mapped files.
| Component | Header | Description |
|---|---|---|
Path |
fs/path.h |
Cross-platform path (wraps ghc::filesystem): decomposition, join (/), normalize, iterate components |
FileStatus / FileType |
fs/file_ops.h |
File metadata: type, size, timestamps (modified/accessed/created nanos), permissions |
Status() / Exists() / IsFile() / IsDir() |
fs/file_ops.h |
File queries returning Result<T> |
CreateDir() / Remove() / RemoveAll() / Rename() |
fs/file_ops.h |
Directory operations |
Copy() / CopyRecursive() |
fs/file_ops.h |
File/tree copy; recursive variant has symlink-cycle detection |
CreateSymlink() / ReadSymlink() |
fs/file_ops.h |
Symlink creation and resolution |
SetPermissions() |
fs/file_ops.h |
POSIX-style permission bitmask |
ReadFile() / ReadFileBytes() / WriteFile() / AppendFile() |
fs/file_ops.h |
One-shot file read/write |
FileStream |
fs/file_stream.h |
RAII streaming file I/O: Read/Write/Seek/Tell/Flush/Close with configurable buffer |
FileMode / SeekOrigin |
fs/file_stream.h |
Open modes (Read/Write/Append/ReadWrite) + seek origins (Begin/Current/End) |
DirectoryIterator |
fs/directory.h |
Single-level directory iteration (STL-compatible input iterator) |
RecursiveDirectoryIterator |
fs/directory.h |
Recursive directory walk with Depth() and Pop() |
MappedFile |
fs/directory.h |
Memory-mapped file (mmap): ReadOnly/ReadWrite, Advise/Prefetch/Flush |
TempDir / TempFile |
fs/temp.h |
RAII temporary directory/file (auto-deleted on destruction) |
Glob() / GlobMatch() |
fs/glob.h |
Glob pattern expansion and pure pattern matching |
Design notes:
- All operations return
Result<T>for structured error handling — no exceptions thrown by the API FileStreamwraps C stdioFILE*with RAII; move-only (non-copyable); configurable buffer size (default 4096)Status()populates all timestamp fields (modified/accessed/created) via POSIXstat; createdNanos may be 0 on filesystems without birth timeCopyRecursivetracks canonical paths to detect and skip symlink cyclesMappedFileuses platform-native mmap (Linux/macOS: mmap+madvise, Windows: CreateFileMapping); falls back gracefully on failure
I/O (teles::io)
Networking (TCP/UDP/TLS), X.509, and async file I/O — native fds driven by the signal-driven EventLoop reactor (no external proactor library).
| Component | Header | Description |
|---|---|---|
EventLoop |
concurrency/event_loop.h |
Signal-driven completion engine: epoll (POSIX) / IOCP (Windows): Run/Stop/RunOnIo — fd registration internal (IoEngine seam, .omo/plans/io-model-redesign.md) |
TcpConnection |
io/tcp.h |
TCP client (signal-driven): Connect() returns concurrency::Future<void> (Get() yields Result<void>), buffered Write(), OnConnected/OnData/OnWritable/OnError/OnClosed, SetTimeout/SetNoDelay/SetKeepAlive |
TcpAcceptor |
io/tcp.h |
TCP server: binds and listens on construction, Port() reads back the assigned port, OnAccepted delivers adopted connections |
UdpSocket |
io/udp.h |
UDP: Bind(0) + LocalPort() for ephemeral ports, Connect/SendTo, OnPacket signal, broadcast/multicast options |
TlsConnection / TlsContext |
io/tls.h |
TLS 1.2/1.3 layered over TcpConnection signals (mbedtls-backed, platform-agnostic) |
X509Certificate / PrivateKey / X509Verifier |
io/x509.h |
X.509 RAII types (no mbedtls headers leak into public API) |
SocketPair |
io/socket_pair.h |
Portable socketpair (raw-fd tests + EventLoop fd API) |
ByteBuffer |
io/byte_buffer.h |
Immutable refcounted byte slice: O(1) slicing, implicit conversion to Bytes |
RecvBuffer |
io/recv_buffer.h |
Mutable recv-side accumulator for protocol parsing |
AsyncReadFile() / AsyncWriteFile() / AsyncAppendFile() |
io/async_file.h |
Async file I/O offloaded to a ThreadPool; returns concurrency::Future<T> (Get() yields Result<T>) |
SetTimeout() / SetInterval() / SetTimer() |
concurrency/timer.h |
One-shot, periodic (MissedTick policy), and deadline timers — RAII Disposable cancellation |
Design notes:
- The data path is signals, not callbacks or std futures:
OnData(conn, data, len)pushes received bytes — the data pointer is valid only during the slot call TcpConnection::Connect()returnsconcurrency::Future<void>(Get() yieldsResult<void>, never throws); async file operations also returnconcurrency::Future— nostd::futurein the libraryTcpConnection/UdpSocketinheritenable_shared_from_this; the EventLoop holds the final reference while the fd is registered —Close()it (or wait for error/EOF) to release- Ephemeral-port pattern:
TcpAcceptor::Create(loop, 0)+Port(),UdpSocket::Bind(0)+LocalPort()— never probe ports with raw sockets MissedTickpolicies:Burst(catch up all missed ticks),Delay(realign to period),Skip(discard missed)
Reactive (teles::reactive)
Push-based composable streams — Flowable<T> with Rx-style operators, backpressure, schedulers, and subjects.
| Component | Header | Description |
|---|---|---|
Flowable<T> |
reactive/flowable.h |
Push-based stream; Subscribe() returns a Subscription (RAII auto-cancel), SubscribeAndForget() for fire-and-forget, Subscribe(Subscriber<T>&) for explicit demand control |
Subscriber<T> |
reactive/subscriber.h |
Callback triple (on_next / on_error / on_complete) bound to a SubscriptionState |
Subscription |
reactive/subscription.h |
RAII cancellation handle (move-only); Cancel() / Request(n) via its state |
Single<T> / Maybe<T> / Completable |
reactive/single.h / maybe.h / completable.h |
0/1-item reactive types built on Flowable (ToFlowable() / FromFlowable()) |
Scheduler |
concurrency/scheduler.h |
Abstract scheduler interface: Submit() / SubmitAfter() / Now() |
ImmediateScheduler |
concurrency/schedulers.h |
Runs tasks inline on the caller thread |
ThreadPool |
concurrency/thread_pool.h |
Worker-thread pool implementing Scheduler; Submit() returns a Future<T> |
Operators — each operator lives in its own header under reactive/operators/<category>/ (transform, filter, combining, scheduling, side_effect, aggregate, factories, backpressure, convert); the umbrellas reactive/operators.h and reactive/reactive.h include them all. Most operators are available both as free functions and as Flowable<T> chain methods (.Map(), .Filter(), …):
| Category | Operator | Description |
|---|---|---|
| Factory | FlowableJust() / FlowableRange() / FlowableInterval() / FlowableEmpty() / FlowableNever() / FlowableThrow() / FlowableFromIterable() |
Create source Flowables (FlowableFromIterable accepts any STL container or initializer_list) |
| Factory | FlowableDefer() / Flowable<T>::Create(fn, strategy) |
Lazy factory / custom emitter source with an explicit BackpressureStrategy |
| Transform | Map() / Scan() / FlatMap() / ConcatMap() / SwitchMap() |
Element transformation, rolling accumulator, inner-Flowable merge (interleaved / sequential / cancel-previous) |
| Filter | Filter() / Take() / Skip() / Distinct() / DistinctUntilChanged() / First() / Last() / ElementAt() / IgnoreElements() |
Predicate- and position-based filtering |
| Combine | Concat() / Merge() / Amb() / StartWith() / Zip() / CombineLatest() / WithLatestFrom() |
Multi-source combining (sequential, interleaved, race, prepend, element-wise) |
| Windowing | Window() / GroupBy() / Buffer() |
Split into sub-streams / keyed groups / bounded chunks |
| Aggregate | Reduce() / Count() / Collect() / ToList() |
Terminal reductions emitting a single value |
| Error | OnErrorReturnItem() / Retry() |
Fallback value on error / resubscribe on error |
| Utility | DoOnNext() / DoOnError() / DoOnComplete() / DoFinally() / Timestamp() / Delay() / Debounce() / Sample() |
Side effects and timing without altering the payload |
| Async | ObserveOn() / SubscribeOn() / Timeout() / Serialize() |
Scheduler hopping, serialization of concurrent emissions |
| Blocking | BlockingFirst() / BlockingLast() |
Block until first/last emission; return T by value (throw on empty/erroring source) |
| Backpressure | OnBackpressureBuffer() / OnBackpressureDrop() / OnBackpressureLatest() |
Buffer, drop, or keep-latest when downstream is slow |
| Future | ToFuture() / FromFuture() |
Bridge Flowable<T> ↔ concurrency::Future<T> (reactive/future_bridge.h) |
Subjects (reactive/subjects.h) — hot, multicast Flowables:
| Subject | Description |
|---|---|
PublishSubject<T> |
Broadcast to current subscribers; no replay history |
BehaviorSubject<T> |
Replays the most recent value to new subscribers; requires initial value |
ReplaySubject<T> |
Replays all (or bounded) emitted values to new subscribers; optional max_size buffer |
ConnectableFlowable<T> |
Multicast wrapper: Ref() for subscriber view, Connect() to start upstream, RefCount() for auto-connect/auto-disconnect |
Publish() |
Free function: wraps a Flowable<T> into a ConnectableFlowable<T> |
Share() |
Free function: Publish(src).RefCount() — auto-connecting multicast |
Design notes:
Subscribe(callbacks...)requests unbounded demand automatically;Subscribe(Subscriber<T>&)gives the caller full control viaSubscriptionState::Request(n)/kUnboundedDemand- Each operator creates per-subscription state, so multiple subscriptions get independent state
Subscriber::OnNextwraps user callbacks in try/catch — uncaught exceptions are routed toon_error(FR-209)OnErrorandOnCompleteare terminal — the first one fires and subsequent calls are suppressedconcurrency::CpuPool()/IoPool()/SinglePool()are lazily initialized global ThreadPools sharingGlobalTimerQueue();Schedulers::Shutdown()releases themTestScheduleruses a priority queue keyed by(virtual_time, sequence)—AdvanceTime()flushes all due tasks in orderConnectableFlowable::RefCount()subscribes to the internal subject before connecting upstream, ensuring no synchronous emissions are missedBlockingFirst()/BlockingLast()capture theSubscriptioninternally and release it after unblocking — empty sources throwstd::out_of_range; upstream errors are rethrown
Architecture: Dogfooding
Teles uses its own primitives internally throughout every module: locks and
atomics via teles::sync (Mutex<T> is pimpl'd over base::MutexCore in the
internal freestanding base layer src/base/), blocking sleeps via
time::SleepFor/SleepUntil, and async results via concurrency::Future.
This dogfooding is lint-enforced, not aspirational: tools/check_layering.py
(run via ctest as teles_layering) fails raw std::mutex/std::thread/
socket-syscall usage outside the single-point base layer and the shrinking
out-of-scope baseline, keeping the abstractions battle-tested in production
code paths.
Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Class / Type | PascalCase | Result, PoolAllocator |
| Method / Function | PascalCase | IsOk(), Allocate() |
| Private member | snake_case_ | code_, message_ |
| Macro / Constant | UPPER_SNAKE | TELES_TRY, kCacheLine |
| Namespace | lowercase | teles::core, teles::memory |
| Enum value | PascalCase | ErrorCategory::System |
Namespace Strategy
Layered namespaces with root aliases for common types:
teles::core:: — core types, sugar utilities
teles::memory:: — allocators, memory diagnostics
teles::error:: — Error, Result, exceptions
teles::str:: — string operations, UTF codecs
teles::format:: — enum name tables (TELES_ENUM), null-safe ToString
teles::concurrency:: — thread pools, futures, channels, sync primitives
teles::fs:: — paths, file ops, streaming I/O, memory-mapped files
teles::io:: — networking, event loop, async file I/O, timers
teles::reactive:: — Flowable<T>, operators, subjects, schedulers
teles::system:: — signal handling, crash diagnostics, thread info
teles::serialization:: — JSON wrapper, serialization macros
teles::config:: — configuration management, multi-provider merge
Root-level aliases (in teles::): Optional, Variant, StringView, Span,
Byte, Error, Result, Ok, Err.
Testing
cmake -B build -DTELES_BUILD_TESTS=ON
cmake --build build
cd build && ctest --output-on-failure
Tests use Google Test (unit tests) and rapidcheck (property-based testing). The sanitizer matrix (ASan + UBSan + TSan + LSan) runs on x86_64 CI.