Skip to content

A high-performance, zero-dependency Golang-style channel implementation for TypeScript. Supports buffered/unbuffered channels, select statement with fairness, and AbortSignal integration.

License

Notifications You must be signed in to change notification settings

own-js-org/chan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@own-js/chan

License: MIT Bun TypeScript

A high-performance, zero-dependency Golang-style channel implementation for TypeScript. Bring the power of Communicating Sequential Processes (CSP) to Bun, Deno, and Node.js.

✨ Features

  • 🚀 Zero Dependencies: Pure TypeScript implementation.
  • 🐹 Go-like Semantics: Supports buffered and unbuffered channels.
  • 🔀 Powerful select: Fair scheduling across multiple read/write cases.
  • ⏱️ Signal Integration: Built-in support for AbortSignal.
  • 📦 Modern Tooling: ESM/CJS support, fully typed with tsup.
  • Optimized: Fast-path execution for ready channels to minimize Promise overhead.

📦 Installation

# Using bun (recommended)
bun add @own-js/chan

# Using npm
npm install @own-js/chan

# Using deno
deno add npm:@own-js/chan

🚀 Quick Start

Basic Usage

import { Chan } from "@own-js/chan";

const ch = new Chan<number>(1); // Buffered channel with capacity 1

// Write to channel
await ch.write(42);

// Read from channel
const { value, ok } = await ch.read();
console.log(value); // 42

Select Multiplexing

The selectChan function mimics Go's select statement, allowing you to wait on multiple channel operations.

import { Chan, selectChan } from "@own-js/chan";

const ch1 = new Chan<string>();
const ch2 = new Chan<string>();

const writeCase = ch2.writeCase("payload");
const readCase = ch1.readCase();
for (let i = 0; i < 3; i++) {
    switch (i) {
        case 1:
            ch1.write("hello");
            break;
        case 2:
            ch2.read();
            break;
    }
    const selected = await selectChan({
        chans: [
            ch1.readCase(),
            writeCase,
        ],
        signal: i == 0 ? AbortSignal.timeout(100) : null,
        silent: true,
    });
    switch (selected) {
        case readCase:
            console.log(i, "Read from ch1:", readCase.read()!.value);
            break;
        case writeCase:
            console.log(i, "Successfully wrote to ch2:", writeCase.write()!.ok);
            break;
        default:
            console.log(i, `${selected.reason}`);
            break;
    }
}

Iteration

Channels implement the AsyncIterable interface.

const ch = new Chan<number>(3);
ch.tryWrite(1);
ch.tryWrite(2);
ch.close();

for await (const val of ch) {
    console.log(val); // 1, 2
}

🛠 API Reference

Chan<T>

  • new Chan(buf?: number): Creates a channel. buf > 0 enables buffering.
  • read(opts?): Asynchronous read.
  • tryRead(): Synchronous read. Returns { ok: false } if no data.
  • write(val, opts?): Asynchronous write.
  • tryWrite(val): Synchronous write. Returns { ok: false } if full.
  • close(): Closes the channel. Subsequent reads return closed: true.
  • isClosed: Returns true if channel is closed.

selectChan(options)

  • chans: Array of ReadCase or WriteCase.
  • default: If true, returns null immediately if no case is ready.
  • signal: AbortSignal to cancel the select operation.
  • silent: If true, returns abortion reason instead of throwing.

🧪 Testing

This library is tested using Bun.

bun test

📄 License

MIT © powerpuffpenguin

About

A high-performance, zero-dependency Golang-style channel implementation for TypeScript. Supports buffered/unbuffered channels, select statement with fairness, and AbortSignal integration.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published