kevy_client_async/lib.rs
1//! kevy-client-async — async client for kevy, runtime-agnostic core
2//! with feature-gated transports for `tokio`, `smol`, and `async-std`.
3//!
4//! # Status
5//!
6//! Phase-4 first cut (T4.x). Surface is intentionally a near-1:1 mirror
7//! of the blocking [`kevy_client::Connection`], plus the pipeline-first
8//! sugar locked by RFC 2026-06-18-v3-cluster Q4 part b. See
9//! `docs/async.md` (added T4.26) for the full guide.
10//!
11//! # Runtime selection
12//!
13//! Exactly one of the following Cargo features must be enabled:
14//!
15//! | feature | transport |
16//! |-------------|--------------------------------------|
17//! | `tokio` | `tokio::net::TcpStream` (T4.5) |
18//! | `smol` | `smol::net::TcpStream` (T4.6) |
19//! | `async-std` | `async_std::net::TcpStream` (T4.7) |
20//!
21//! `default = ["tokio"]` is a dev convenience so `cargo test
22//! --workspace` builds without flags; **lib consumers should set
23//! `default-features = false`** and pick their runtime explicitly so
24//! the wrong one is never silently inherited. Enabling zero or more
25//! than one triggers a `compile_error!` from this crate (T4.8).
26//!
27//! # Dep-rule exemption
28//!
29//! This crate is the sole carved exemption from the project's
30//! 0-crates.io-dep rule. Rationale: the Rust async ecosystem has no
31//! std-only viable substrate. The exemption is per-crate and per-dep:
32//! `kevy-client-async` may dep tokio / smol / async-std (and only those
33//! three) with `default-features = false` + minimum-surface features
34//! and an inline `# EXEMPTION` Cargo.toml comment. See RFC F5 and
35//! memory `feedback-pure-rust-no-c-principle.md`.
36//!
37//! # Error compatibility
38//!
39//! Every async method returns `std::io::Result<T>` with the same
40//! `ErrorKind` variants the blocking [`kevy_client`](https://docs.rs/kevy-client)
41//! surface produces. This is contract, not coincidence — it lets
42//! caller code carry over without changing match arms.
43//!
44//! | source | `ErrorKind` |
45//! |---------------------------------------|--------------------|
46//! | RESP `-ERR …` reply | `Other` |
47//! | unexpected reply variant | `Other` |
48//! | malformed RESP frame | `InvalidData` |
49//! | server closed connection mid-read | `UnexpectedEof` |
50//! | unknown URL scheme / bad port / etc. | `InvalidInput` |
51//! | TLS / AUTH / embed URL scheme | `Unsupported` |
52//! | underlying socket I/O | (native kind) |
53//!
54//! Wider error context (the RESP error string, the unexpected
55//! variant name) is carried in the `io::Error`'s message — fetch with
56//! `.to_string()` / `.into_inner()`.
57
58#![forbid(unsafe_code)]
59#![warn(missing_docs)]
60
61pub mod cluster;
62mod cluster_topology;
63pub mod cmd_hash;
64pub mod cmd_list;
65pub mod cmd_set;
66pub mod cmd_string;
67pub mod cmd_zset;
68pub mod codec;
69pub mod conn;
70pub mod pipeline;
71pub mod pubsub;
72mod reply;
73pub mod subscriber;
74pub mod transport;
75pub mod url;
76
77#[cfg(feature = "tokio")]
78pub mod rt_tokio;
79
80#[cfg(feature = "smol")]
81pub mod rt_smol;
82
83#[cfg(feature = "async-std")]
84pub mod rt_async_std;
85
86pub use codec::AsyncRespCodec;
87pub use conn::AsyncConnection;
88pub use transport::{AsyncRead, AsyncTransport, AsyncWrite, read, write_all};
89
90// T4.8 — compile-time runtime selection gate. We enforce
91// **exactly-one**: zero enabled = no IO substrate (silent shell);
92// more than one enabled = ambiguous transport pick + bloats the build
93// with unused runtimes. Either fails the build with a clear message.
94
95#[cfg(not(any(feature = "tokio", feature = "smol", feature = "async-std")))]
96compile_error!(
97 "kevy-client-async requires exactly one runtime feature to be enabled: \
98 `tokio`, `smol`, or `async-std`. See the crate-level docs."
99);
100
101#[cfg(any(
102 all(feature = "tokio", feature = "smol"),
103 all(feature = "tokio", feature = "async-std"),
104 all(feature = "smol", feature = "async-std"),
105))]
106compile_error!(
107 "kevy-client-async: multiple runtime features enabled. Pick exactly \
108 one of `tokio`, `smol`, or `async-std` — never two."
109);