socketry 0.1.0

Foundational concurrency APIs for Socketry
Documentation
# Conventions

## Repository and packages

- Use lowercase filenames for Markdown documents. In particular, use
  readme.md and license.md.
- The first line of each license.md is `# MIT License`. Preserve attribution
  when copying or porting upstream code.
- Keep foundational Rust packages in this repository's Cargo workspace. Give
  published component packages the `socketry-` prefix.
- Keep the root Cargo package named `socketry`; use it as the convenient public
  facade for the foundational packages.
- Keep package APIs in separately publishable workspace members when they have
  a clear dependency and version boundary.
- Keep this file as the record of project-specific conventions and follow it
  when adding or changing files.
- Use Cargo's standard `src/`, `tests/`, and `examples/` directories. Keep
  architecture-specific implementations in separate modules.
- Treat `socketry-` as the published package prefix. Use semantic module
  names within packages; the facade exposes `socketry::executor`.
- Keep the future executor in `crates/executor`, published as `socketry-executor`.
  Its public scheduler type is `Scheduler`, also exported as `socketry::Scheduler`.
- Create a new package when it has a useful implementation and a clear
  dependency boundary. Keep higher-level protocol packages in their own
  repositories when appropriate.

## Rust code

- Avoid abbreviations in source code. Prefer clear, consistent names over
  shortened names. Preserve names required by external APIs, traits, and
  vendored source.
- Follow Rust naming conventions and use the workspace's `cargo fmt` style.
- Keep public APIs small. Prefer private implementation details until a
  concrete consumer needs them.
- Use `Result` for expected failures. Document panic conditions and avoid
  `unwrap` and `expect` for recoverable failures in library code.
- Prefer standard types and established traits where their semantics fit.
  Document why a new abstraction is necessary.
- Use safe Rust by default. Keep unsafe code narrowly scoped, state its
  invariants in `SAFETY` comments, and document caller obligations on unsafe
  public functions.

## Runtime boundaries

- New concurrency work targets ordinary futures, without a coroutine stack
  per task. The coroutine implementation is saved on its own branch; see
  design.md for the migration plan.
- Protocol code depends on the I/O and task capabilities it uses. Keep
  concrete executors, OS selectors, and runtime adapters at explicit boundaries.
- Use `selector` for Socketry's native I/O backends. Keep platform modules
  under `scheduler/selector/` and runtime adapters such as Tokio alongside
  `scheduler/socketry.rs`. Upstream dependencies may use their own terminology.
- Select native implementations through target configuration and Cargo
  features. Share portable contracts and fallback helpers, retaining concrete
  future types. Readiness is a socket capability, not a regular-file fallback.
- Pass the task owner explicitly when a library starts child tasks. Scheduler
  and barrier ownership follow the same spawning contract. Contextual lookup
  may be a convenience at the application boundary.
- Document whether a future, handle, or resource is Send, Sync, or restricted
  to a thread. Let Rust check these properties. Do not add unsafe Send or Sync
  implementations solely to satisfy a spawning bound.
- Document cancellation at each asynchronous API: what happens before
  submission, during execution, after partial progress, and on drop.
- Destructors perform synchronous cleanup or request deferred cleanup.
  Methods that wait for shutdown return futures. Do not promise asynchronous
  cleanup has completed merely because a value was dropped.

## Performance and dependencies

- Make allocation, copying, locking, and reference counting costs explicit
  where they affect frequently used operations. Reuse registrations and
  buffers when their lifetimes permit it.
- Prefer concrete or generic futures. Introduce boxed futures and dynamic
  dispatch at deliberate boundaries rather than on every I/O operation.
- Keep optional runtime and platform dependencies out of portable packages.
  Adding a backend must not require every consumer to enable it.
- Distinguish a performance hypothesis from a measured result. A Rust port
  inherits an algorithm, not the upstream implementation's benchmark results.

## Documentation and verification

- Describe implemented behavior separately from planned behavior. Include
  ownership, shutdown, and runtime requirements in public API documentation.
- Keep agent-context.md current when implementation boundaries change. Put
  reusable Rust guidance in context/rust.md.
- Put public API tests in `tests/`; keep tests of private invariants beside
  the implementation or in a private test module.
- When tests or benchmarks are requested, use deterministic clocks and
  synchronization where possible. Record which platforms and configurations
  actually ran; distinguish compilation from execution.
- Retain upstream revision, paths, license, and attribution for ports. Keep
  verbatim vendor copies separate from translated Rust implementations.