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
//! Macros to make common workflows easier

pub use screeps_async_macros::*;

/// Run a block of code each tick, resolving the specified list of
/// dependencies by calling `.resolve` each tick and exiting if
/// any dependency can't be resolved.
///
/// Dependencies can be of any type, but must have a `.resolve` method
/// that returns an [`Option`]
///
/// The resolved dependencies will be available within the code block
/// under the same ident. EG an [`screeps::ObjectId<screeps::Creep>`] called `creep`
/// will be resolved to a [`screeps::Creep`] also called `creep`
///
/// The code block must return an [`Option`]. If the code block returns [`None`],
/// then execution will continue next tick. If the code block returns [`Some`],
/// then looping will cease and `each_tick!` will return whatever the value returned by the code block
///
/// Returns [`Some`] if the inner block ever returned [`Some`]
///
/// # Errors
///
/// Returns [`None`] if any dependency ever fails to resolve
///
/// # Examples
///
/// ```
/// use screeps::*;
/// async fn harvest_forever(creep: ObjectId<Creep>, source: ObjectId<Source>) {
///     screeps_async::each_tick!(creep, source, {
///         let _ = creep.harvest(&source);
///         None::<()> // do this forever
///     }).await;
/// }
/// ```
#[macro_export]
macro_rules! each_tick {
    ($($dep:ident),*, $body:block) => {
        async move {
            loop {
                $(
                    let $dep = $dep.resolve()?;
                )*
                let fut = async move $body;
                if let Some(ret) = fut.await {
                    return Some(ret);
                }

                ::screeps_async::time::yield_tick().await;
            }
        }
    }
}