Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
Loading...
Searching...
No Matches
README.en

⚡ Aria

Modern MVVM framework for C++23 (C++20 minimum) · cross-platform · layered · coroutine-first
One shared core: Windows / macOS / Linux / iOS / Android / Web
C++23 supported License: MIT CI Platform

🌟 Flagship example: AriaTools

Start with AriaTools to see Aria in a real application. It is Aria's single flagship cross-platform example, driving Qt, iOS, Android, and Web from one C++ ViewModel. This repository now stays focused on the framework, acceptance tests, and minimal documentation snippets.

🚀 Aria in 30 seconds

Aria splits a screen in two. The ViewModel is plain C++ and knows nothing about any UI library; the View is native widgets. BindingEngine joins them, and it only ever talks to the IViewAdapter interface — so porting means swapping the adapter, nothing else.

Upper half — the ViewModel (plain C++, unit-testable, shared by every platform)

// Splitting a bill: total ÷ people = each person's share.
struct BillViewModel {
aria::Property<double> bill{100.0}; // read-write state
// Computed is a read-only derived value. You never write its
// dependency list: the first evaluation reads bill and people, and
// those two are recorded as its dependencies automatically.
aria::Computed<double> per_person{[this] {
return bill.get() / people.get();
}};
};
Definition property.hpp:103
T get() const
Auto-tracked read.
Definition property.hpp:138

There is no UI in that code and no UI header included — it runs under a console test.

Lower half — wiring up the View (a dozen lines per platform; the UI itself stays native)

First, the thing most likely to be misread: you do not write the UI in C++. Buttons, layout and animation are still authored the usual way — Qt Designer, Storyboard, Compose, HTML. The code below only hands widgets that already exist over to the engine, and the three steps never change: ① construct the platform adapter ② build a BindingEngine from it ③ bind a widget to a Property.

Qt6 (Windows / macOS / Linux · plain C++)

auto adapter = std::make_shared<aria::adapters::qt6::QtAdapter>();
BillViewModel vm;
// label_view wraps the QLabel you dragged out in Qt Designer
aria::adapters::qt6::QtView label_view{real_label};
engine.bind_text_projected(vm.per_person, label_view,
[](double v) { return std::format("¥{:.2f}", v); });
Wraps any QWidget* (or QObject*) as an IView.
Definition qt_view.hpp:25
BindingEngine: connects ViewModel properties to platform views via an adapter.
Definition binding_engine.hpp:103
void bind_text_projected(Src &src, IView &view, Project project)
Bind a read-only text view to src, rendered through project (T -> std::string).
Definition binding_engine.hpp:323
iOS / UIKit (the wiring file is Objective-C++ .mm; the UI is still Storyboard / SwiftUI)

#import "aria/adapters/uikit/UIKitAdapter.hpp"
auto adapter = std::make_shared<aria::adapters::uikit::UIKitAdapter>();
aria::binding::BindingEngine engine(adapter, ui_dispatcher,
aria::binding::BindingEngine::DispatchPolicy::SmartMarshal);
// Wrap the UILabel* from your Storyboard so C++ can bind to it
auto label = std::make_shared<aria::adapters::uikit::UIKitView>(self.totalLabel);
engine.bind_text_projected(vm.per_person, *label,
[](double v) { return std::format("¥{:.2f}", v); });

UIKitView retains the UIView* under ARC and, on destruction, tells BindingEngine to drop its subscriptions while the native view is still valid — so no callback ever reaches a released widget.

macOS / AppKit (same shape: .mm + NSView)

#import "aria/adapters/appkit/AppKitAdapter.hpp"
auto adapter = std::make_shared<aria::adapters::appkit::AppKitAdapter>();
aria::binding::BindingEngine engine(adapter, ui_dispatcher,
aria::binding::BindingEngine::DispatchPolicy::SmartMarshal);
auto label = std::make_shared<aria::adapters::appkit::AppKitView>(self.totalField);
engine.bind_text_projected(vm.per_person, *label, /* ... */);
Android (UI in Kotlin / Compose; C++ only does the wiring)

// Called on the Android UI thread with real android.view.View objects
auto adapter = std::make_shared<aria::adapters::jni::JniAdapter>(env);
aria::adapters::jni::JniView total_view(env, total_text_view);
engine.bind_text_projected(vm.per_person, total_view,
[](double v) { return std::format("¥{:.2f}", v); }); // → TextView
Wraps an Android View (jobject) as an IView.
Definition JniAdapter.hpp:60

Kotlin-side listeners forward native events back in (adapter->notify_text_changed(...) / notify_click(...)), so listener ownership stays on Android while the C++ side stays strongly typed. Compose has no addressable view object; use the side-channel shape from the adapter guide.

Web (no C++ in the browser — the frontend is HTML/JS, C++ runs server-side)

config.port = 9090;
auto http = std::make_shared<aria::adapters::http::HttpAdapter>(config);
// Here a "widget" is a string ID matching a DOM element in the browser
auto& total = http->register_view("total", "text");
engine.bind_text_projected(vm.per_person, total,
[](double v) { return std::format("¥{:.2f}", v); });
http->start(); // Property changes go out over SSE; user input comes back over REST
Configuration for HttpAdapter.
Definition http_config.hpp:15
std::uint16_t port
TCP port.
Definition http_config.hpp:23

That is the point: five wiring snippets that look nearly identical, and the BillViewModel above is byte-for-byte unchanged across all of them. Porting costs you those dozen lines, not your business logic.

After wiring — mutate data, the UI follows

Once bound, the rest is platform-independent. The code below behaves identically on all five platforms, and not one line of refresh code is written by hand:

BillViewModel vm; // per_person = 100/2 = ¥50.00
// ... bound to a label via any of the platforms above ...
vm.people = 4; // label → ¥25.00
vm.bill = 200.0; // label → ¥50.00

Change either bill or people and per_person recomputes and pushes to the label — because its dependencies were recorded automatically on the Computed's first evaluation. You never wrote anything resembling "when people changes, update the label".

One detail worth knowing when you change several values in a row:

// One at a time → one push each, so the label flashes an intermediate value
vm.bill = 300.0; // label → ¥150.00 ← intermediate
vm.people = 4; // label → ¥75.00
// Wrapped in batch → a single push at the end, no intermediate state
vm.bill = 1200.0;
vm.people = 8;
}); // label → ¥150.00 (once)
auto batch(Fn &&fn) -> decltype(fn())
Sugar: batch([&]{ firstName = "..."; lastName = "..."; }).
Definition graph.hpp:369

And a convenient default: if the final result equals the current value, nothing is notified at all. Following on from above, a batch setting bill=600, people=4 (still 150) leaves the label untouched.

The whole architecture in one picture — upper half is the pure C++ ViewModel, the middle is BindingEngine (which only knows the IViewAdapter interface), and the bottom row is the five native adapters:

Aria architecture overview

Continue with the binding guide, the per-platform adapter guides, the cookbook, or the full four-platform AriaTools application.

🎯 Where Aria fits

Aria does one thing: it extracts the reactive engine and binding layer out of the UI framework, as a plain C++ library supporting C++23, independent of any UI toolkit.

A ViewModel is an ordinary C++ class — no framework base class, no macros, no code generator. UI layers plug in through IViewAdapter; five adapters ship in-tree today (Qt6 / AppKit / UIKit / JNI / HTTP). Swapping the UI toolkit does not touch the ViewModel.

Know the costs before you pick it:

Trade-off What it means
C++20 minimum; C++23 supported Full coroutine and concepts support (GCC 12+ / Clang 15+ / MSVC v143). C++17 projects cannot use it.
No widgets Aria draws nothing. Widgets, layout and animation stay with your UI toolkit; Aria only owns the data flow between state and view.
Template layer is source-compatible only aria-abi / aria-runtime / aria-binding are ABI-stable within a major version; Property<T> and friends need a recompile across versions.
Adapters are on you Only the five adapters above work out of the box. A new toolkit means implementing an IViewAdapter (see the adapter guides).
Young project Ecosystem, tutorials and third-party components are nowhere near a mature framework's. AriaTools is currently the only real application using it.

Good fit: you already have a C++ business core, want to reuse one copy of that logic across platforms, and want each platform to keep its native UI.

Poor fit: you want "one codebase including the UI". That is what full UI frameworks like Flutter and Qt Quick are for — they have mature reactive binding of their own, and Aria does not try to replace them.

✨ Core features

  • 📦 Template-based reactive coreProperty<T> / Computed<T> / Effect / Command<> / ObservableList<T> / Validator<T> share one reactive dependency-graph engine. Computed auto-tracks deps; reactive::batch / reactive::untracked for fine control.
  • 🔌 Shared foundation and ABI layeraria::core automatically links aria::abi for shared graph, diagnostics and signal storage. Binary compatibility requires matching compiler, standard library, build options and major version. Rebuild template code and its containing types after updates.
  • C++ coroutinesTask<T>, executors, co_await schedule_on(pool). Async code reads like sync code.
  • 🖥 Adapter abstraction (IViewAdapter) — Qt6 / AppKit / UIKit / JNI / HTTP. Any UI toolkit, same business logic.

🏗 Architecture (10 modules)

┌────────────────────────────────────────────────────────────────────────┐
│ Application │
└────────────────────────────────┬───────────────────────────────────────┘
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Qt6 adapter │ │ JNI adapter │ │ HTTP adapter │ (optional
│ (Win/Mac/Lin)│ │ (Android) │ │ REST/SSE Web │ modules;
│ AppKit/UIKit │ │ │ │ Web browser │ opt-in)
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
└───────────────────┴───────────────────┘
┌─────────────────────────────────┐
│ aria-binding (SHARED) │
│ BindingEngine + IViewAdapter │
└────────────────┬────────────────┘
┌──────────────────────┴───────────────────────┐
▼ ▼
┌───────────────────┐ ┌────────────────────┐
│ aria-runtime │ │ aria-async │
│ (SHARED .dylib) │ │ (header-only) │
│ EventBus │ │ Task<T> │
│ Container │ │ Scheduler │
│ Dispatcher │ │ Executor │
│ Logger │ │ schedule_on │
└───────┬───────────┘ └─────────┬──────────┘
└──────────────────┬─────────────────────────—┘
┌─────────────────────────────┐
│ aria-core (header-only) │
│ Property / Computed / Cmd │
│ ObservableList / Validator │
│ Subscription │
└──────────────┬──────────────┘
┌─────────────────────────────┐
│ aria-abi (SHARED) │
│ Type-erased Signal/Slot │
│ ABI-stable, no templates │
└─────────────────────────────┘
Module Type Depends on Notes
aria-abi SHARED by default Threads Compiled foundation: signals, shared reactive graph, diagnostics storage, scheduler base, and version metadata. Static builds are supported.
aria-core header-only abi All the templates: Property, Computed, Command, ObservableList, Validator. Source-compatible only (not ABI-stable).
aria-async header-only core Coroutine Task<T>, executors. Source-compatible only.
aria-runtime SHARED core, abi EventBus / Container / Dispatcher / Logger — singletons live in one dylib. ABI-stable (non-template exports).
aria-binding SHARED core, runtime BindingEngine, IViewAdapter. ABI-stable (non-template exports).
Adapters SHARED/STATIC binding Qt6 / AppKit / UIKit / JNI / HTTP (each opt-in). WASM is conditional roadmap work.

📋 Requirements

  • CMake >= 3.20
  • Compiler with full C++20 support:
    • GCC >= 12 (the MSYS2 UCRT64 toolchain on Windows)
    • Clang >= 15 (AppleClang 15+ on macOS/iOS)
    • MSVC v143 / Visual Studio 2022 (Windows, see below)
  • C++23 is opt-in with -DCMAKE_CXX_STANDARD=23; C++20 remains the minimum. See the evaluation.
  • (optional) Qt6 >= 6.4 (for the Qt6 adapter)

Windows is supported on two toolchains: MSYS2 UCRT64 (GCC) and MSVC / Visual Studio 2022. Pick whichever fits your team's existing stack — both build the full framework + tests + adapters from a single tree, no source forks. See "Windows toolchains" below.

🚀 Quick start

git clone https://github.com/dqsjqian/Aria.git
cd Aria
cmake -B build/flavors/release -DCMAKE_BUILD_TYPE=Release
cmake --build build/flavors/release -j
ctest --test-dir build/flavors/release --output-on-failure

build/ is a container for build trees — never configure straight into it. The unified build layout is documented at the top of scripts/build.sh; the per-flavor script scripts/build.sh [release|debug|asan|tsan] picks the right directory for you.

Normal builds use the bundled doctest header. CMake fetches the fallback test dependency only if that vendored header is absent.

One-liner build scripts

# macOS / Linux
scripts/build.sh # release
scripts/build.sh tests # release + ctest
scripts/build.sh asan # debug + AddressSanitizer + UBSan
scripts/build.sh tsan # debug + ThreadSanitizer
scripts/build.sh clean
# Windows — MSYS2 UCRT64 (GCC + Ninja)
scripts\build.ps1 # release
scripts\build.ps1 tests
scripts\build.ps1 asan
scripts\build.ps1 tsan # debug + ThreadSanitizer (not available on MSVC, see below)
# Windows — MSVC / Visual Studio 2022
scripts\build-msvc.ps1 # release (build/flavors/msvc/ tree)
scripts\build-msvc.ps1 tests
scripts\build-msvc.ps1 debug
scripts\build-msvc.ps1 asan # /fsanitize=address (no UBSan on MSVC)

Windows toolchains

Aria ships with two parallel build scripts for Windows. They live side-by-side in scripts/, write to separate build directories, and neither one needs to know about the other.

Toolchain Script Build dir Notes
MSYS2 UCRT64 (GCC 14+ / Clang 18+) scripts\build.ps1 build/ Lightweight (~300 MB). Pre-installed on most CI images. Auto-detected from C:\msys64\ucrt64\bin and a few other common paths.
MSVC v143 (VS 2022) scripts\build-msvc.ps1 build/flavors/msvc/ Auto-detects the VS install via vswhere, scrubs MSYS2 env vars (INCLUDE / LIB / CPATH / ...) before running CMake, and uses the Visual Studio 17 2022 generator.

You can switch back and forth without clean — the two trees are isolated. CI runs both nightly to make sure neither regresses.

MSVC one-time setup

# 1. Install Visual Studio 2022 Build Tools (or the full IDE) with
# workload "Desktop development with C++" + "C++ CMake tools".
# 2. (Optional) install Qt 6 with the msvc2022_64 kit if you need the
# Qt6 adapter.
# 3. From any PowerShell window:
scripts\build-msvc.ps1 tests

MSYS2 one-time setup

# 1. Install MSYS2 from https://www.msys2.org
# 2. Open the "MSYS2 UCRT64" shell:
pacman -Syu
pacman -S --needed mingw-w64-ucrt-x86_64-toolchain `
mingw-w64-ucrt-x86_64-cmake `
mingw-w64-ucrt-x86_64-ninja git
# 3. (Optional) Add C:\msys64\ucrt64\bin to your PATH.
# 4. From any shell:
scripts\build.ps1 tests

Rationale for shipping both: Aria uses C++ coroutines extensively that libstdc++, libc++, and the MSVC STL all handle cleanly. Pinning a single Windows toolchain artificially excluded a large chunk of users in the .NET / Visual Studio ecosystem — we now validate against MSVC v143 on the same release gate as macOS, Ubuntu, and MSYS2.

Use it from your own project

Option A — find_package after install (recommended for production):

# In the aria tree:
cmake -S . -B build/flavors/release -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build/flavors/release -j && sudo cmake --install build/flavors/release
# In your project's CMakeLists.txt:
find_package(aria 2.0 CONFIG REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE aria::aria)
# or pick individual modules: aria::core / ::async / ::runtime / ::binding

Installed Linux shared libraries resolve other Aria libraries from their own directory. Keep these libraries together; after moving the SDK, configure consumers against its new installation path.

Option B — vendored (no install):

add_subdirectory(third_party/aria EXCLUDE_FROM_ALL)
target_link_libraries(my_app PRIVATE aria::core aria::async)

Flagship example

AriaTools is the single flagship cross-platform example, driving Qt, iOS, Android, and Web from one C++ ViewModel, with all four shells gated in CI. It is also the reference for both Android integration shapes: the Compose side-channel and the typed JniAdapter. The Aria repository no longer carries application examples. Framework behavior is pinned by tests/acceptance/ and module tests, while these docs keep only focused, minimal snippets.

Build options

Option Default Description
ARIA_BUILD_TESTS ON Build unit tests + ctest registration.
ARIA_BUILD_BENCHMARK ON Build the micro-benchmark suite.
ARIA_BUILD_SHARED ON Runtime/binding as .dylib/.so/.dll instead of .a.
ARIA_BUILD_QT6 OFF Build the Qt6 adapter (requires Qt6Widgets).
ARIA_BUILD_APPKIT OFF (production-grade) Build the macOS AppKit adapter as a first-class STATIC CMake module using Objective-C++; ships aria::adapters::appkit and passes the shared adapter_conformance battery. Requires APPLE.
ARIA_BUILD_UIKIT OFF (production-grade) Build the iOS UIKit adapter as a first-class STATIC CMake module using Objective-C++; ships aria::adapters::uikit and passes the shared conformance battery. Requires APPLE.
ARIA_BUILD_JNI OFF Build Android JNI adapter as a first-class CMake module — built as STATIC, ships aria::adapters::jni, implementing the same IViewAdapter contract as Qt/AppKit/UIKit via reflective JNI dispatch (text / bool / int / double / visibility / click). Requires an Android NDK toolchain (NDK r26+ — the C++20-concepts core does not build under NDK r25's libc++).
ARIA_ENABLE_ASAN OFF AddressSanitizer.
ARIA_ENABLE_UBSAN OFF UndefinedBehaviorSanitizer.
ARIA_ENABLE_TSAN OFF ThreadSanitizer.

👋 Hello, world

The section above needs a UI adapter. To see the reactive core on its own, you need no UI at all:

#include "aria/aria.hpp"
using namespace aria;
Property<int> count{0};
// No explicit dependency list — the first evaluation reads count, so
// count is recorded as a dependency automatically.
return "count = " + std::to_string(count.get());
});
Command<> increment([&]{ count = count.get() + 1; });
// bind opens a subscription: it fires once immediately with the current
// value, then again on every change. The returned Subscription is the
// handle that OWNS that subscription's lifetime — so you must keep it.
// Write `label.bind(...);` and discard the result and the temporary dies
// on that very line, taking the subscription with it: nothing would ever
// print. (bind is [[nodiscard]], so the compiler warns you.)
auto sub = label.bind([](const std::string& s) { std::cout << s << '\n'; });
// ↑ this line has already printed "count = 0" (the initial sync)
increment(); // → "count = 1"
increment(); // → "count = 2"
// sub unsubscribes on destruction — no manual deregistration. You can
// also disconnect early:
sub.release();
increment(); // prints nothing
Definition command.hpp:154
Definition computed.hpp:86
Definition signal.hpp:12

So sub exists to express the subscription's lifetime as a scope: while the variable lives the subscription lives, and when it goes the subscription is torn down. In a real UI this Subscription is usually a member of the View, so destroying the View detaches the binding and no callback ever reaches a destroyed widget.

⚡ Async (C++ coroutines)

using namespace aria::async;
Task<std::string> fetch_user(int id) {
co_await schedule_on(network_pool); // jump to worker thread
auto raw = http::get("/users/" + std::to_string(id));
co_await schedule_on(main_dispatcher); // jump back to UI thread
co_return parse(raw);
}
Definition task.hpp:78
Definition async_command.hpp:118
auto schedule_on(IExecutor &exec)
Schedule a coroutine to resume on the given executor.
Definition executor.hpp:396

🌍 Cross-platform mapping

Platform UI host Adapter
Windows Qt6 aria-qt6 ✅ ready (MSYS2 UCRT64 + MSVC 2022)
macOS AppKit / Qt6 aria-qt6 ✅ ready; AppKit ✅ ready
Linux Qt6 aria-qt6 ✅ ready
iOS UIKit aria-uikit ✅ ready
Android Compose / View aria-jni ✅ ready (NDK r26+)
Web (server-driven) HTML/JS in browser aria-http ✅ ready (REST + SSE)
Web (in-browser C++) DOM via WASM Not implemented; conditional roadmap work

The HTTP adapter ships a small server (HttpAdapter) that exposes any ViewModel over a JSON REST + Server-Sent-Events protocol, plus a vanilla-JS browser SDK (aria_client.js). The server is built on the vendored single-header cpp-httplib (HTTP/1.1 + SSE) and nlohmann::json (encode/decode) — both committed under third_party/, so the adapter adds no new external build dependency; aria itself owns the wire protocol, view registry, subscription dispatch and SSE fan-out. It is the right shape for desktop apps that want a web UI on the side, headless services, and local debug dashboards. The WASM adapter — which compiles C++ business logic into the browser sandbox — solves a different, more constrained problem and remains conditional on a concrete consumer. See RFC 0001 for the design.

The current release ships the platform-agnostic core, runtime, async, and binding layers — fully unit-tested. Qt6, AppKit, UIKit, JNI, and HTTP are first-class opt-in adapters in the CMake tree (subject to their platform requirements). WASM and SwiftUI remain conditional roadmap work.

🖼 Real-world showcase

The big picture first — three real applications grew out of one framework:

Aria ecosystem: the framework plus three real apps

Below is what Aria looks like in real applications — one C++ ViewModel, native shells per platform. AriaTools (17-module cross-platform workbench on Qt / iOS / Android / Web), AriaAgent (provider-agnostic LLM Agent GUI), and OpenRead (cross-platform book-source engine, HTTP/SSE web shell) all run Aria 1.x in production shape. Every screenshot comes from a stable release: one build, one shared C++ business core across platforms.

AriaTools — cross-platform workbench (17 modules)

Aria's flagship example: one ViewModel, four platforms. The cart / theme switching / Framework Lab / Echo modules in the side navigation are all driven by ObservableList, Computed, and reactive::batch.

Platform Screenshot Adapter
macOS (Qt6) AriaTools-Mac aria-qt6
iOS / UIKit AriaTools-iOS aria-uikit
Android (Compose side-channel) AriaTools-Android aria-jni
Web (HTTP/REST/SSE) AriaTools-Web aria-http

AriaAgent — LLM Agent GUI

A provider-agnostic Agent GUI built on Aria + Qt6: true token-level streaming SSE, tool-call chain visualization, permission approval (fail-closed), Markdown rendering.

View Screenshot
Main chat AriaAgent-Main
Settings (General / Model / Plugins / Agent Presets) AriaAgent-Setting

OpenRead — cross-platform book-source engine

A book-source manager powered by the Aria HTTP adapter: source list on the left, book cards on the right — search, subscribe, and debug in one place. The same C++ core drives two web shapes: a REST+SSE thin client and an SSR variant.

View Screenshot
Source manager (Web, REST + SSE) OpenRead-Web
Source manager (Web, SSR) OpenRead-SSR

These screenshots show the macOS example applications. Other platforms reuse the ViewModel; native appearance depends on the platform, Qt style, and host application. Consult CI for framework build and test results on Windows/Linux.

🧪 Test status

ctest --test-dir build/flavors/release --no-tests=error --output-on-failure

Tests exercise reactive state, collection events, async cancellation, binding lifetimes, ABI, and adapter contracts. Enabled suites depend on platform and build options. See CI results, lifecycle contracts, and the error model.

📊 Benchmarks

Measured on 2026-09-13: Apple M3 Pro / Apple Clang 21 / C++20 Release (-O3 -DNDEBUG). Each entry is the median of five paired runs' mean operation times, comparing original revision eeb613f with 2.0 snapshot c33850d.

Operation Original Current
Property set, no observers 20.5 ns 13.2 ns
Property set, one observer 98.9 ns 35.0 ns
Computed chain ×5 570.8 ns 229.0 ns
Ten sets in one batch 250.6 ns 102.5 ns
FilteredList tail append, 10k initial rows 11.18 μs 0.23 μs
SortedList random-key append, 10k initial rows 8.38 μs 17.28 μs

Performance is mixed: owning event data and maintaining correct ordering after batched changes also have costs. See the performance reference for all scenarios, complexity, remaining regressions, and reproduction details.

📋 Framework contracts

Every non-trivial behaviour Aria promises is pinned in a numbered contract document. Each contract item carries an ID (e.g. L-13, E-22, LD-7, D-4, S-31) so a failing assertion or PR review comment can point straight at the canonical description.

Document Prefix Scope
docs/reference/api-style.md S-N Naming, namespace, error and async-entry style
docs/reference/lifecycle.md L-N Threading, subscription, reactive flush, view-destroy, async cancel/dtor invariants
docs/reference/error-model.md E-N aria::Error / ErrorKind taxonomy and per-subsystem error contracts
docs/reference/list-diff-contract.md LD-N Insert / Remove / Replace / Move / Reset / ItemChanged semantics
docs/reference/diagnostics.md D-N aria::TraceEvent + aria::TraceSink protocol
docs/reference/performance.md PERF-N Complexity bounds and per-operation baselines for every public API

The P0 hard-bedrock pass (see CHANGELOG → Latest framework-grade hardening) closed every open contract above; the seven framework-level fuzzers in modules/core/fuzz/ stress-verify the lifecycle invariants (default 50k iterations / fuzzer; nightly runs set ARIA_FUZZ_ITERS=1000000).

🗺 Capabilities

Capability Type Where
Reactive state Property<T> / Computed<T> / Effect aria/reactive/reactive.hpp
Commands Command<Args...> (reactive can_execute) aria/command.hpp
Collections ObservableList<T> + derived Filtered/Sorted/Mapped/Distinct/Grouped/Paged aria/observable_list.hpp, aria/derived/*
Selection Selection<T> / MultiSelection<T> (SE-1..SE-5) aria/selection.hpp
Validation Validator<T> / FormValidator / ValidationState + async rules aria/validator.hpp, aria/binding/form.hpp, aria/async/async_validator.hpp
Async Task<T> / AsyncCommand / with_timeout / when_any / when_all / CancellationToken aria/async/*
Data fetching AsyncResource<T> (SWR + dedupe) / Loadable<T> (5-state) aria/async/async_resource.hpp, aria/loadable.hpp
Navigation Navigator (push/pop/push_for_result<R>, route patterns) aria/binding/navigation.hpp
Binding BindingEngine / IViewAdapter / IView / Converter / bind_view_lifetime aria/binding/*
Diagnostics TraceEvent / TraceSink / GraphInspector (atomic check when disabled) aria/diagnostics.hpp

Learn it: the documentation index links the guides, the Cookbook (task-oriented recipes), and the contract references. The public API reference is generated from main. See the 2.0 migration guide when upgrading from 1.2.x. Build the reference locally with cmake -B build/flavors/docs -DARIA_BUILD_DOCS=ON && cmake --build build/flavors/docs --target aria_docs.

🗺 Roadmap

Aria is open source (MIT License), hosted on GitHub. The single source of truth for what is not yet done (and what has been deliberately deferred) lives in docs/ROADMAP.md. For the current capability snapshot, see CHANGELOG.md.

🤝 Contributing

Contributions are welcome! Please open an issue first to discuss design changes.

  • Code style is enforced by .clang-format and .clang-tidy.
  • All changes must pass ctest --output-on-failure.
  • New features require tests in the matching modules/*/tests/ suite.

🙏 Acknowledgments

📄 License

MIT © 2026 aria contributors


📖 Other languages