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
//! Data structures and runtimes for timer management.
//!
//! This library provides various data structures for managing coarse grain timers.
//!
//! #### Data Structures
//!
//! **Overview**
//!
//! We provide various data structures for timer management, each with their own tradeoffs and suited for different application.
//!
//! * For applications that set shorted lived timeouts, all around the same duration, consider using a `HashedWheel`, as it will
//! require minimal bookkeeping at runtime for operations such as ticking, or removing expired timers.
//! * Network communication
//! * Cache for short lived items
//!
//! * For applications that set long lived timeouts, or timeouts spread across many different durations, considuer using a `HierarchicalWheel`, as
//! it will accept a variety of different durations, without loss of precision.
//! * Cache for long lived items
//! * Varied timeouts from user input
//!
//! **Hashed Wheel**
//!
//! Stores all timers in a fixed number of slots (`num_slots`), where each slot represents some fixed period of time (`tick_duration`).
//! The slots we maintain are used as a circular buffer, where after each tick, we advance our position in the buffer. Each tick occurrs
//! after approximately `tick_duration` time has passed.
//!
//! **Note**: One slot could have multiple timers of differing durations, these timers will be sorted based on tick expiration. However, if
//! the wheel is configured such that one slot contains timers expiring at different ticks, insertion time will fall back to O(n) instead of O(1).
//! By default, `max_timeout` is set equal to `tick_duration` * `num_slots` - `1 ns`, to ensure that all timers inserted will be O(1) inserts, though
//! you can change this if required.
//!
//! **Hierarchical Wheel**
//!
//! *Not Implemented Yet*
//!
//! #### Runtimes
//!
//! **Overview**
//!
//! We provide various runtimes on top of the base data structures for timer management, each being generic over the type of `Pendulum` that you choose.
//!
//! Runtimes are useful because they allow you to not care about how the underlying data structure is getting ticked, or when we should check for an expired timer.
//!
//! **Futures**
//!
//! Runs the actual `Pendulum` in a separate thread that handles accepting requests for new timers, as well as making sure the `Pendulum` is ticked correctly, and
//! finally notifications for expired timeouts.
//!
//! Since the futures library is based around the concept of readiness, via `Task`, we can have callers doing other useful work and make it so that callers aren't
//! continuously checking if a timer is up, only when it is actually up with the background timer thread signal readiness, so that the `Future`s library will
//! poll the timer again.
//!
//! **Note**: Timer bounds (on both the duration and capacity), is checked before returning a `Future`/`Stream` from the `Timer` object, so the only `Error` being
//! returned from either of those objects is related to timer expiration, which makes it easy to integrate the error handling into your application correctly.
//!
//! ## Hashed Wheel Example:
//!
//! ```rust
//! extern crate pendulum;
//!
//! use std::time::Duration;
//! use std::thread;
//!
//! use pendulum::{Pendulum, HashedWheelBuilder};
//!
//! #[derive(Debug, PartialEq, Eq)]
//! struct SomeData(usize);
//!
//! fn main() {
//! // Create a pendulum with mostly default configration
//! let mut wheel = HashedWheelBuilder::default()
//! // Tick duration defines the resolution for our timer (all timeouts will be a multiple of this)
//! .with_tick_duration(Duration::from_millis(100))
//! .build();
//!
//! // Insert a timeout and store the token, we can use this to cancel the timeout
//! let token = wheel.insert_timeout(Duration::from_millis(50), SomeData(5)).unwrap();
//!
//! // Tick our wheel after the given duration (100 ms)
//! thread::sleep(wheel.tick_duration());
//!
//! // Tell the wheel that it can perform a tick
//! wheel.tick();
//!
//! // Retrieve any expired timeouts
//! while let Some(timeout) = wheel.expired_timeout() {
//! assert_eq!(SomeData(5), timeout);
//! }
//!
//! // If we tried to remove the timeout using the token, we get None (already expired)
//! assert_eq!(None, wheel.remove_timeout(token));
//! }
//! ```
extern crate log;
extern crate slab;
extern crate crossbeam;
extern crate futures;
pub use ;
pub use ;