#queue #calendar #idea #scheduler #data #structure

calendar_queue

This crate implements the idea of a 'Calendar Queue Scheduler' data structure

1 unstable release

Uses old Rust 2015

0.0.1 Nov 25, 2015

#34 in #idea

MIT license

15KB
145 lines

Calendar Queue Scheduler

Build Status Coverage Status

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::Receivers. This implementation is intentionally very generi, practical and simple.

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:

    (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

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()));

No runtime deps