Search by

codinglombok / lombokasync

codinglombok

Cooperative async on PHP Fibers: event loop with timers, tasks, timeout, bounded and unbounded mpsc channels, oneshot channels, joinAll and select with a cross-language contract. Zero dependencies.

Package info

github.com/codinglombok/LombokAsync

Language:Rust

pkg:composer/codinglombok/lombokasync

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.2.0 2026-10-26 05:28 UTC

This package is auto-updated.

Last update: 2026-10-26 06:57:01 UTC


README

Small async toolkit with one behaviour in five languages: bounded and unbounded mpsc channels, oneshot channels, join_all, select, and timeout, plus a single-threaded Rust executor. Zero runtime dependencies.

License CI Vectors Lombok Ecosystem

Part of the Lombok Ecosystem.

Mengapa library ini? (Why this library?)

  • Same rules everywhere. Rust, TypeScript, Python, Go, and PHP follow one written contract (SPEC): when a send is full or closed, when a receive is empty, which task wins a select tie (the lowest index), which error join_all reports (the lowest index, not the earliest). All five ports run the same 141 vector cases in CI.
  • Explicit channel states. Non-blocking try_send / try_recv with named outcomes, bounded capacity for backpressure, sender cloning, and receiver close() that still drains queued values.
  • A real small executor in Rust. Ready queue, timer heap, thread parking instead of busy-polling, wakers usable from other threads, and #![forbid(unsafe_code)].
  • Idiomatic per language. Rust Result, TypeScript status objects and AsyncError, Python exceptions on asyncio, Go sentinel errors with context variants, PHP Fibers with a timer-driven event loop.

Installation

Language Package Status
Rust lombokasync (crates.io) not yet published
TypeScript / JavaScript lombokasync (npm) not yet published; dual ESM + CJS build
Python lombokasync (PyPI) not yet published
Go github.com/codinglombok/lombokasync/go tag go/v0.2.0 on release
PHP codinglombok/lombokasync (Packagist) not yet published; root composer.json — release.yml pings Packagist on v* tags (one-time submit)

On a v* tag, release.yml also creates a GitHub Release containing every port's package artifact (npm tarball, Python sdist + wheel, Rust .crate, PHP composer dist zip) and pings Packagist.

Until then, use the source in this repository. See docs/How To Dist_LombokAsync_0.2.0.md.

Quick start

Rust

use lombokasync::{block_on, mpsc, spawn, timeout};
use std::time::Duration;

let total = block_on(async {
    let (tx, mut rx) = mpsc::bounded::<u32>(8).unwrap();
    for i in 0..3 {
        let tx = tx.clone();
        spawn(async move { tx.send(i).await.unwrap() });
    }
    drop(tx);
    let mut sum = 0;
    while let Some(v) = rx.recv().await {
        sum += v;
    }
    sum
});
assert_eq!(total, 3);
assert_eq!(block_on(timeout(Duration::from_millis(50), async { 1 })), Ok(1));

TypeScript

import { mpscChannel, select, timeout, AsyncError } from 'lombokasync';

const [tx, rx] = mpscChannel<number>(2);
tx.trySend(1);       // 'ok'
tx.trySend(2);       // 'ok'
tx.trySend(3);       // 'full'
rx.tryRecv();        // { status: 'value', value: 1 }

const { index, value } = await select([fetchA(), fetchB()]);
try {
    await timeout(500, fetchSlow());
} catch (e) {
    if (e instanceof AsyncError && e.code === 'TIMEOUT') { /* ... */ }
}

Python

import lombokasync as la

async def main():
    tx, rx = la.mpsc_channel(capacity=8)
    la.spawn(producer(tx))
    async for item in rx:
        print(item)
    results = await la.join_all([fetch(1), fetch(2)])
    index, value = await la.select([fast(), slow()])

la.run(main())

Go

import lombokasync "github.com/codinglombok/lombokasync/go"

tx, rx, _ := lombokasync.NewBoundedMpsc[int](8)
go func() { defer tx.Close(); for i := 0; i < 3; i++ { tx.Send(i) } }()
for v, ok := rx.Recv(); ok; v, ok = rx.Recv() {
    fmt.Println(v)
}
v, err := lombokasync.Timeout(time.Second, func() int { return 42 })

PHP

use LombokAsync\Async;
use LombokAsync\Channel\MpscChannel;

$sum = Async::run(function (): int {
    [$tx, $rx] = MpscChannel::bounded(8);
    Async::spawn(function () use ($tx) {
        foreach ([1, 2, 3] as $v) { $tx->send($v); }
        $tx->close();
    });
    $sum = 0;
    foreach ($rx as $v) { $sum += $v; }
    return $sum;
});

Ports

Feature Rust TypeScript Python Go PHP
mpsc (bounded/unbounded, clone, close) YES YES YES YES YES
oneshot YES YES YES YES YES
join_all / select / timeout YES YES YES YES YES
own executor YES (block_on) JS event loop asyncio goroutines YES (Fibers)
shared vectors 141/141 141/141 141/141 141/141 141/141

Known limitations

No I/O reactor (sockets, files), no broadcast or watch channels, no thread pool; the Rust executor is single-threaded. Go Timeout cannot stop the goroutine it started (use TimeoutCtx). PHP publishing to Packagist reads this monorepo directly (root composer.json, composer dist trimmed by .gitattributes export-ignore) and is automated in release.yml; it needs a one-time submission on Packagist plus the PACKAGIST_USERNAME / PACKAGIST_TOKEN secrets. Full list: docs/Full Summary Project_LombokAsync_0.2.0.md.

Upgrading from 0.1.0

0.2.0 changes every port: channel outcomes are explicit, timeout reports a TIMEOUT error instead of None/undefined, select takes a list and returns the winning index, and the Go module path is now lowercase. See CHANGELOG.md.

Development

cd rust && cargo test && cargo clippy --all-targets -- -D warnings
cd typescript && npm ci && npm run lint && npm run coverage && npm run build && npm run build:cjs && npm run smoke
cd python && python -m pytest && ruff check . && mypy
cd go && go test -race ./...
cd php && php tests/run.php && phpstan analyse --no-progress --memory-limit=1G && composer validate --strict
bash scripts/lombok-doctor.sh LombokAsync

Coverage gates follow the ecosystem standard: 95% lines/statements and 90% branches in every port (Rust line-based via cargo-llvm-cov, TS 95/90/90, Python branch mode, Go statements, PHP pcov).

License

Apache-2.0. See LICENSE.