SkillAgentSearch skills...

Ilias

一个类似tokio的C++20的迷你异步库 Lightweight asynchronous io library for modern C++, with minimal dependency, support tcp, udp, file, console, pipe

Install / Use

/learn @BusyStudent/Ilias
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Ilias

A lightweight asynchronous I/O library based on C++20 stackless coroutines, completion-based, and inspired by Tokio's design.

<!-- Project Info Badges -->

License C++ Standard Build System Platform

English | 中文

Features

  • Zero-dependency core library
  • Cancellation support
  • Structured concurrency support (using TaskScope and TaskGroup)
  • Full networking support (TCP / UDP / async DNS resolution)
  • File I/O
  • TLS support (Windows: Schannel / Others: OpenSSL)
  • Cross-platform (Windows / Linux)
  • Single-threaded executor, easy to integrate with frameworks like Qt and convenient for development

Table of Contents

📊 CI Status

| CI Name | Status | | --------- | ------- | | Windows | CI for windows by xmake | | Linux | CI for linux by xmake | | Coverage | codecov|

Quick Start

Adding to Your Project

For xmake projects

add_repositories("btk-repo https://github.com/Btk-Project/xmake-repo.git")
add_requires("ilias")

target("your_app")
    add_packages("ilias")

For CMake projects

include(FetchContent)

FetchContent_Declare(
    ilias
    GIT_REPOSITORY https://github.com/BusyStudent/Ilias.git
    GIT_TAG main
)

FetchContent_MakeAvailable(ilias)

add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE ilias::ilias)

Basic Environment

#include <ilias/platform.hpp>
#include <ilias/task.hpp>

auto main() -> int {
    ilias::PlatformContext ctxt; // Create an I/O context for submitting tasks
    ctxt.install(); // Register it to the current thread
    
    // Currently available I/O contexts: IocpContext, EpollContext, UringContext, QIoContext
    // A simple executor without I/O is: EventLoop
    // PlatformContext is a typedef, automatically selected based on the compilation platform
    
    auto task = []() -> ilias::Task<int> { // Coroutine function, return value must be Task<T>
        co_return 1;
    };
    
    auto result = task().wait(); // Create the task and block until completion
    // Task<T> represents a return value of T
    assert(result == 1);
    return 0;
}

Simplified with the ilias_main macro

If you want to simplify the code, you can use the ilias_main macro, which is equivalent to the code above.

#include <ilias/platform.hpp>
#include <ilias/task.hpp>

void ilias_main() {
    co_return;
}

// Or return an int
int ilias_main() {
    co_return 0;
}

// Supports two parameter formats 
// - ilias_main()
// - ilias_main(int argc, char** argv)
// Return value supports void and int
// The `auto ->` syntax is currently not supported due to implementation limitations

Network Programming

Simple Message Sending

#include <ilias/platform.hpp>
#include <ilias/task.hpp>
#include <ilias/net.hpp>

using ilias::TcpStream;

void ilias_main() {
    auto client = (co_await TcpStream::connect("127.0.0.1:8080")).value();
    
    // ilias::makeBuffer converts any type convertible to std::span<T>
    // into std::span<const std::byte> (Buffer) or std::span<std::byte> (MutableBuffer)
    // The parameters for read and write are MutableBuffer and Buffer respectively
    // read and write return an IoTask<size_t>
    // IoTask<T> is an alias for Task<Result<T, std::error_code>>, indicating that an error might occur (see the Error Handling section for details)
    
    std::string_view sv = "HELLO WORLD";
    if (auto res = co_await client.write(ilias::makeBuffer(sv)); !res) {
        co_return;
    }
}

Accepting Connections

#include <ilias/platform.hpp>
#include <ilias/task.hpp>
#include <ilias/net.hpp>

using ilias::TcpListener;
using ilias::TcpStream;
using ilias::IPEndpoint;

// Coroutine to handle a client connection
auto handleClient(TcpStream stream) -> ilias::Task<void> {
    std::array<std::byte, 1024> buffer;
    
    // Read data and echo it back
    while (true) {
        auto n = co_await stream.read(buffer);
        if (!n || n == 0) {
            break;
        }
        co_await stream.write(ilias::makeBuffer(buffer.data(), *n));
    }
}

void ilias_main() {
    auto listener = (co_await TcpListener::bind("127.0.0.1:8080")).value();
    
    while (true) {
        auto [stream, endpoint] = (co_await listener.accept()).value();
        // Spawn a new coroutine for each client
        auto handle = ilias::spawn(handleClient(std::move(stream)));
        // The handle can be used to check for completion or to wait for it
        // Discarding the handle is equivalent to detaching
    }
}

Spawning Coroutines

#include <ilias/platform.hpp>
#include <ilias/task.hpp>

void ilias_main() {
    // Spawn a coroutine
    auto handle = ilias::spawn(task());
    
    // Spawn a blocking task, which will be submitted to a thread pool
    auto handle2 = ilias::spawnBlocking(callable);
    
    // The handle can be used to check for completion or to wait for it
    co_await std::move(handle);

    // For finer control over the coroutine's lifecycle, use TaskScope or TaskGroup<T>
}

Error Handling

Both error codes and exceptions are supported. The core type is Result<T, E>, an alias for std::expected<T, E>. Depending on the C++ version, it will use either the standard library implementation (C++23) or a third-party one (zeus_expected).

  • Exceptions propagate up the call stack and are thrown at the await point.
  • Result<T, E> is equivalent to std::expected<T, E>.
  • Err<T> is equivalent to std::unexpected<T>.
  • IoResult<T> is equivalent to Result<T, std::error_code>.

Two Ways to Handle Errors

auto example() -> ilias::Task<void> {
    // Method 1: Use value() (throws an exception on error, catch it at the top level with try-catch)
    auto stream = (co_await TcpStream::connect("example.com:80")).value();
    
    // Method 2: Explicitly check for errors
    auto result = co_await TcpStream::connect("example.com:80");
    if (!result) {
        std::println("Connection failed: {}", result.error().message());
        co_return;
    }
    // Use *result
}

Qt Integration

#include <ilias/platform/qt.hpp>
#include <QApplication>

auto main(int argc, char **argv) -> int {
    QApplication app(argc, argv);
    ilias::QIoContext ctxt; // An I/O context integrated with Qt
    ctxt.install();
    
    // Subsequent code is the same as on other platforms; coroutines can be used normally
    
    return app.exec();
}

Cancellation

Cancellation is supported. A cancellation request will stop the execution of the current coroutine at an await point, similar to throwing an uncatchable exception.

#include <ilias/platform.hpp>
#include <ilias/task.hpp>

using namespace std::literals;

void ilias_main() {
    auto task = []() -> ilias::Task<int> {
        co_return 1;
    };
    auto handle = ilias::spawn(task());
    handle.stop(); // Send a cancellation signal

    // The result of `co_await` on a `WaitHandle<T>` is `Option<T>` (an alias for `std::optional`, with `void` automatically replaced by `std::monostate`)
    // If it's `nullopt`, the task was cancelled
    auto res = co_await std::move(handle);
    assert(res == 1); // Since this task has no await points, the cancellation will not succeed

    // A task with an await point
    auto task2 = []() -> ilias::Task<int> {
        co_await ilias::sleep(1000ms);
        co_return 1;
    };
    auto handle2 = ilias::spawn(task2());
    handle2.stop();
    auto res2 = co_await std::move(handle2);
    assert(res2 == std::nullopt); // Since sleep i

Related Skills

View on GitHub
GitHub Stars5
CategoryCustomer
Updated2d ago
Forks1

Languages

C++

Security Score

90/100

Audited on Mar 28, 2026

No findings