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
//! Animate and schedule code.
//!
//! This crate provides a very simple mechanism to animate some code. Consider:
//!
//! ```
//! let mut time = 0.; // time that passes
//! let a = 0.;
//! let b = 1.;
//! let c = 2.;
//!
//! // main loop of our application
//! loop {
//!   if time < a {
//!     // do something until time passes a point in time a
//!   } else if time < b {
//!     // do something until time passes a point in time b
//!   } else if time < c {
//!     // do something until time passes a point in time c
//!   } // etc. etc.
//!
//!   // time advances here
//!   time += 0.1;
//!
//!   if time >= c {
//!     break
//!   }
//! }
//! ```
//!
//! That might sound surprising to you, but _a lot_ of demoscene productions are written with that kind
//! of `if / else if` blocks. It’s pretty bad and ugly though, I agree. For several reasons:
//!
//!   - It doesn’t compose at all. If you want to do something in between α and β, you will have to
//!     break the whole block and change every timings.
//!   - Dynamic branching will get worse and worse as time passes, since you’re going to make more and
//!     more tests.
//!   - The code is just ugly!
//!
//! Instead of writing that kind of code, we can do better:
//!
//! ```
//! use awoo::window::Window;
//!
//! let pre_alpha = Window::new(0., 1.); // do something until time passes 1.
//! let pre_beta = Window::new(1., 2.); // do something until time passes 2.
//! let pre_gamma = Window::new(2., 3.); // do something until time passes 3.
//! ```
//!
//! By default, [`Window<T>`] is just a window of time `T`. We can map actions to completely
//! do the same thing as above:
//!
//! ```
//! # use awoo::window::Window;
//! let pre_alpha = Window::new(0., 1.).map(|time| println!("time is {}", time));
//! ```
//!
//! The type of that [`MappedWindow<_>`] is determined by what you return from your closure in the
//! `map` call. Once all windows are created, you can schedule them:
//!
//! ```
//! # use awoo::window::Window;
//! use awoo::scheduler::RandomAccessScheduler;
//! use awoo::time::simple::SimpleF32TimeGenerator;
//!
//! # let pre_alpha = Window::new(0., 1.).map(|t| println!("pre α: {}", t));
//! # let pre_beta = Window::new(1., 2.).map(|t| println!("pre β: {}", t));
//! # let pre_gamma = Window::new(2., 3.).map(|t| println!("pre γ: {}", t));
//! let mut scheduler = RandomAccessScheduler::new(
//!   SimpleF32TimeGenerator::new(0., 0.1), // a generator that generates linear time starting at 0 and incrementing by 0.1
//!   vec![pre_alpha, pre_beta, pre_gamma] // our mapped windows
//! ).unwrap();
//!
//! scheduler.schedule();
//! ```
//!
//! What’s interesting is that we can get the windows from a file, for instance, and map them on the
//! fly.
//!
//! [`Window<T>`]: crate::window::Window
//! [`MappedWindow<_>`]: crate::window::MappedWindow

pub mod scheduler;
pub mod time;
pub mod window;