1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! A facade that provides an efficient, unified API for async I/O and task management,
//! as well as blocking I/O where applicable.
//! Intended for use by other library crates which need async I/O but want to remain runtime-agnostic,
//! such as [SQLx](https://github.com/launchbadge/sqlx) <sup>(shameless plug)</sup>.
//!
//! ## Usage
//!
//! The types and functions in this crate are meant to be, more or less,
//! drop-in replacements for their counterparts in Tokio and `async-std`.
//! The `rtx` crate will pick the correct runtime to use automatically,
//! assuming the correct features are enabled.
//!
//! The overhead is intended to be as small as possible; if only one runtime feature is enabled,
//! the performance should be identical to using that runtime directly.
//!
//! **Library crates: do not enable the `tokio` or `async-std` features directly.**
//! Instead, either forward those features through your `Cargo.toml`, or instruct
//! your users to depend on `rtx` directly and enable the feature for their chosen runtime.
//!
//! #### Forwarded features example (recommended for best user experience)
//! Add this to your crate's `Cargo.toml`:
//! ```toml,ignore
//! [dependencies]
//! rtx = "0.1"
//!
//! [features]
//! tokio = ["rtx/tokio"]
//! async-std ["rtx/async-std"]
//! ```
//! and then instruct users to enable the `tokio` or `async-std` feature of your crate,
//! corresponding to their chosen runtime.
//!
//! This has the advantage of allowing you to upgrade `rtx` at will without breaking downstream
//! consumers.
//!
//! #### Non-forwarded features example (simpler but less optimal user experience)
//! Simply instruct your users to add this to their `Cargo.toml`:
//!
//! ```toml,ignore
//! [dependencies]
//! ## if using `tokio`
//! rtx = { version = "0.1", features = ["tokio"]
//! ## if using `async-std`
//! rtx = { version = "0.1", features = ["async-std"]
//! ```
//!
//! This simplifies your crate's features at the expense of involving `rtx` in your semantic
//! versioning, as your users will need to keep their `rtx` version in sync with yours, and so
//! non-backwards-compatible upgrades to `rtx`, e.g. `0.1.0` to `0.2.0`, must be considered a
//! breaking change to your crate.
//!
//! ## How it Works
//! Unlike the previous incarnation of this crate, `sqlx-rt`, the runtime features are **not**
//! mutually exclusive.
//!
//! When you call a free function or a constructor-like method of a type,
//! it internally picks the correct underlying function for the context.
//!
//! For example, when you call [`net::TcpStream::connect()`]:
//!
//! * if the `tokio` feature is enabled and a Tokio context is active
//! <sup><a href="#how-works-1">(1)</a></sup>, it calls `tokio::net::TcpStream::connect()`.
//! * or, if the `async-std` feature is enabled, it calls `async_std::net::TcpStream::connect()`
//! <sup><a href="#how-works-2">(2)</a></sup>
//! * otherwise, it panics.<sup><a href="#how-works-3">(3)</a></sup>
//!
//! However, once a type has been instantiated in a particular runtime, that instance will only
//! use that runtime. This is to limit branching in hot code paths when both the `tokio`
//! and `async-std` features are enabled<sup><a href="#how-works-4">(4)</a></sup>.
//! **Thus, an instance of a type like [`net::TcpStream`] created in a Tokio runtime
//! will likely panic if sent to and used in a task in the `async-std` runtime.**
//! You should still avoid mixing and matching runtimes if at all possible.
//!
//! Some types also support blocking operations, but those will use separate methods with
//! `_blocking` in the name. If a type is constructed in blocking mode but you attempt to use
//! an async method on it, it will panic. Conversely, calling a blocking method on a type
//! constructed in non-blocking mode may either return `std::io::ErrorKind::WouldBlock` or panic,
//! depending on what makes sense for the context. The exact behavior will be documented on the
//! impl or method in question.
//!
//! <sup id="how-works-1">(1) via `tokio::runtime::Handle::try_current()`</sup>
//! <sup id="how-works-2">
//! (2) actually, `async_io::Async::<std::net::TcpStream>::connect()`
//! because `async-std`'s version doesn't support polling for readiness which we needed for our
//! use-cases, but [
//! `async_std::net::TcpStream` is also but a thin facade around the former anyway.
//! ](https://docs.rs/async-std/1.10.0/src/async_std/net/tcp/stream.rs.html#49-51)
//! </sup>
//! <sup id="how-works-3">
//! (3) similar to how Tokio's types panic if a runtime is not available.
//! </sup>
//! <sup id="how-works-4">
//! (4) also, not every type has a way to jump back and forth between runtimes.
//! `TcpStream` can be converted via `std::net::TcpStream` as an intermediate, but most types
//! won't support something like that.
//! </sup>
//!
//! ### Note: API is Incomplete
//! The current API is the bare minimum to suit our needs. If there's something missing that you
//! need, feel free to open an issue, or ideally a PR.
extern crate tokio_ as tokio;
extern crate async_std_ as async_std;