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
use crate::{AnyCompose, AnyComposeFn, Compose};
use bevy::prelude::*;
use std::any::Any;

type LazyFn = Box<
    dyn FnMut(Option<&mut dyn Any>, &mut World, &mut Option<LazyState>, &mut Vec<Entity>)
        + Send
        + Sync,
>;

pub fn lazy<C: Compose, Marker>(system: impl IntoSystem<(), C, Marker>) -> Lazy {
    let mut cell = Some(IntoSystem::<(), C, Marker>::into_system(system));

    let system: Option<LazyFn> = Some(Box::new(move |target, world, state_cell, children| {
        if let Some(ref mut state) = state_cell {
            let _target = target.unwrap();

            let mut compose = (state.system)(world);
            compose.rebuild_any(
                state.compose.as_any_mut(),
                &mut *state.state,
                world,
                children,
            );
        } else {
            let system = cell.take().unwrap();
            let system_id = world.register_system(system);

            let mut compose = world.run_system(system_id).unwrap();
            let state = compose.build_any(world, children);

            *state_cell = Some(LazyState {
                system: Box::new(move |world| {
                    let compose = world.run_system(system_id).unwrap();
                    Box::new(compose)
                }),
                compose: Box::new(compose),
                state,
            })
        }
    }));

    Lazy { system }
}

pub struct LazyState {
    system: AnyComposeFn,
    compose: Box<dyn AnyCompose>,
    state: Box<dyn Any + Send + Sync>,
}

pub struct Lazy {
    system: Option<LazyFn>,
}

impl Compose for Lazy {
    type State = Option<LazyState>;

    fn build(&mut self, world: &mut World, children: &mut Vec<Entity>) -> Self::State {
        let mut state_cell = None;
        self.system.as_mut().unwrap()(None, world, &mut state_cell, children);
        state_cell
    }

    fn rebuild(
        &mut self,
        target: &mut Self,
        state: &mut Self::State,
        world: &mut World,
        children: &mut Vec<Entity>,
    ) {
        self.system.as_mut().unwrap()(Some(target), world, state, children);
    }
}