rsloop 0.1.51__tar.gz → 0.1.52__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rsloop-0.1.51 → rsloop-0.1.52}/Cargo.lock +1 -1
- {rsloop-0.1.51 → rsloop-0.1.52}/Cargo.toml +43 -42
- rsloop-0.1.52/PKG-INFO +201 -0
- rsloop-0.1.52/README.md +168 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/benches/compare_event_loops.py +1 -3
- rsloop-0.1.52/docs/benchmarks.md +170 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/development.md +62 -5
- rsloop-0.1.52/docs/fast-streams.md +41 -0
- rsloop-0.1.52/docs/free-threading.md +43 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/how-it-works.md +43 -30
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/index.md +3 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/rust-extensions.md +1 -1
- rsloop-0.1.52/docs/supported-features.md +66 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/justfile +1 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/mkdocs.yml +4 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/pyproject.toml +56 -56
- {rsloop-0.1.51 → rsloop-0.1.52}/python/rsloop/__init__.pyi +1 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/python/rsloop/_loop_compat.py +3 -2
- {rsloop-0.1.51 → rsloop-0.1.52}/qualirs.toml +48 -48
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/hotpath_lab.py +12 -2
- {rsloop-0.1.51 → rsloop-0.1.52}/src/engine/commands.rs +4 -1
- {rsloop-0.1.51 → rsloop-0.1.52}/src/engine/dispatcher.rs +2 -1
- {rsloop-0.1.51 → rsloop-0.1.52}/src/engine/loop_core.rs +5 -4
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/accept.rs +10 -2
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/mod.rs +31 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/py_server.rs +2 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/server.rs +1 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/server_core.rs +16 -3
- {rsloop-0.1.51 → rsloop-0.1.52}/uv.lock +1 -1
- rsloop-0.1.51/PKG-INFO +0 -651
- rsloop-0.1.51/README.md +0 -618
- {rsloop-0.1.51 → rsloop-0.1.52}/.cargo/config.toml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.github/workflows/anyio.yml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.github/workflows/kani.yml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.github/workflows/mkdocs.yml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.github/workflows/tests.yml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.github/workflows/update-version.yml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.github/workflows/vibeio-native.yml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.github/workflows/wheels.yml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.gitignore +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.python-version +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/.vscode/settings.json +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/LICENSE +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/benches/compare_granian.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/benches/workload_matrix.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/build.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/examples.md +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/getting-started.md +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/hotpath-lab.md +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/project-structure.md +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/rsloop.png +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/docs/verification.md +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/01_basics.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/02_fd_and_sockets.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/03_streams.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/04_unix_and_accepted_socket.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/05_pipes_signals_subprocesses.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/README.md +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/fastapi_service.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/granian_service.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/picows_server.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/picows_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/examples/wsbench_websockets.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/pyrightconfig.json +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/python/rsloop/__init__.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/python/rsloop/_bootstrap.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/python/rsloop/_loop.pyi +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/python/rsloop/_run.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/python/rsloop/py.typed +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/rust-toolchain.toml +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/build-pgo-wheels.sh +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/build-wheels.sh +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/generate_test_tls_certs.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/prepare_anyio_rsloop_tests.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/python-versions.sh +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/run_all_tests.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/run_python_tests.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/run_rust_tests.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/scripts/test-supported-pythons.sh +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/async_event.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/asyncgens.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/asyncio_cache.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/connections.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/executor.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/fast_callbacks.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/ffi_helpers.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/lifecycle.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/methods.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/pipes.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/pre_exec.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/process_handles.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/process_spawn.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/process_stdio.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/servers.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/signals.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/sock_ops.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/socket_connect.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/socket_operation.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/sockets.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/spawn_env.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/tasks.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/tls_params.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api/watchers.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/loop_api.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/bindings/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/blocking.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/build_metadata.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/context.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/engine/callbacks.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/engine/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/engine/timer_entry.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/errors.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/lib.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/module_init.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/platform/fd/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/platform/fd/windows.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/platform/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/python_names.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/rust_async.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/core_events.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/core_protocol.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/core_state.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/params.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/py_pipes.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/py_transport.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/spawn.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/process/worker.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/buffers.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/builder.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/connect.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/core_events.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/core_protocol.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/core_state.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/core_write.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/fast.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/io_targets.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/pipe_transport.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/platform.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/poll.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/protocol.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/py_transport.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/reader.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/reader_task.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/server_types.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/socket_transport.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/stats.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/tls_session.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/tls_transport.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/tuning.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/worker.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/write_queue.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/stream/writer.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/tls/material.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/transport/tls/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/verification.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/UPSTREAM.md +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/blocking/default.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/blocking/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/builder.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/driver/iocp.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/driver/kqueue.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/driver/mio.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/driver/mock.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/driver/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/driver/uring.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/executor.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/fd_inner.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/fs/file.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/fs/metadata.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/fs/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/fs/open_options.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/io/buf.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/io/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/io/pipe.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/io/splice.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/io/stdio.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/io/util.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/lib.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/tcp/listener.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/tcp/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/tcp/stream.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/udp.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/unix/listener.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/unix/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/net/unix/stream.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/accept.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/accept_unix.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/connect.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/fsync.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/hard_link.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/io_util.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/mkdir.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/open.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/read.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/readat.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/readiness.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/readv.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/recv.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/recvfrom.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/rename.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/send.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/sendto.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/socket_addr.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/splice.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/statx.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/symlink.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/unlink.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/waitpid.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/write.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/writeat.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/op/writev.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/process/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/process/reaper.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/signal/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/signal/unix.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/signal/windows.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/task.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/test_support.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/time/interval.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/time/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/time/sleep.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/time/timeout.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/timer.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/util/async_wrap.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/src/vibeio/util/mod.rs +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/conftest.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/_smoke.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/aiohttp_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/anyio_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/beanie_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/daphne_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/django_asgi_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/django_orm_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/edgy_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/falcon_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/fastapi_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/faststream_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/hypercorn_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/litestar_granian_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/litestar_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/mangum_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/ormar_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/piccolo_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/quart_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/sanic_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/sqlalchemy_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/sqlmodel_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/starlette_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/tortoise_orm_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/integration/packages/uvicorn_test.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/proptest-regressions/transport/stream/fast.txt +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_buffered_delivery.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_compat.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_fast_callbacks.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_free_threading.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_local_sockets.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_local_timers.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_numeric_addrinfo.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_run.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_stream_reader.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_subprocesses.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_tls.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/test_write_reentrancy.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/tooling/test_benchmark_loops.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/tooling/test_granian_benchmark.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/tooling/test_hotpath_lab.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/tooling/test_test_runner.py +0 -0
- {rsloop-0.1.51 → rsloop-0.1.52}/tests/typing/public_api.py +0 -0
|
@@ -1,45 +1,37 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rsloop"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.52"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
description = "An event loop for asyncio written in Rust"
|
|
6
|
-
|
|
6
|
+
documentation = "https://github.com/RustedBytes/rsloop#readme"
|
|
7
7
|
readme = "README.md"
|
|
8
|
-
repository = "https://github.com/RustedBytes/rsloop"
|
|
9
8
|
homepage = "https://github.com/RustedBytes/rsloop"
|
|
10
|
-
|
|
9
|
+
repository = "https://github.com/RustedBytes/rsloop"
|
|
10
|
+
license = "Apache-2.0"
|
|
11
|
+
|
|
12
|
+
[package.metadata.kani.flags]
|
|
13
|
+
# Force every proof that reaches a loop to state and review its own bound.
|
|
14
|
+
default-unwind = "1"
|
|
11
15
|
|
|
12
16
|
[lib]
|
|
13
|
-
name = "rsloop"
|
|
14
17
|
crate-type = ["cdylib", "rlib"]
|
|
15
|
-
|
|
16
|
-
[features]
|
|
17
|
-
default = []
|
|
18
|
-
# Embedded-runtime modules are opt-in; production wheels retain the default
|
|
19
|
-
# networking/timer build unless a feature is explicitly requested.
|
|
20
|
-
fs = []
|
|
21
|
-
process = ["dep:async-channel"]
|
|
22
|
-
signal = ["dep:once_cell", "dep:errno"]
|
|
23
|
-
pipe = []
|
|
24
|
-
stdio = []
|
|
25
|
-
splice = []
|
|
26
|
-
blocking-default = ["dep:rusty_pool"]
|
|
18
|
+
name = "rsloop"
|
|
27
19
|
|
|
28
20
|
[dependencies]
|
|
29
|
-
errno = { version = "0.3", optional = true }
|
|
30
21
|
async-channel = { version = "2", optional = true }
|
|
31
22
|
async-io = "2"
|
|
32
23
|
async-std = "1"
|
|
33
24
|
crossbeam-channel = "0.5"
|
|
34
25
|
crossbeam-queue = "0.3"
|
|
26
|
+
errno = { version = "0.3", optional = true }
|
|
35
27
|
futures = { version = "0.3", default-features = false, features = ["std"] }
|
|
36
28
|
futures-util = "0.3"
|
|
37
29
|
libc = "0.2"
|
|
38
30
|
memchr = "2"
|
|
39
31
|
mio = "1"
|
|
32
|
+
once_cell = { version = "1", optional = true }
|
|
40
33
|
oneshot = { version = "0.2", features = ["async", "std"] }
|
|
41
34
|
pin-project-lite = "0.2"
|
|
42
|
-
once_cell = { version = "1", optional = true }
|
|
43
35
|
pyo3 = { version = "0.29.2" }
|
|
44
36
|
pyo3-async-runtimes = { version = "0.29", features = ["async-std-runtime"] }
|
|
45
37
|
rustls = "0.23"
|
|
@@ -50,48 +42,57 @@ signal-hook = "0.4"
|
|
|
50
42
|
slab = "0.4"
|
|
51
43
|
socket2 = "0.6"
|
|
52
44
|
tokio = { version = "1", default-features = false, features = ["io-util"] }
|
|
45
|
+
|
|
46
|
+
[dev-dependencies]
|
|
47
|
+
proptest = { version = "1", default-features = false, features = ["std"] }
|
|
48
|
+
|
|
49
|
+
[build-dependencies]
|
|
50
|
+
pyo3-build-config = "0.29.2"
|
|
51
|
+
|
|
53
52
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
54
53
|
io-uring = "0.7"
|
|
55
54
|
|
|
56
|
-
[target.
|
|
57
|
-
mio = { version = "1", features = ["os-
|
|
55
|
+
[target."cfg(unix)".dependencies]
|
|
56
|
+
mio = { version = "1", features = ["os-ext", "os-poll"] }
|
|
58
57
|
|
|
59
|
-
[target.
|
|
58
|
+
[target."cfg(windows)".dependencies]
|
|
60
59
|
windows-sys = { version = "0.61", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Wdk_System_IO", "Wdk_System_SystemServices", "Win32_Foundation", "Win32_Networking_WinSock", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_IO", "Win32_System_Pipes", "Win32_System_SystemInformation", "Win32_System_Threading"] }
|
|
61
60
|
|
|
62
|
-
[
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
[features]
|
|
62
|
+
default = []
|
|
63
|
+
blocking-default = ["dep:rusty_pool"]
|
|
64
|
+
# Embedded-runtime modules are opt-in; production wheels retain the default
|
|
65
|
+
# networking/timer build unless a feature is explicitly requested.
|
|
66
|
+
fs = []
|
|
67
|
+
pipe = []
|
|
68
|
+
process = ["dep:async-channel"]
|
|
69
|
+
signal = ["dep:errno", "dep:once_cell"]
|
|
70
|
+
splice = []
|
|
71
|
+
stdio = []
|
|
67
72
|
|
|
68
73
|
[lints.clippy]
|
|
74
|
+
await_holding_lock = "warn"
|
|
75
|
+
await_holding_refcell_ref = "warn"
|
|
76
|
+
cast_ptr_alignment = "warn"
|
|
77
|
+
complexity = { level = "warn", priority = -1 }
|
|
69
78
|
# Enforce bug, concurrency, and performance checks rather than style preferences.
|
|
70
79
|
correctness = { level = "deny", priority = -1 }
|
|
71
|
-
suspicious = { level = "warn", priority = -1 }
|
|
72
|
-
perf = { level = "warn", priority = -1 }
|
|
73
|
-
complexity = { level = "warn", priority = -1 }
|
|
74
|
-
style = { level = "allow", priority = -1 }
|
|
75
|
-
pedantic = { level = "allow", priority = -1 }
|
|
76
80
|
# Keep safety checks even when they belong to an otherwise disabled group.
|
|
77
81
|
missing_safety_doc = "warn"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
pedantic = { level = "allow", priority = -1 }
|
|
83
|
+
perf = { level = "warn", priority = -1 }
|
|
84
|
+
style = { level = "allow", priority = -1 }
|
|
85
|
+
suspicious = { level = "warn", priority = -1 }
|
|
81
86
|
|
|
82
87
|
[lints.rust]
|
|
83
88
|
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(kani)", "cfg(musl_v1_2_3)", "cfg(syscall_accept4)", "cfg(feature, values(\"blocking-default\", \"fs\", \"pipe\", \"process\", \"signal\", \"splice\", \"stdio\"))"] }
|
|
84
89
|
|
|
85
|
-
[
|
|
86
|
-
|
|
87
|
-
default-unwind = "1"
|
|
90
|
+
[profile.bench]
|
|
91
|
+
inherits = "release"
|
|
88
92
|
|
|
89
93
|
[profile.release]
|
|
90
94
|
opt-level = 3
|
|
91
95
|
lto = "fat"
|
|
92
|
-
codegen-units = 1
|
|
93
96
|
incremental = false
|
|
97
|
+
codegen-units = 1
|
|
94
98
|
# strip = true
|
|
95
|
-
|
|
96
|
-
[profile.bench]
|
|
97
|
-
inherits = "release"
|
rsloop-0.1.52/PKG-INFO
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rsloop
|
|
3
|
+
Version: 0.1.52
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
7
|
+
Classifier: Operating System :: MacOS
|
|
8
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
9
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
19
|
+
Classifier: Programming Language :: Rust
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Classifier: Topic :: System :: Networking
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Summary: An event loop for asyncio written in Rust
|
|
24
|
+
Keywords: asyncio,event-loop,pyo3,python,rust
|
|
25
|
+
Home-Page: https://github.com/RustedBytes/rsloop
|
|
26
|
+
Author: Yehor Smoliakov <egorsmkv@gmail.com>
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
29
|
+
Project-URL: Homepage, https://github.com/RustedBytes/rsloop
|
|
30
|
+
Project-URL: Issues, https://github.com/RustedBytes/rsloop/issues
|
|
31
|
+
Project-URL: Repository, https://github.com/RustedBytes/rsloop
|
|
32
|
+
|
|
33
|
+
<img src="./docs/rsloop.png" alt="rsloop logo" align="center">
|
|
34
|
+
|
|
35
|
+
# An event loop for asyncio written in Rust
|
|
36
|
+
|
|
37
|
+
[](https://pypi.org/project/rsloop/)
|
|
38
|
+
[](https://github.com/RustedBytes/rsloop/actions/workflows/tests.yml)
|
|
39
|
+
[](https://pepy.tech/projects/rsloop)
|
|
40
|
+
|
|
41
|
+
`rsloop` is a PyO3-based `asyncio` event loop implemented in Rust.
|
|
42
|
+
|
|
43
|
+
Each `rsloop.Loop` owns a dedicated Rust runtime thread for loop coordination
|
|
44
|
+
and I/O work. That thread runs an rsloop-specialized `vibeio` runtime, using
|
|
45
|
+
io_uring on Linux, IOCP on Windows, and native kqueue readiness on macOS.
|
|
46
|
+
Native-stream TCP reads and Unix-domain socket reads run on that runtime. On Unix, generic
|
|
47
|
+
TCP protocol readers use a second `vibeio` runtime on the Python loop thread
|
|
48
|
+
(io_uring on Linux), avoiding cross-thread delivery of each read. Non-TLS accepts
|
|
49
|
+
run on either runtime depending on where the server starts. Python callbacks,
|
|
50
|
+
tasks, and coroutines run on the thread that calls
|
|
51
|
+
`run_forever()` or `run_until_complete()` (usually the main Python thread).
|
|
52
|
+
|
|
53
|
+
The package exposes:
|
|
54
|
+
|
|
55
|
+
- a native extension module at `rsloop._loop`
|
|
56
|
+
- a Python wrapper in [`python/rsloop/__init__.py`](./python/rsloop/__init__.py)
|
|
57
|
+
- `rsloop.Loop`, `rsloop.EventLoopPolicy`, `rsloop.new_event_loop()`,
|
|
58
|
+
`rsloop.run(...)`, `rsloop.install()`, `rsloop.uninstall()`, and
|
|
59
|
+
`rsloop.build_info()`
|
|
60
|
+
|
|
61
|
+
Repository metadata currently targets Python `>=3.10`.
|
|
62
|
+
The native runtime requires Linux 6.1+, macOS 13+, or Windows 10+ so its hot
|
|
63
|
+
paths can rely on modern completion, timer, and scheduler primitives.
|
|
64
|
+
Free-threaded CPython (`3.14t`) is supported: the extension declares
|
|
65
|
+
`gil_used = false`, so importing it no longer re-enables the GIL. See
|
|
66
|
+
[Free-Threaded CPython](./docs/free-threading.md) for what that does and does not
|
|
67
|
+
buy you.
|
|
68
|
+
|
|
69
|
+
## Documentation
|
|
70
|
+
|
|
71
|
+
Project documentation now lives in [`docs/`](./docs/).
|
|
72
|
+
|
|
73
|
+
If you are new to the repository, start with:
|
|
74
|
+
|
|
75
|
+
- [`docs/index.md`](./docs/index.md)
|
|
76
|
+
- [`docs/getting-started.md`](./docs/getting-started.md)
|
|
77
|
+
- [`docs/supported-features.md`](./docs/supported-features.md)
|
|
78
|
+
- [`docs/fast-streams.md`](./docs/fast-streams.md)
|
|
79
|
+
- [`docs/free-threading.md`](./docs/free-threading.md)
|
|
80
|
+
- [`docs/rust-extensions.md`](./docs/rust-extensions.md)
|
|
81
|
+
- [`docs/how-it-works.md`](./docs/how-it-works.md)
|
|
82
|
+
- [`docs/project-structure.md`](./docs/project-structure.md)
|
|
83
|
+
- [`docs/development.md`](./docs/development.md) for building, testing, and profiling
|
|
84
|
+
|
|
85
|
+
To browse the docs locally with MkDocs:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uvx --from mkdocs mkdocs serve
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
From PyPI:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install rsloop
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
With `uv`:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
uv add rsloop
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
From [conda-forge](https://conda-forge.org), using [pixi](https://pixi.prefix.dev/latest/#installation):
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pixi add rsloop
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Usage
|
|
112
|
+
|
|
113
|
+
Simple entry point:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
import rsloop
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
async def main(): ...
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
rsloop.run(main())
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Install as the default asyncio event loop policy:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import asyncio
|
|
129
|
+
import rsloop
|
|
130
|
+
|
|
131
|
+
rsloop.install()
|
|
132
|
+
try:
|
|
133
|
+
asyncio.run(main())
|
|
134
|
+
finally:
|
|
135
|
+
rsloop.uninstall()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Manual loop creation also works:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
import asyncio
|
|
142
|
+
import rsloop
|
|
143
|
+
|
|
144
|
+
loop = rsloop.new_event_loop()
|
|
145
|
+
asyncio.set_event_loop(loop)
|
|
146
|
+
try:
|
|
147
|
+
loop.run_until_complete(...)
|
|
148
|
+
finally:
|
|
149
|
+
asyncio.set_event_loop(None)
|
|
150
|
+
loop.close()
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Importing `rsloop` also patches `asyncio.set_event_loop()` so Python 3.10 can
|
|
154
|
+
accept an `rsloop.Loop` instance, matching the behavior exercised by
|
|
155
|
+
[`tests/test_run.py`](./tests/test_run.py).
|
|
156
|
+
|
|
157
|
+
## Examples
|
|
158
|
+
|
|
159
|
+
Run the repository examples from the project root:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv run python examples/01_basics.py
|
|
163
|
+
uv run python examples/02_fd_and_sockets.py
|
|
164
|
+
uv run python examples/03_streams.py
|
|
165
|
+
uv run python examples/04_unix_and_accepted_socket.py
|
|
166
|
+
uv run python examples/05_pipes_signals_subprocesses.py
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Example files:
|
|
170
|
+
[`examples/01_basics.py`](./examples/01_basics.py),
|
|
171
|
+
[`examples/02_fd_and_sockets.py`](./examples/02_fd_and_sockets.py),
|
|
172
|
+
[`examples/03_streams.py`](./examples/03_streams.py),
|
|
173
|
+
[`examples/04_unix_and_accepted_socket.py`](./examples/04_unix_and_accepted_socket.py),
|
|
174
|
+
[`examples/05_pipes_signals_subprocesses.py`](./examples/05_pipes_signals_subprocesses.py).
|
|
175
|
+
|
|
176
|
+
The repository also includes:
|
|
177
|
+
|
|
178
|
+
- [`examples/fastapi_service.py`](./examples/fastapi_service.py) for running the same
|
|
179
|
+
FastAPI app on stdlib `asyncio`, `uvloop`, or `rsloop`
|
|
180
|
+
- [`examples/granian_service.py`](./examples/granian_service.py) for registering
|
|
181
|
+
`rsloop` as Granian's worker event loop
|
|
182
|
+
- [`benches/compare_event_loops.py`](./benches/compare_event_loops.py)
|
|
183
|
+
for callback, task, and TCP stream comparisons
|
|
184
|
+
- [`benches/compare_granian.py`](./benches/compare_granian.py) for Granian HTTP
|
|
185
|
+
throughput and latency comparisons with `oha`
|
|
186
|
+
|
|
187
|
+
## Benchmarks
|
|
188
|
+
|
|
189
|
+
See [benchmark results and reproduction commands](./docs/benchmarks.md).
|
|
190
|
+
|
|
191
|
+
## Acknowledgements
|
|
192
|
+
|
|
193
|
+
`rsloop` builds on the Python `asyncio` model and is implemented with
|
|
194
|
+
[PyO3](https://pyo3.rs/) on the Rust side. Runtime and socket I/O are powered by
|
|
195
|
+
[vibeio](https://crates.io/crates/vibeio).
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
This project is licensed under the Apache License, Version 2.0. See
|
|
200
|
+
[`LICENSE`](./LICENSE) for the full text.
|
|
201
|
+
|
rsloop-0.1.52/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<img src="./docs/rsloop.png" alt="rsloop logo" align="center">
|
|
2
|
+
|
|
3
|
+
# An event loop for asyncio written in Rust
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/rsloop/)
|
|
6
|
+
[](https://github.com/RustedBytes/rsloop/actions/workflows/tests.yml)
|
|
7
|
+
[](https://pepy.tech/projects/rsloop)
|
|
8
|
+
|
|
9
|
+
`rsloop` is a PyO3-based `asyncio` event loop implemented in Rust.
|
|
10
|
+
|
|
11
|
+
Each `rsloop.Loop` owns a dedicated Rust runtime thread for loop coordination
|
|
12
|
+
and I/O work. That thread runs an rsloop-specialized `vibeio` runtime, using
|
|
13
|
+
io_uring on Linux, IOCP on Windows, and native kqueue readiness on macOS.
|
|
14
|
+
Native-stream TCP reads and Unix-domain socket reads run on that runtime. On Unix, generic
|
|
15
|
+
TCP protocol readers use a second `vibeio` runtime on the Python loop thread
|
|
16
|
+
(io_uring on Linux), avoiding cross-thread delivery of each read. Non-TLS accepts
|
|
17
|
+
run on either runtime depending on where the server starts. Python callbacks,
|
|
18
|
+
tasks, and coroutines run on the thread that calls
|
|
19
|
+
`run_forever()` or `run_until_complete()` (usually the main Python thread).
|
|
20
|
+
|
|
21
|
+
The package exposes:
|
|
22
|
+
|
|
23
|
+
- a native extension module at `rsloop._loop`
|
|
24
|
+
- a Python wrapper in [`python/rsloop/__init__.py`](./python/rsloop/__init__.py)
|
|
25
|
+
- `rsloop.Loop`, `rsloop.EventLoopPolicy`, `rsloop.new_event_loop()`,
|
|
26
|
+
`rsloop.run(...)`, `rsloop.install()`, `rsloop.uninstall()`, and
|
|
27
|
+
`rsloop.build_info()`
|
|
28
|
+
|
|
29
|
+
Repository metadata currently targets Python `>=3.10`.
|
|
30
|
+
The native runtime requires Linux 6.1+, macOS 13+, or Windows 10+ so its hot
|
|
31
|
+
paths can rely on modern completion, timer, and scheduler primitives.
|
|
32
|
+
Free-threaded CPython (`3.14t`) is supported: the extension declares
|
|
33
|
+
`gil_used = false`, so importing it no longer re-enables the GIL. See
|
|
34
|
+
[Free-Threaded CPython](./docs/free-threading.md) for what that does and does not
|
|
35
|
+
buy you.
|
|
36
|
+
|
|
37
|
+
## Documentation
|
|
38
|
+
|
|
39
|
+
Project documentation now lives in [`docs/`](./docs/).
|
|
40
|
+
|
|
41
|
+
If you are new to the repository, start with:
|
|
42
|
+
|
|
43
|
+
- [`docs/index.md`](./docs/index.md)
|
|
44
|
+
- [`docs/getting-started.md`](./docs/getting-started.md)
|
|
45
|
+
- [`docs/supported-features.md`](./docs/supported-features.md)
|
|
46
|
+
- [`docs/fast-streams.md`](./docs/fast-streams.md)
|
|
47
|
+
- [`docs/free-threading.md`](./docs/free-threading.md)
|
|
48
|
+
- [`docs/rust-extensions.md`](./docs/rust-extensions.md)
|
|
49
|
+
- [`docs/how-it-works.md`](./docs/how-it-works.md)
|
|
50
|
+
- [`docs/project-structure.md`](./docs/project-structure.md)
|
|
51
|
+
- [`docs/development.md`](./docs/development.md) for building, testing, and profiling
|
|
52
|
+
|
|
53
|
+
To browse the docs locally with MkDocs:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uvx --from mkdocs mkdocs serve
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
From PyPI:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install rsloop
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
With `uv`:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv add rsloop
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
From [conda-forge](https://conda-forge.org), using [pixi](https://pixi.prefix.dev/latest/#installation):
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pixi add rsloop
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Usage
|
|
80
|
+
|
|
81
|
+
Simple entry point:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import rsloop
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def main(): ...
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
rsloop.run(main())
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Install as the default asyncio event loop policy:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import asyncio
|
|
97
|
+
import rsloop
|
|
98
|
+
|
|
99
|
+
rsloop.install()
|
|
100
|
+
try:
|
|
101
|
+
asyncio.run(main())
|
|
102
|
+
finally:
|
|
103
|
+
rsloop.uninstall()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Manual loop creation also works:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
import asyncio
|
|
110
|
+
import rsloop
|
|
111
|
+
|
|
112
|
+
loop = rsloop.new_event_loop()
|
|
113
|
+
asyncio.set_event_loop(loop)
|
|
114
|
+
try:
|
|
115
|
+
loop.run_until_complete(...)
|
|
116
|
+
finally:
|
|
117
|
+
asyncio.set_event_loop(None)
|
|
118
|
+
loop.close()
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Importing `rsloop` also patches `asyncio.set_event_loop()` so Python 3.10 can
|
|
122
|
+
accept an `rsloop.Loop` instance, matching the behavior exercised by
|
|
123
|
+
[`tests/test_run.py`](./tests/test_run.py).
|
|
124
|
+
|
|
125
|
+
## Examples
|
|
126
|
+
|
|
127
|
+
Run the repository examples from the project root:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
uv run python examples/01_basics.py
|
|
131
|
+
uv run python examples/02_fd_and_sockets.py
|
|
132
|
+
uv run python examples/03_streams.py
|
|
133
|
+
uv run python examples/04_unix_and_accepted_socket.py
|
|
134
|
+
uv run python examples/05_pipes_signals_subprocesses.py
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Example files:
|
|
138
|
+
[`examples/01_basics.py`](./examples/01_basics.py),
|
|
139
|
+
[`examples/02_fd_and_sockets.py`](./examples/02_fd_and_sockets.py),
|
|
140
|
+
[`examples/03_streams.py`](./examples/03_streams.py),
|
|
141
|
+
[`examples/04_unix_and_accepted_socket.py`](./examples/04_unix_and_accepted_socket.py),
|
|
142
|
+
[`examples/05_pipes_signals_subprocesses.py`](./examples/05_pipes_signals_subprocesses.py).
|
|
143
|
+
|
|
144
|
+
The repository also includes:
|
|
145
|
+
|
|
146
|
+
- [`examples/fastapi_service.py`](./examples/fastapi_service.py) for running the same
|
|
147
|
+
FastAPI app on stdlib `asyncio`, `uvloop`, or `rsloop`
|
|
148
|
+
- [`examples/granian_service.py`](./examples/granian_service.py) for registering
|
|
149
|
+
`rsloop` as Granian's worker event loop
|
|
150
|
+
- [`benches/compare_event_loops.py`](./benches/compare_event_loops.py)
|
|
151
|
+
for callback, task, and TCP stream comparisons
|
|
152
|
+
- [`benches/compare_granian.py`](./benches/compare_granian.py) for Granian HTTP
|
|
153
|
+
throughput and latency comparisons with `oha`
|
|
154
|
+
|
|
155
|
+
## Benchmarks
|
|
156
|
+
|
|
157
|
+
See [benchmark results and reproduction commands](./docs/benchmarks.md).
|
|
158
|
+
|
|
159
|
+
## Acknowledgements
|
|
160
|
+
|
|
161
|
+
`rsloop` builds on the Python `asyncio` model and is implemented with
|
|
162
|
+
[PyO3](https://pyo3.rs/) on the Rust side. Runtime and socket I/O are powered by
|
|
163
|
+
[vibeio](https://crates.io/crates/vibeio).
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
This project is licensed under the Apache License, Version 2.0. See
|
|
168
|
+
[`LICENSE`](./LICENSE) for the full text.
|
|
@@ -533,9 +533,7 @@ def run_child(
|
|
|
533
533
|
if not lines:
|
|
534
534
|
raise RuntimeError(f"{loop_name}/{workload} produced no output")
|
|
535
535
|
payload = next(
|
|
536
|
-
json.loads(line)
|
|
537
|
-
for line in reversed(lines)
|
|
538
|
-
if line.lstrip().startswith("{")
|
|
536
|
+
json.loads(line) for line in reversed(lines) if line.lstrip().startswith("{")
|
|
539
537
|
)
|
|
540
538
|
return ChildResult(
|
|
541
539
|
loop=payload["loop"],
|