Skip to content
Closed

rust io #7055

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
234 commits
Select commit Hold shift + click to select a range
24184aa
Add Rust I/O dependency features
mikea Aug 18, 2026
213580d
Document kj::Maybe unsafe invariants
mikea Aug 18, 2026
e9cfec0
Tighten KjOwn thread-safety guarantees
mikea Aug 18, 2026
f0201b3
Tighten KjArc thread-safety bounds
mikea Aug 18, 2026
d88afc9
Document promise bridge safety invariants
mikea Aug 18, 2026
21ec538
Keep guarded executors alive through teardown
mikea Aug 18, 2026
747be9d
Add tokio runtime accessors
mikea Aug 18, 2026
45e7007
Add readiness polling helper
mikea Aug 18, 2026
31f46d2
Add KJ stream unwrap interface
mikea Aug 18, 2026
ed44089
Declare tokio file watcher bridge
mikea Aug 18, 2026
a626e4f
Declare peer filtering interfaces
mikea Aug 18, 2026
ffc60b5
Add tokio event port setup entry point
mikea Aug 18, 2026
f60aa1a
Declare CLI I/O backend selection
mikea Aug 18, 2026
96b9e97
Declare tokio event port bridge
mikea Aug 18, 2026
9cd1c1d
Tune high-resolution timer threads
mikea Aug 18, 2026
9b4be93
Add precise macOS deadline sleeps
mikea Aug 18, 2026
e4d58c1
Add precise Linux deadline sleeps
mikea Aug 18, 2026
b1509f7
Add portable Unix deadline sleep fallback
mikea Aug 18, 2026
c889b06
Define tokio event port scheduling constants
mikea Aug 18, 2026
f4de76c
Add local tokio task spawning
mikea Aug 18, 2026
4e1c62e
Define tokio event port shared state
mikea Aug 18, 2026
9467417
Add high-resolution timer arming
mikea Aug 18, 2026
e668daa
Stop high-resolution timers on drop
mikea Aug 18, 2026
90d6be6
Run high-resolution timer requests
mikea Aug 18, 2026
b0119ba
Define the tokio event port
mikea Aug 18, 2026
1771614
Initialize tokio event ports
mikea Aug 18, 2026
9dd0696
Wait on tokio event ports
mikea Aug 18, 2026
4a3ea71
Poll and wake tokio event ports
mikea Aug 18, 2026
3cc6180
Clean up tokio event ports on drop
mikea Aug 18, 2026
c625213
Test tokio event port behavior
mikea Aug 18, 2026
b88af97
Expose tokio event port APIs
mikea Aug 18, 2026
55644ee
Declare tokio event port
mikea Aug 18, 2026
86dd088
Add tokio async I/O context
mikea Aug 18, 2026
e5dc51b
Format tokio event port modules
mikea Aug 18, 2026
c1493ba
Define tokio I/O errors
mikea Aug 18, 2026
5519fe5
Classify portable I/O errors
mikea Aug 18, 2026
71b4333
Map Unix errors to KJ exception types
mikea Aug 18, 2026
8733b93
Convert I/O errors to KJ exceptions
mikea Aug 18, 2026
3442b95
Add portable signal watcher fallback
mikea Aug 18, 2026
b22bdab
Watch Unix signals on the tokio runtime
mikea Aug 18, 2026
f1be13f
Watch Windows console signals
mikea Aug 18, 2026
dd6f73a
Declare tokio async I/O streams
mikea Aug 18, 2026
e3cf632
Declare tokio connection receivers
mikea Aug 18, 2026
bc00183
Declare tokio network addresses
mikea Aug 18, 2026
dc78222
Declare tokio networks
mikea Aug 18, 2026
5d73e96
Declare low-level tokio I/O providers
mikea Aug 18, 2026
563093e
Declare tokio async I/O providers
mikea Aug 18, 2026
9ceea86
Declare tokio async I/O setup
mikea Aug 18, 2026
fd1fca1
Implement tokio stream reads
mikea Aug 18, 2026
9043989
Implement tokio stream operations
mikea Aug 18, 2026
0ce3be1
Authenticate accepted tokio peers
mikea Aug 18, 2026
7fd6753
Implement tokio connection receivers
mikea Aug 18, 2026
fb48dd5
Implement tokio network addresses
mikea Aug 18, 2026
9081c0b
Prepare native descriptors for tokio
mikea Aug 18, 2026
a7d8b4c
Adapt native descriptors to tokio streams
mikea Aug 18, 2026
6af4bf8
Implement tokio async I/O providers
mikea Aug 18, 2026
38c865d
Add peer address classification helpers
mikea Aug 18, 2026
fb872bf
Parse peer filter rules
mikea Aug 18, 2026
57a2be1
Apply peer filtering rules
mikea Aug 18, 2026
c2bade8
Add file watcher platform dependencies
mikea Aug 18, 2026
cccf690
Watch files with inotify
mikea Aug 18, 2026
e30552b
Watch files with kqueue
mikea Aug 18, 2026
8dd82b5
Add unsupported file watcher fallback
mikea Aug 18, 2026
7aa2044
Expose cross-platform file watching
mikea Aug 18, 2026
a38b91e
Parse Unix network addresses
mikea Aug 18, 2026
db08e02
Parse IP and hostname addresses
mikea Aug 18, 2026
8ee0990
Connect and inspect tokio addresses
mikea Aug 18, 2026
eea9da9
Listen on tokio addresses
mikea Aug 18, 2026
f1d8787
Implement tokio network listeners
mikea Aug 18, 2026
b1a5234
Resolve hostnames on the tokio runtime
mikea Aug 18, 2026
cb7dc0b
Expose tokio network address operations
mikea Aug 18, 2026
7eaa05e
Adapt owned sockets for Rust serving
mikea Aug 18, 2026
1c64717
Wrap connected native sockets
mikea Aug 18, 2026
5d31dc1
Wrap native listening sockets
mikea Aug 18, 2026
79cc0ac
Wrap connecting native sockets
mikea Aug 18, 2026
f506c95
Add Rust I/O test helpers
mikea Aug 18, 2026
e16cd72
Add Rust serving test helpers
mikea Aug 18, 2026
c2ccc21
Add Rust I/O test bridge
mikea Aug 18, 2026
dd802e2
Test Capn Proto RPC over tokio I/O
mikea Aug 18, 2026
5d54bed
Test HTTP over tokio I/O
mikea Aug 18, 2026
822303d
Test tokio file watching
mikea Aug 18, 2026
10aa007
Test Rust serving over KJ streams
mikea Aug 18, 2026
b836950
Test tokio async I/O compatibility
mikea Aug 18, 2026
827ed80
Define tokio stream variants
mikea Aug 18, 2026
447e3a7
Add tokio stream constructors and readiness
mikea Aug 18, 2026
c04503b
Read and write tokio streams
mikea Aug 18, 2026
462bb5f
Detect tokio stream disconnection
mikea Aug 18, 2026
67caf16
Shut down tokio stream writes
mikea Aug 18, 2026
094be8c
Access tokio stream socket options
mikea Aug 18, 2026
e4abdce
Inspect tokio stream endpoints
mikea Aug 18, 2026
dab101e
Consume tokio stream wrappers
mikea Aug 18, 2026
e3b9754
Expose tokio stream bridge operations
mikea Aug 18, 2026
2f3adbe
Wrap arbitrary native file descriptors
mikea Aug 18, 2026
0508419
Read tokio input descriptors
mikea Aug 18, 2026
7e9be6e
Write tokio output descriptors
mikea Aug 18, 2026
a9a1a4d
Define Rust serving paths
mikea Aug 18, 2026
636d0e3
Define tokio serving streams
mikea Aug 18, 2026
e0038a4
Read tokio serving streams
mikea Aug 18, 2026
d70078c
Write tokio serving streams
mikea Aug 18, 2026
89d07ab
Represent served KJ streams
mikea Aug 18, 2026
08b65ef
Represent native socket extraction failures
mikea Aug 18, 2026
203573d
Extract native sockets from KJ streams
mikea Aug 18, 2026
8fc0e48
Select native or pumped serving
mikea Aug 18, 2026
1894dfd
Pump KJ streams through tokio duplexes
mikea Aug 18, 2026
e6c758a
Define Rust I/O bridge vocabulary
mikea Aug 18, 2026
2c2f03c
Create the Rust I/O bridge
mikea Aug 18, 2026
a3d99c7
Bridge tokio stream operations
mikea Aug 18, 2026
7d7b926
Bridge tokio network addresses
mikea Aug 18, 2026
0a158a7
Bridge tokio listeners
mikea Aug 18, 2026
5ccd1b5
Bridge native descriptor wrapping
mikea Aug 18, 2026
f995417
Bridge signals and descriptor readiness
mikea Aug 18, 2026
10bf249
Bridge foreign KJ streams
mikea Aug 18, 2026
3ecf71c
Own native descriptors across the I/O bridge
mikea Aug 18, 2026
5b6f86c
Convert socket addresses across the I/O bridge
mikea Aug 18, 2026
5dd05c9
Read Unix socket options
mikea Aug 18, 2026
e954771
Write Unix socket options
mikea Aug 18, 2026
e5657c0
Read Windows socket options
mikea Aug 18, 2026
246ce99
Write Windows socket options
mikea Aug 18, 2026
ee9787a
Bridge stream socket options
mikea Aug 18, 2026
52087af
Bridge listener socket options
mikea Aug 18, 2026
fc671f0
Split borrowed KJ streams safely
mikea Aug 18, 2026
b58f074
Unwrap owned KJ streams
mikea Aug 18, 2026
6565c47
Expose tokio async I/O APIs
mikea Aug 18, 2026
bdb3581
Add tokio event port test helpers
mikea Aug 18, 2026
969c620
Add tokio event port test bridge
mikea Aug 18, 2026
403c577
Test tokio event port behavior
mikea Aug 18, 2026
14b73ec
Test neutralized Rust wakers
mikea Aug 18, 2026
cc2adc6
Test shared Rust future events
mikea Aug 18, 2026
759a252
Add same-thread future waker cells
mikea Aug 18, 2026
b9497b8
Declare poll-scoped Rust wakers
mikea Aug 18, 2026
6fdb36f
Attach retained waker cells to future events
mikea Aug 18, 2026
211bb45
Implement poll-scoped Rust wakers
mikea Aug 18, 2026
92fa53a
Bridge retained future waker cells
mikea Aug 18, 2026
ef1077b
Add retained-cell Rust wakers
mikea Aug 18, 2026
d636eec
Add poll-scoped Rust wakers
mikea Aug 18, 2026
5ae2e1c
Poll Rust futures with same-thread wakers
mikea Aug 18, 2026
7009a0e
Build the tokio event port crate
mikea Aug 18, 2026
82ae4b6
Build tokio event port tests
mikea Aug 18, 2026
f652aaf
Build the tokio async I/O crate
mikea Aug 18, 2026
469e471
Build tokio async I/O tests
mikea Aug 18, 2026
d6259ef
Make bridged Rust futures eager
mikea Aug 18, 2026
670ba72
Define Rust I/O backend build toggles
mikea Aug 18, 2026
a5b9d40
Trace forbidden native I/O dependencies
mikea Aug 18, 2026
a850b29
Report Rust I/O build hermeticity
mikea Aug 18, 2026
8dbed51
Add the Rust I/O hermeticity rule
mikea Aug 18, 2026
1a5d3cb
Add selectable Rust I/O backend
mikea Aug 18, 2026
90bb95e
Provide inert Windows event-port symbols
mikea Aug 18, 2026
fdc2101
Provide inert Unix event-port symbols
mikea Aug 18, 2026
1a8f9b4
Adapt tokio I/O to the KJ setup API
mikea Aug 18, 2026
fdfaae0
Add CLI I/O backend dependencies
mikea Aug 18, 2026
b49cc55
Watch CLI files with inotify
mikea Aug 18, 2026
3769796
Watch CLI files with kqueue
mikea Aug 18, 2026
4d532d4
Add Windows CLI file watcher fallback
mikea Aug 18, 2026
4c111e1
Add portable CLI file watcher fallback
mikea Aug 18, 2026
e0ac177
Adapt tokio CLI file watching
mikea Aug 18, 2026
8c36223
Select CLI signal and file watchers
mikea Aug 18, 2026
ea68617
Add backend-selectable async I/O setup
mikea Aug 18, 2026
b64830a
Isolate the legacy CLI file watcher
mikea Aug 18, 2026
e6462bf
Route CLI I/O through the selected backend
mikea Aug 18, 2026
1540626
Enforce Rust I/O server dependencies
mikea Aug 18, 2026
cfc73ed
Create the kj-rs bridge module
mikea Aug 18, 2026
cf4061a
Bridge kj-rs Rust waker storage
mikea Aug 18, 2026
b621663
Bridge kj-rs C++ wakers
mikea Aug 18, 2026
59a545e
Bridge KJ promise nodes
mikea Aug 18, 2026
9be94d2
Bridge KJ promise awaiters
mikea Aug 18, 2026
b19f8a5
Mark kj-rs FFI implementation islands
mikea Aug 18, 2026
d12a854
Add same-thread promise polling overloads
mikea Aug 18, 2026
744959c
Preserve the legacy waker bridge during migration
mikea Aug 18, 2026
975e544
Move the kj-rs bridge into its FFI island
mikea Aug 18, 2026
15803b6
Remove the embedded awaiter bridge
mikea Aug 18, 2026
f3aafa2
Remove the embedded waker bridge
mikea Aug 18, 2026
f60cfb0
Remove the embedded promise bridge
mikea Aug 18, 2026
1a4e73f
Remove the embedded bridge shell
mikea Aug 18, 2026
e121312
Remove legacy Rust waker construction
mikea Aug 18, 2026
57dabed
Remove the legacy Rust waker vtable
mikea Aug 18, 2026
0753aa7
Remove the legacy waker bridge
mikea Aug 18, 2026
1ec24d2
Use abstract async I/O dependencies
mikea Aug 18, 2026
7c7db0f
Use abstract async API dependencies
mikea Aug 18, 2026
14bc149
Link JSG against selected async I/O
mikea Aug 18, 2026
db83a6d
Link workerd tests against selected I/O
mikea Aug 18, 2026
a4835ac
Select I/O backend for KJ tests
mikea Aug 18, 2026
80da17a
Remove the legacy inotify CLI watcher
mikea Aug 18, 2026
57668ab
Remove the legacy kqueue CLI watcher
mikea Aug 18, 2026
9256768
Remove the legacy Windows CLI watcher
mikea Aug 18, 2026
4835bb5
Remove the legacy portable CLI watcher
mikea Aug 18, 2026
9e84e46
Remove legacy CLI watcher dependencies
mikea Aug 18, 2026
5ac5881
Normalize tokio async I/O implementation
mikea Aug 18, 2026
3144b76
Normalize tokio I/O error mapping
mikea Aug 18, 2026
ae660d4
Normalize the tokio I/O bridge
mikea Aug 18, 2026
abd082c
Normalize tokio file watching
mikea Aug 18, 2026
8e0b05f
Inline tokio network address parsing
mikea Aug 18, 2026
82c508c
Normalize tokio signal watching
mikea Aug 18, 2026
00bf205
Normalize tokio stream implementation
mikea Aug 18, 2026
c129a3d
Normalize tokio event port bridge
mikea Aug 18, 2026
1d037a4
Normalize tokio event port implementation
mikea Aug 18, 2026
02b3940
Normalize tokio setup shim
mikea Aug 18, 2026
bc7b5e5
Document the Rust I/O crates
mikea Aug 18, 2026
36e8639
Enforce kj-rs safety boundaries
mikea Aug 18, 2026
be5018f
Finalize promise bridge safety
mikea Aug 18, 2026
9a9325a
Document eager Rust future conversion
mikea Aug 18, 2026
9339080
Finalize the kj-rs bridge
mikea Aug 18, 2026
4931bec
Finalize kj-rs build dependencies
mikea Aug 18, 2026
5b4a96d
Convert future panics into KJ exceptions
mikea Aug 18, 2026
2166b7a
Catch panics from fallible future polls
mikea Aug 18, 2026
47fe4d7
Catch panics from infallible future polls
mikea Aug 18, 2026
ecece8c
Guard fallible future destruction from unwinding
mikea Aug 18, 2026
203f738
Guard infallible future destruction from unwinding
mikea Aug 18, 2026
7c3feda
Document Rust future safety invariants
mikea Aug 18, 2026
d88db03
Add weak links for promise awaiters
mikea Aug 18, 2026
630638b
Use weak links when polling KJ promises
mikea Aug 18, 2026
13cd6ef
Remove legacy promise polling
mikea Aug 18, 2026
1297fea
Remove legacy poll-scope implementation
mikea Aug 18, 2026
38d02d5
Remove linked-group future polling
mikea Aug 18, 2026
3822d13
Document promise awaiter weak links
mikea Aug 18, 2026
881e8bb
Remove legacy atomic waker implementation
mikea Aug 18, 2026
64cebfe
Remove legacy lazy waker implementation
mikea Aug 18, 2026
32616a0
Remove the legacy abstract waker
mikea Aug 18, 2026
2d294f2
Remove the legacy waker promise node
mikea Aug 18, 2026
ffdd604
Remove the legacy atomic waker
mikea Aug 18, 2026
39b946c
Remove the legacy lazy waker
mikea Aug 18, 2026
20f9792
Order retained waker declarations by dependency
mikea Aug 18, 2026
173ad0d
Document future poll wake behavior
mikea Aug 18, 2026
dc682c3
Place borrowed waker support before owned cells
mikea Aug 18, 2026
3e40d4b
Remove superseded borrowed waker declarations
mikea Aug 18, 2026
24f591f
Stop building linked-group tests
mikea Aug 18, 2026
de415d2
Remove obsolete linked-group tests
mikea Aug 18, 2026
fe08290
Remove obsolete linked-group documentation
mikea Aug 18, 2026
131a495
Remove the obsolete linked-group mixin
mikea Aug 18, 2026
057c218
Remove obsolete linked-object documentation
mikea Aug 18, 2026
55d22e1
Remove obsolete linked-group proxies
mikea Aug 18, 2026
4cdfc56
Remove the obsolete linked-object mixin
mikea Aug 18, 2026
ef405c9
Remove the obsolete linked-group iterator
mikea Aug 18, 2026
4017d49
Test future waker and panic handling
mikea Aug 18, 2026
a17a064
Test KJ exception descriptions across Rust FFI
mikea Aug 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@aspect_rules_js//npm:defs.bzl", "npm_link_package")
load("@bazel_skylib//lib:selects.bzl", "selects")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag")
load("@npm//:capnp-es/package_json.bzl", capnp_es_bins = "bin")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//:build/wd_cc_embed.bzl", "wd_cc_embed")
Expand Down Expand Up @@ -128,6 +128,44 @@ bool_flag(
build_setting_default = True,
)

# =============================================================================
# I/O backend selection: a build/compile/link-time hermeticity guarantee.
#
# --//:io_backend=rust (default) -- the rust I/O layer: the process event loop is tokio
# (kj-rs-tokio) and every socket/stream is tokio-backed (kj-rs-io); the
# C++ layers above the streams (kj-http, kj-tls, capnp-rpc) are unchanged
# and run over those tokio streams. In this config the forbidden concrete
# C++ OS-I/O target must be ABSENT from the link, enforced by the
# build-graph aspect in //build:rust_io_backend.bzl (whose forbidden
# set grows as later migration stages move more of the stack to rust).
# --//:io_backend=cxx -- workerd's I/O is the concrete C++ stack end to end, including the
# kj OS event loop and sockets. Byte-identical to the pre-migration
# build.
#
# Code that must differ per backend keys off the WORKERD_RUST_IO_BACKEND define (see
# //src/workerd/util:setup-async-io) or off the config_settings below in a select().
string_flag(
name = "io_backend",
build_setting_default = "rust",
values = [
"cxx",
"rust",
],
visibility = ["//visibility:public"],
)

config_setting(
name = "io_backend_rust",
flag_values = {":io_backend": "rust"},
visibility = ["//visibility:public"],
)

config_setting(
name = "io_backend_cxx",
flag_values = {":io_backend": "cxx"},
visibility = ["//visibility:public"],
)

config_setting(
name = "set_dead_strip",
flag_values = {"dead_strip": "True"},
Expand Down
4 changes: 3 additions & 1 deletion build/deps/deps.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
"type": "github_tarball",
"owner": "capnproto",
"repo": "capnproto",
"branch": "v2",
// Interim: v2 plus kj::Rc::disown()/reown() (mirror of kj::Arc's), needed by the Rust
// I/O bridge's waker. Switch back to "v2" once the upstream PR merges.
"branch": "dlapid/RcdisReOwn",
"extra_strip_prefix": "/c++"
},
// We want to avoid version skew with v8, so we use identical versions. Keep this
Expand Down
6 changes: 3 additions & 3 deletions build/deps/gen/deps.MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ bazel_dep(name = "brotli", version = "1.2.0.bcr.1")
# capnp-cpp
http.archive(
name = "capnp-cpp",
sha256 = "6753378bd099029cb2830fecd32dd158218019e459ffd3c8e379cbf025906eb8",
strip_prefix = "capnproto-capnproto-a1cd1c4/c++",
sha256 = "afaf9a84342533e12c8f8c67adcfeb59c74ba86f04c15499736de453c3edea22",
strip_prefix = "capnproto-capnproto-1ac3c72/c++",
type = "tgz",
url = "https://github.com/capnproto/capnproto/tarball/a1cd1c4b3d241b77478035a6ccad8b0fb587d444",
url = "https://github.com/capnproto/capnproto/tarball/1ac3c7259ddf3917d7c5947978e1f97bf328b699",
)
use_repo(http, "capnp-cpp")

Expand Down
7 changes: 7 additions & 0 deletions build/kj_test.bzl
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_shell//shell:sh_test.bzl", "sh_test")
load("//:build/rust_io_backend.bzl", "rust_io_backend_local_defines")

def kj_test(
src,
data = [],
deps = [],
tags = [],
size = "medium",
local_defines = [],
**kwargs):
test_name = src.removesuffix(".c++")
binary_name = test_name + "_binary"
Expand All @@ -18,6 +20,11 @@ def kj_test(
"@capnp-cpp//src/kj:kj-test",
"//build/deps:linkopts_default",
] + deps,
# Under --//:io_backend=rust the native kj::setupAsyncIo()/UnixEventPort aren't linked, so
# tests that need an event loop swap to the tokio backend behind
# `#if WORKERD_RUST_IO_BACKEND_RUST`. Supplied to every kj_test TU here (cheap, harmless
# where unused) instead of repeating it per target.
local_defines = local_defines + rust_io_backend_local_defines(),
linkstatic = select({
"@platforms//os:linux": 0,
"//conditions:default": 1,
Expand Down
165 changes: 165 additions & 0 deletions build/rust_io_backend.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
"""Build-graph hermeticity check + shared toggles for workerd's Rust I/O backend.

An aspect walks the transitive dependency graph of a guarded target and, in the rust I/O
config, fails ANALYSIS if the graph reaches a forbidden concrete C++ I/O library (the ones
the rust layer replaces), printing one example dependency path to each offender.

Why a graph assertion and not a link check: if kj-async-os sneaks back into the rust-config
graph, the failure mode is a DOUBLE-DEFINITION (kj::setupAsyncIo and kj::UnixEventPort's
members are defined by both the native TUs and the tokio shim), and with static archives the
winner is link-order-dependent -- possibly a loud duplicate-symbol error, possibly the wrong
event loop silently winning. Undefined-symbol errors only backstop the opposite (absent-lib)
direction. This aspect catches the double-definition direction deterministically, at analysis.

IMPORTANT -- the gate is opt-in: //src/workerd/server:rust-io-hermeticity is tagged `manual`,
so `bazel build //...` never runs it. The rust-config CI lane must build it EXPLICITLY for
the guarantee to hold.

The forbidden set grows in lockstep with what `=rust` means per migration stage (v1: the
tokio event loop + I/O; later stages append kj-http/kj-tls, then capnp-rpc). Deliberately
ALLOWED today: @capnp-cpp//src/kj:kj-async-core and :kj-async-io (the abstract Promise and
stream/Network layers the rust backend itself is built on), kj-http/kj-tls/capnp-rpc (still
the only implementation in both configs; they consume abstract streams, no OS I/O), and the
kj-gzip/kj-brotli codecs (not a transport).
"""

visibility("public")

def rust_io_backend_local_defines():
"""local_defines for TUs that `#if WORKERD_RUST_IO_BACKEND_RUST` (the declared seam points).

Kept per-target rather than a repo-global define so the seam stays enumerable: the only
places allowed to diverge per backend are the targets that ask for this.
"""
return select({
"//:io_backend_rust": ["WORKERD_RUST_IO_BACKEND_RUST=1"],
"//conditions:default": [],
})

# Forbidden concrete C++ I/O targets, as "//package:target" label suffixes (suffix-matched so
# bzlmod repo-name canonicalization doesn't have to be spelled out). The single source of truth.
_FORBIDDEN = [
# The kj OS event loop / socket layer (setupAsyncIo, UnixEventPort/Win32IocpEventPort),
# replaced by kj-rs-tokio + kj-rs-io.
"//src/kj:kj-async-os",
]

RustIoForbiddenInfo = provider(
doc = "One example dependency path to each forbidden C++ I/O target a subgraph reaches.",
fields = {
"paths": "dict of forbidden-label-suffix -> example path (list of label strings)",
},
)

def _forbidden_suffix(label_str):
for suffix in _FORBIDDEN:
if label_str.endswith(suffix):
return suffix
return None

def _rust_io_forbidden_aspect_impl(target, ctx):
label_str = str(target.label)
paths = {}

hit = _forbidden_suffix(label_str)
if hit != None:
paths[hit] = [label_str]

# Scan ctx.rule.attr generically (attr_aspects = ["*"]) rather than enumerating
# deps/implementation_deps/etc. per rule kind.
for attr_name in dir(ctx.rule.attr):
value = getattr(ctx.rule.attr, attr_name)
dep_targets = []
if type(value) == "list":
for item in value:
if type(item) == "Target":
dep_targets.append(item)
elif type(value) == "Target":
dep_targets.append(value)

for dep in dep_targets:
if RustIoForbiddenInfo in dep:
for forbidden, subpath in dep[RustIoForbiddenInfo].paths.items():
if forbidden not in paths:
paths[forbidden] = [label_str] + subpath

return [RustIoForbiddenInfo(paths = paths)]

rust_io_forbidden_aspect = aspect(
implementation = _rust_io_forbidden_aspect_impl,
attr_aspects = ["*"],
doc = "Propagates RustIoForbiddenInfo up the dependency graph.",
)

def _rust_io_hermeticity_impl(ctx):
info = ctx.attr.target[RustIoForbiddenInfo]
paths = info.paths

report = ctx.actions.declare_file(ctx.label.name + ".txt")

if ctx.attr.enforce and len(paths) > 0:
lines = [
"",
"Rust-I/O hermeticity FAILED for {} in the rust I/O config.".format(
str(ctx.attr.target.label),
),
"",
"Its transitive dependency graph reaches {} forbidden concrete C++ ".format(len(paths)) +
"I/O target(s) that the rust I/O layer (the tokio event loop + tokio",
"sockets) is meant to keep off the build. Each is a real migration item; the",
"example dependency edge shows one path that pulls it in:",
"",
]
for forbidden in sorted(paths.keys()):
path = paths[forbidden]
lines.append(" [FORBIDDEN] {}".format(forbidden))
lines.append(" reached via:")
for i, hop in enumerate(path):
lines.append(" {}{}".format(" " * i, hop))
lines.append("")
lines.append(
"Fix by removing the offending edge (migrate the code to the tokio-backed I/O layer,",
)
lines.append(
"or drop the forbidden dep from that target's deps under select(io_backend_rust)),",
)
lines.append(
"or -- if this is a deliberate remaining kj-mode/in-process site -- adjust the",
)
lines.append(
"forbidden set in build/rust_io_backend.bzl (a reviewable change).",
)
fail("\n".join(lines))

# Not enforcing (cxx config), or clean: emit a report artifact and a summary.
if len(paths) == 0:
summary = "rust-io-hermeticity: OK -- {} reaches 0 forbidden C++ I/O targets.".format(
str(ctx.attr.target.label),
)
else:
summary = ("rust-io-hermeticity: {} reaches {} forbidden C++ I/O target(s) " +
"(NOT enforced in this config; --//:io_backend=rust would fail): {}").format(
str(ctx.attr.target.label),
len(paths),
", ".join(sorted(paths.keys())),
)
ctx.actions.write(report, summary + "\n")
return [DefaultInfo(files = depset([report]))]

rust_io_hermeticity = rule(
implementation = _rust_io_hermeticity_impl,
doc = "Fails analysis (when enforced) if `target` transitively depends on a forbidden " +
"concrete C++ I/O library, naming the offending edge.",
attrs = {
"target": attr.label(
mandatory = True,
aspects = [rust_io_forbidden_aspect],
doc = "The target whose transitive deps are checked (e.g. the workerd binary).",
),
"enforce": attr.bool(
default = False,
doc = "Whether reaching a forbidden target fails analysis. Set from a " +
"select() on //:io_backend_rust at the instantiation site.",
),
},
)
40 changes: 38 additions & 2 deletions deps/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions deps/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ syn = { version = "2", features = ["full"] }
ada-url = { version = "4", default-features = false, features = ["std"] }
anyhow = "1"
async-trait = { version = "0", default-features = false }
bytes = "1"
capnp = "0"
capnpc = "0"
capnp-rpc = "0"
Expand All @@ -48,9 +49,9 @@ ruff_python_parser = { git = "https://github.com/astral-sh/ruff", tag = "0.12.1"
# param_extractor depends on unbounded_depth feature
serde_json = { version = "1", features = ["unbounded_depth"] }
serde = { version = "1", features = ["derive"] }
socket2 = "0.6"
thiserror = "2"
# tokio is huge, let's enable only features when we actually need them.
tokio = { version = "1", default-features = false, features = ["net", "rt", "rt-multi-thread", "time"] }
tokio = { version = "1", default-features = false, features = ["io-util", "macros", "net", "rt", "rt-multi-thread", "signal", "sync", "time"] }
tracing = { version = "0", default-features = false, features = ["std"] }
swc_common = "25"
swc_ts_fast_strip = "57"
Loading
Loading