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
use crate::{assets::database::AssetsDatabase, error::*, fetch::FetchEngine};

enum Phase {
    None,
    Start(Box<dyn FetchEngine>),
    Loading,
    Ready,
}

pub struct AssetsPreloader {
    paths: Vec<String>,
    phase: Phase,
}

impl AssetsPreloader {
    pub fn new<E>(engine: E, paths: Vec<&str>) -> Self
    where
        E: FetchEngine + 'static,
    {
        let paths = paths.into_iter().map(|p| p.to_owned()).collect::<Vec<_>>();
        Self {
            paths,
            phase: Phase::Start(Box::new(engine)),
        }
    }

    pub fn process(&mut self, assets: &mut AssetsDatabase) -> Result<bool> {
        match std::mem::replace(&mut self.phase, Phase::None) {
            Phase::Start(engine) => {
                assets.push_fetch_engine(engine);
                if self.paths.is_empty() {
                    self.phase = Phase::Ready;
                } else {
                    self.phase = Phase::Loading;
                    for path in &self.paths {
                        if let Err(error) = assets.load(path) {
                            return Err(Error::Message(format!(
                                "Cannot load asset: {}\n{:?}",
                                path, error
                            )));
                        }
                    }
                }
            }
            Phase::Loading => {
                if assets.is_ready() && assets.are_ready(self.paths.iter()) {
                    assets.pop_fetch_engine();
                    self.phase = Phase::Ready;
                } else {
                    self.phase = Phase::Loading;
                }
            }
            Phase::Ready => {
                self.phase = Phase::Ready;
                return Ok(true);
            }
            Phase::None => {}
        }
        Ok(false)
    }

    pub fn is_ready(&self) -> bool {
        matches!(self.phase, Phase::Ready)
    }
}