Skip to content

add net module: tcp sockets via libuv (prereq for pure-ts postgres driver)#585

Merged
cs01 merged 4 commits intomainfrom
feat/net-module-tcp
Apr 20, 2026
Merged

add net module: tcp sockets via libuv (prereq for pure-ts postgres driver)#585
cs01 merged 4 commits intomainfrom
feat/net-module-tcp

Conversation

@cs01
Copy link
Copy Markdown
Owner

@cs01 cs01 commented Apr 20, 2026

Summary

Adds a net module exposing raw TCP sockets via libuv. Prerequisite for a pure-TypeScript Postgres driver (and any future protocol implementation — Redis, MongoDB, etc).

Built by an agent in worktree isolation off origin/main. Smoke test passes on macOS arm64.

What's in it

  • c_bridges/net-bridge.c (401 LOC) — libuv-backed TCP bridge: cs_net_connect, cs_socket_write/end/destroy, cs_socket_poll/wait, event kind/data/len/consume accessors. GC-aware, no trampolines.
  • lib/net.ts (225 LOC) — Socket class with on('connect' | 'data' | 'error' | 'close', cb), write(buf: Buffer), end(), destroy(), removeDataListener(cb). Exposes createConnection(host, port).
  • Build + CI wiring:
    • scripts/build-vendor.sh — builds net-bridge.o after child-process-spawn
    • src/compiler.ts + src/native-compiler-lib.tsusesNet detection (scans declaredExternFunctions for cs_net_* prefix, mirrors usesPostgres), conditional linking of net-bridge.o + -luv
    • .github/workflows/ci.ymlnet-bridge.o added to release tarball packaging + verify-lib-contents list
  • tests/fixtures/net/tcp-echo.ts — smoke test: createConnectioncs_net_connect → libuv connect → isOpen() / destroy() round-trip. Follows the // @test-passed fixture pattern.

Chad-subset friction points discovered

All documented in the "Known limits" block at the top of lib/net.ts. Four of these are real codegen bugs worth filing as separate issues:

  1. Function arrays unsupportedArray<(x: string) => void> emits "function-pointer arrays not yet supported". Forced a single-listener-per-event shape instead of the usual array-of-listeners pattern.
  2. Arrow-literal in class ctor body: codegen emits store i8* __lambda_N missing the @ sigil; clang rejects the IR. Worked around with a module-level _netNoopCb reference.
  3. Closures capture by value — outer-scope let flags mutated inside listeners aren't visible outside. Test had to signal via stdout sentinels instead of a captured flag.
  4. arr[i](args) call pattern — parser rejects as "Unsupported call expression: ElementAccessExpression".
  5. let x: Type; then later-assign — method resolution on x breaks ("Method 'on' on 'x' is not supported"). Worked around by inlining the createConnection call.
  6. NULL char* across the FFI boundary doesn't reliably compare === "". Dropped the throw-on-fail; callers use isOpen() instead.

Test plan

  • bash scripts/build-vendor.sh builds c_bridges/net-bridge.o
  • npm run build typechecks lib/net.ts
  • tests/fixtures/net/tcp-echo.ts compiles + runs + emits TEST_PASSED
  • CI green on Linux (build-linux-glibc) and macOS (build-macos)
  • verify-cross-compiled-binary finds net-bridge.o in the release tarball

Follow-ups (separate PRs)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

Benchmark Results (Linux x86-64)

Benchmark C ChadScript Go Node Place
Binary Trees 1.410s 1.176s 2.624s 1.197s 🥇
Cold Start 1.0ms 0.9ms 1.2ms 28.0ms 🥇
Fibonacci 0.910s 0.792s 1.729s 3.368s 🥇
Hash Map Lookup 0.099s 0.074s 0.094s 0.122s 🥇
Monte Carlo Pi 0.440s 0.439s 0.457s 2.592s 🥇
JSON Parse/Stringify 0.036s 0.050s 0.157s 0.128s 🥈
N-Body Simulation 1.750s 2.253s 2.288s 2.334s 🥈
Regex Match 0.015s 0.005s 0.022s 0.004s 🥈
SQLite 0.041s 0.345s 0.441s 0.409s 🥈
File I/O 0.087s 0.094s 0.087s 0.165s 🥉
Quicksort 0.246s 0.284s 0.242s 0.300s 🥉
Sieve of Eratosthenes 0.014s 0.027s 0.020s 0.041s 🥉
String Manipulation 0.008s 0.020s 0.016s 0.038s 🥉
Matrix Multiply 0.499s 1.157s 0.783s 0.427s #4

CLI Tool Benchmarks

Benchmark ChadScript grep node xxd Place
Hex Dump 0.595s 0.964s 0.141s 🥈
Recursive Grep 0.021s 0.011s 0.106s 🥈

@cs01
Copy link
Copy Markdown
Owner Author

cs01 commented Apr 20, 2026

CI is blocked on a main-branch regression, not on this PR's code.

Bisected: #597 — the checkMissingReturns pass false-positives on transformExpression when chad-native.ts has 8+ registerStdlib calls. This PR adds the 8th (net.ts), tripping the regression for the first time. Introduced in #583.

Repro is deterministic: reduce registerStdlib calls in chad-native.ts to 7 → compile succeeds. Any 8th (regardless of content/order/key) → fails with transformExpression does not return.

Options:

I lean option 1. Pausing on pushing more commits to this branch.

cs01 added 4 commits April 20, 2026 15:01
…/end/destroy, on connect/data/error/close events). prereq for pure-ts postgres driver. smoke test passes (connect-refused path).
… was failing because chad build couldn't resolve the chadscript/net import since registerStdlib call was missing. one-line fix in src/chad-native.ts.
… socket class + createConnection so user code + ide gets typechecked (was missing from the initial net-module commit, paired with the registerStdlib fix).
…-guards aren't defeated by ffi null-to-empty-string conversion. poll/wait/isopen now see a real handle with connect_failed=closed=1 and behave as dead-socket instead of dereferencing the empty-string constant
@cs01 cs01 force-pushed the feat/net-module-tcp branch from f141a5b to 9f8521f Compare April 20, 2026 22:19
@cs01 cs01 merged commit f6bc2f5 into main Apr 20, 2026
13 checks passed
@cs01 cs01 deleted the feat/net-module-tcp branch April 24, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant