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
#![crate_name = "calendar_queue"]
#![crate_type="lib"]
#![doc(html_logo_url = "")]
#![doc(html_root_url = "https://hoverbear.github.io/calendar_queue/calendar_queue/")]
//! This crate implements the idea of a "Calendar Queue Scheduler" data structure.
//!
//! The Calendar Queue Sheduler is an effective way to fairly receive
//! from a number of `mpsc::Receiver`s. This implementation is intentionally very generi, practical
//! and simple.
//!
//! ```text
//! TODO ideas for PR's or future fun:
//! [ ] Handle overflows (easy first PR!)
//! [ ] Implement a variety of fake interfaces for simulations? (Read? TcpSocket?)
//! [ ] Optimize `next()` for production so it don't just call `tick()` repeatedly.
//! ```
//!
//! You can imagine it like so:
//!
//! ```text
//!     (The Sorter)              (The flows)
//!          +
//!          |
//!          |
//!        +-v-+
//!        |   |
//!        | ∅ |
//!        |   |
//!        +-+-+
//!          |
//! +---+  +-+-+
//! |   |  |   |
//! | 2 +--+ 3 |
//! |   |  |   |
//! +---+  +-+-+        |              |              |
//!          |          |              |              |
//!        +-+-+  +-----v-----+  +-----v-----+  +-----v-----+
//!        |   |  |           |  |           |  |           |
//!        | 1 |  | Channel 1 |  | Channel 2 |  | Channel 3 |
//!        |   |  |           |  |           |  |           |
//!        +-+-+  +-----------+  +-----------+  +-----------+
//!          |
//!          |
//!          v
//! ```
//!
//! The sorter, on the left, maintains a list of keys matching to channels. At each 'tick' of the
//! calendar it may or may not have one or many channels scheduled. Using the data structure this
//! way allows for simulations, since one can effectively simulate something similar to a router.
//!
//! The queue also implements the `Iterator` trait, and can be used as a generic iterator
//! throughout your code however you see fit. An iterator over the queue will simple repeatedly
//! call tick until it has carried out an entire "cycle" and (still fairly) given every channel a
//! chance to send, **only then** will the iterator finally exhaust.
//!
//! ### An Example
//!
//! ```rust
//! use calendar_queue::CalendarQueue;
//!
//! // `id`s and `value`s are generic. Think of this as a hashmap of channels.
//! let mut queue = CalendarQueue::<u64, String>::new();
//!
//! // Each `Reciever` is one channel to the queue.
//! // Here we give our reciever to the queue, with a cycle of 3 ticks.
//! let (sender_1, receiver_1) = std::sync::mpsc::channel();
//! queue.add_channel(receiver_1, 1, 3)
//!     .unwrap();
//! // We can also just pull one out.
//! let sender_2 = queue.create_channel(2, 5)
//!     .unwrap();
//!
//! // The `Sender`s behave as you might expect.
//! for _ in 0..3 {
//!     sender_1.send("Foo".into())
//!         .unwrap();
//! }
//!
//! for _ in 0..5 {
//!     sender_2.send("Bar".into())
//!         .unwrap();
//! }
//!
//! // The zero-th clock tick has two items!
//! assert_eq!(queue.tick(), Some("Foo".into()));
//! assert_eq!(queue.tick(), Some("Bar".into()));
//! // First tick has none!
//! assert_eq!(queue.tick(), None);
//! // Second tick has none either!
//! assert_eq!(queue.tick(), None);
//! // The third tick will be "Foo" because of it's cycle time.
//! assert_eq!(queue.tick(), Some("Foo".into()));
//! // We can use `.next()` (and other iterator goodies) to fast forward over empty gaps.
//! // This will tick over 4 and move on to 5.
//! assert_eq!(queue.next(), Some("Bar".into()));
//! // Tick 6 now.
//! assert_eq!(queue.tick(), Some("Foo".into()));
//! ```

mod calendar_queue;

pub use calendar_queue::CalendarQueue;

pub type ConformanceTicks = u64;
pub type ClockTick = u64;
pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    DuplicateFlowId,
}