retty_io/
lib.rs

1// retty-io targets old versions of the Rust compiler. In order to do this, uses
2// deprecated APIs.
3#![allow(
4    bare_trait_objects,
5    deprecated,
6    unknown_lints,
7    unstable_name_collisions
8)]
9//#![deny(missing_docs, missing_debug_implementations)]
10//#![cfg_attr(test, deny(warnings))]
11// Many of retty-io's public methods violate this lint, but they can't be fixed
12// without a breaking change.
13#![cfg_attr(feature = "cargo-clippy", allow(clippy::trivially_copy_pass_by_ref))]
14
15//! A fast, low-level IO library for Rust focusing on non-blocking APIs, event
16//! notification, and other useful utilities for building high performance IO
17//! apps.
18//!
19//! # Features
20//!
21//! * Non-blocking TCP, UDP
22//! * Timer, Channel, Broadcast
23//! * I/O event notification queue backed by epoll, kqueue, and IOCP
24//! * Zero allocations at runtime
25//! * Platform specific extensions
26//!
27//! # Non-goals
28//!
29//! The following are specifically omitted from retty-io and are left to the user or higher-level libraries.
30//!
31//! * File operations
32//! * Thread pools / multi-threaded event loop
33//!
34//! # Platforms
35//!
36//! Currently supported platforms:
37//!
38//! * Linux
39//! * OS X
40//! * Windows
41//! * FreeBSD
42//! * NetBSD
43//! * Android
44//! * iOS
45//!
46//! retty-io can handle interfacing with each of the event notification systems of the aforementioned platforms. The details of
47//! their implementation are further discussed in [`Poll`].
48//!
49//! # Usage
50//!
51//! Using retty-io starts by creating a [`Poll`], which reads events from the OS and
52//! put them into [`Events`]. You can handle IO events from the OS with it.
53//!
54//! For more detail, see [`Poll`].
55//!
56//! [`Poll`]: struct.Poll.html
57//! [`Events`]: struct.Events.html
58//!
59//! # Example
60//!
61//! ```
62//! use retty_io::*;
63//! use retty_io::net::{TcpListener, TcpStream};
64//!
65//! // Setup some tokens to allow us to identify which event is
66//! // for which socket.
67//! const SERVER: Token = Token(0);
68//! const CLIENT: Token = Token(1);
69//!
70//! let addr = "127.0.0.1:13265".parse().unwrap();
71//!
72//! // Setup the server socket
73//! let server = TcpListener::bind(&addr).unwrap();
74//!
75//! // Create a poll instance
76//! let poll = Poll::new().unwrap();
77//!
78//! // Start listening for incoming connections
79//! poll.register(&server, SERVER, Ready::readable(),
80//!               PollOpt::edge()).unwrap();
81//!
82//! // Setup the client socket
83//! let sock = TcpStream::connect(&addr).unwrap();
84//!
85//! // Register the socket
86//! poll.register(&sock, CLIENT, Ready::readable(),
87//!               PollOpt::edge()).unwrap();
88//!
89//! // Create storage for events
90//! let mut events = Events::with_capacity(1024);
91//!
92//! loop {
93//!     poll.poll(&mut events, None).unwrap();
94//!
95//!     for event in events.iter() {
96//!         match event.token() {
97//!             SERVER => {
98//!                 // Accept and drop the socket immediately, this will close
99//!                 // the socket and notify the client of the EOF.
100//!                 let _ = server.accept();
101//!             }
102//!             CLIENT => {
103//!                 // The server just shuts down the socket, let's just exit
104//!                 // from our event loop.
105//!                 return;
106//!             }
107//!             _ => unreachable!(),
108//!         }
109//!     }
110//! }
111//!
112//! ```
113
114extern crate crossbeam;
115extern crate iovec;
116extern crate net2;
117extern crate slab;
118
119#[cfg(target_os = "fuchsia")]
120extern crate fuchsia_zircon as zircon;
121#[cfg(target_os = "fuchsia")]
122extern crate fuchsia_zircon_sys as zircon_sys;
123
124#[cfg(unix)]
125extern crate libc;
126
127#[cfg(windows)]
128extern crate miow;
129
130#[cfg(windows)]
131extern crate winapi;
132
133#[cfg(windows)]
134extern crate kernel32;
135
136#[macro_use]
137extern crate log;
138
139mod event_imp;
140mod io;
141mod poll;
142mod sys;
143mod token;
144
145pub mod broadcast;
146pub mod channel;
147pub mod lazycell;
148pub mod net;
149pub mod timer;
150
151#[deprecated(since = "0.6.5", note = "update to use `Poll`")]
152#[cfg(feature = "with-deprecated")]
153#[doc(hidden)]
154pub mod deprecated;
155
156#[deprecated(since = "0.6.5", note = "use iovec crate directly")]
157#[cfg(feature = "with-deprecated")]
158#[doc(hidden)]
159pub use iovec::IoVec;
160
161#[deprecated(since = "0.6.6", note = "use net module instead")]
162#[cfg(feature = "with-deprecated")]
163#[doc(hidden)]
164pub mod tcp {
165    pub use net::{TcpListener, TcpStream};
166    pub use std::net::Shutdown;
167}
168
169pub use event_imp::{PollOpt, Ready};
170pub use poll::{Poll, Registration, SetReadiness};
171pub use token::Token;
172
173pub mod event {
174    //! Readiness event types and utilities.
175
176    pub use super::event_imp::{Event, Evented};
177    pub use super::poll::{Events, Iter};
178}
179
180pub use event::Events;
181
182#[deprecated(since = "0.6.5", note = "use events:: instead")]
183#[cfg(feature = "with-deprecated")]
184#[doc(hidden)]
185pub use event::{Event, Evented};
186
187#[deprecated(since = "0.6.5", note = "use events::Iter instead")]
188#[cfg(feature = "with-deprecated")]
189#[doc(hidden)]
190pub use poll::Iter as EventsIter;
191
192#[deprecated(since = "0.6.5", note = "std::io::Error can avoid the allocation now")]
193#[cfg(feature = "with-deprecated")]
194#[doc(hidden)]
195pub use io::deprecated::would_block;
196
197#[cfg(all(unix, not(target_os = "fuchsia")))]
198pub mod unix {
199    //! Unix only extensions
200    pub use sys::unix::UnixReady;
201    pub use sys::EventedFd;
202}
203
204#[cfg(target_os = "fuchsia")]
205pub mod fuchsia {
206    //! Fuchsia-only extensions
207    //!
208    //! # Stability
209    //!
210    //! This module depends on the [magenta-sys crate](https://crates.io/crates/magenta-sys)
211    //! and so might introduce breaking changes, even on minor releases,
212    //! so long as that crate remains unstable.
213    pub use sys::fuchsia::{zx_signals_t, FuchsiaReady};
214    pub use sys::EventedHandle;
215}
216
217/// Windows-only extensions to the retty-io crate.
218///
219/// retty-io on windows is currently implemented with IOCP for a high-performance
220/// implementation of asynchronous I/O. retty-io then provides TCP and UDP as sample
221/// bindings for the system to connect networking types to asynchronous I/O. On
222/// Unix this scheme is then also extensible to all other file descriptors with
223/// the `EventedFd` type, but on Windows no such analog is available. The
224/// purpose of this module, however, is to similarly provide a mechanism for
225/// foreign I/O types to get hooked up into the IOCP event loop.
226///
227/// This module provides two types for interfacing with a custom IOCP handle:
228///
229/// * `Binding` - this type is intended to govern binding with retty-io's `Poll`
230///   type. Each I/O object should contain an instance of `Binding` that's
231///   interfaced with for the implementation of the `Evented` trait. The
232///   `register`, `reregister`, and `deregister` methods for the `Evented` trait
233///   all have rough analogs with `Binding`.
234///
235///   Note that this type **does not handle readiness**. That is, this type does
236///   not handle whether sockets are readable/writable/etc. It's intended that
237///   IOCP types will internally manage this state with a `SetReadiness` type
238///   from the `poll` module. The `SetReadiness` is typically lazily created on
239///   the first time that `Evented::register` is called and then stored in the
240///   I/O object.
241///
242///   Also note that for types which represent streams of bytes the retty-io
243///   interface of *readiness* doesn't map directly to the Windows model of
244///   *completion*. This means that types will have to perform internal
245///   buffering to ensure that a readiness interface can be provided. For a
246///   sample implementation see the TCP/UDP modules in retty-io itself.
247///
248/// * `Overlapped` - this type is intended to be used as the concrete instances
249///   of the `OVERLAPPED` type that most win32 methods expect. It's crucial, for
250///   safety, that all asynchronous operations are initiated with an instance of
251///   `Overlapped` and not another instantiation of `OVERLAPPED`.
252///
253///   retty-io's `Overlapped` type is created with a function pointer that receives
254///   a `OVERLAPPED_ENTRY` type when called. This `OVERLAPPED_ENTRY` type is
255///   defined in the `winapi` crate. Whenever a completion is posted to an IOCP
256///   object the `OVERLAPPED` that was signaled will be interpreted as
257///   `Overlapped` in the retty-io crate and this function pointer will be invoked.
258///   Through this function pointer, and through the `OVERLAPPED` pointer,
259///   implementations can handle management of I/O events.
260///
261/// When put together these two types enable custom Windows handles to be
262/// registered with retty-io's event loops. The `Binding` type is used to associate
263/// handles and the `Overlapped` type is used to execute I/O operations. When
264/// the I/O operations are completed a custom function pointer is called which
265/// typically modifies a `SetReadiness` set by `Evented` methods which will get
266/// later hooked into the retty-io event loop.
267#[cfg(windows)]
268pub mod windows {
269
270    pub use sys::{Binding, Overlapped};
271}
272
273#[cfg(feature = "with-deprecated")]
274mod convert {
275    use std::time::Duration;
276
277    const NANOS_PER_MILLI: u32 = 1_000_000;
278    const MILLIS_PER_SEC: u64 = 1_000;
279
280    /// Convert a `Duration` to milliseconds, rounding up and saturating at
281    /// `u64::MAX`.
282    ///
283    /// The saturating is fine because `u64::MAX` milliseconds are still many
284    /// million years.
285    pub fn millis(duration: Duration) -> u64 {
286        // Round up.
287        let millis = (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
288        duration
289            .as_secs()
290            .saturating_mul(MILLIS_PER_SEC)
291            .saturating_add(u64::from(millis))
292    }
293}